1bf215546Sopenharmony_ci/**********************************************************
2bf215546Sopenharmony_ci * Copyright 2008-2009 VMware, Inc.  All rights reserved.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person
5bf215546Sopenharmony_ci * obtaining a copy of this software and associated documentation
6bf215546Sopenharmony_ci * files (the "Software"), to deal in the Software without
7bf215546Sopenharmony_ci * restriction, including without limitation the rights to use, copy,
8bf215546Sopenharmony_ci * modify, merge, publish, distribute, sublicense, and/or sell copies
9bf215546Sopenharmony_ci * of the Software, and to permit persons to whom the Software is
10bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions:
11bf215546Sopenharmony_ci *
12bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be
13bf215546Sopenharmony_ci * included in all copies or substantial portions of the Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18bf215546Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19bf215546Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20bf215546Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21bf215546Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22bf215546Sopenharmony_ci * SOFTWARE.
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci **********************************************************/
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "svga_cmd.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "pipe/p_state.h"
29bf215546Sopenharmony_ci#include "pipe/p_defines.h"
30bf215546Sopenharmony_ci#include "util/u_inlines.h"
31bf215546Sopenharmony_ci#include "os/os_thread.h"
32bf215546Sopenharmony_ci#include "util/u_math.h"
33bf215546Sopenharmony_ci#include "util/u_memory.h"
34bf215546Sopenharmony_ci#include "util/u_resource.h"
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#include "svga_context.h"
37bf215546Sopenharmony_ci#include "svga_screen.h"
38bf215546Sopenharmony_ci#include "svga_resource_buffer.h"
39bf215546Sopenharmony_ci#include "svga_resource_buffer_upload.h"
40bf215546Sopenharmony_ci#include "svga_resource_texture.h"
41bf215546Sopenharmony_ci#include "svga_sampler_view.h"
42bf215546Sopenharmony_ci#include "svga_winsys.h"
43bf215546Sopenharmony_ci#include "svga_debug.h"
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci/**
47bf215546Sopenharmony_ci * Determine what buffers eventually need hardware backing.
48bf215546Sopenharmony_ci *
49bf215546Sopenharmony_ci * Vertex- and index buffers need hardware backing.  Constant buffers
50bf215546Sopenharmony_ci * do on vgpu10. Staging texture-upload buffers do when they are
51bf215546Sopenharmony_ci * supported.
52bf215546Sopenharmony_ci */
53bf215546Sopenharmony_cistatic inline boolean
54bf215546Sopenharmony_cisvga_buffer_needs_hw_storage(const struct svga_screen *ss,
55bf215546Sopenharmony_ci                             const struct pipe_resource *template)
56bf215546Sopenharmony_ci{
57bf215546Sopenharmony_ci   unsigned bind_mask = (PIPE_BIND_VERTEX_BUFFER | PIPE_BIND_INDEX_BUFFER |
58bf215546Sopenharmony_ci                         PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_STREAM_OUTPUT |
59bf215546Sopenharmony_ci                         PIPE_BIND_SHADER_BUFFER | PIPE_BIND_COMMAND_ARGS_BUFFER);
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   if (ss->sws->have_vgpu10) {
62bf215546Sopenharmony_ci      /*
63bf215546Sopenharmony_ci       * Driver-created upload const0- and staging texture upload buffers
64bf215546Sopenharmony_ci       * tagged with PIPE_BIND_CUSTOM
65bf215546Sopenharmony_ci       */
66bf215546Sopenharmony_ci      bind_mask |= PIPE_BIND_CUSTOM;
67bf215546Sopenharmony_ci      /**
68bf215546Sopenharmony_ci       * Uniform buffer objects.
69bf215546Sopenharmony_ci       * Don't create hardware storage for state-tracker constant buffers,
70bf215546Sopenharmony_ci       * because we frequently map them for reading and writing, and
71bf215546Sopenharmony_ci       * the length of those buffers are always small, so it is better
72bf215546Sopenharmony_ci       * to just use system memory.
73bf215546Sopenharmony_ci       */
74bf215546Sopenharmony_ci   }
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   if (template->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)
77bf215546Sopenharmony_ci      return TRUE;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   return !!(template->bind & bind_mask);
80bf215546Sopenharmony_ci}
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_cistatic inline boolean
84bf215546Sopenharmony_cineed_buf_readback(struct svga_context *svga,
85bf215546Sopenharmony_ci                  struct pipe_transfer *st)
86bf215546Sopenharmony_ci{
87bf215546Sopenharmony_ci   struct svga_buffer *sbuf = svga_buffer(st->resource);
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   if (st->usage != PIPE_MAP_READ)
90bf215546Sopenharmony_ci      return FALSE;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   /* No buffer surface has been created */
93bf215546Sopenharmony_ci   if (!sbuf->bufsurf)
94bf215546Sopenharmony_ci      return FALSE;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   return  ((sbuf->dirty ||
97bf215546Sopenharmony_ci             sbuf->bufsurf->surface_state == SVGA_SURFACE_STATE_RENDERED) &&
98bf215546Sopenharmony_ci            !sbuf->key.coherent && !svga->swc->force_coherent);
99bf215546Sopenharmony_ci}
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci/**
103bf215546Sopenharmony_ci * Create a buffer transfer.
104bf215546Sopenharmony_ci *
105bf215546Sopenharmony_ci * Unlike texture DMAs (which are written immediately to the command buffer and
106bf215546Sopenharmony_ci * therefore inherently serialized with other context operations), for buffers
107bf215546Sopenharmony_ci * we try to coalesce multiple range mappings (i.e, multiple calls to this
108bf215546Sopenharmony_ci * function) into a single DMA command, for better efficiency in command
109bf215546Sopenharmony_ci * processing.  This means we need to exercise extra care here to ensure that
110bf215546Sopenharmony_ci * the end result is exactly the same as if one DMA was used for every mapped
111bf215546Sopenharmony_ci * range.
112bf215546Sopenharmony_ci */
113bf215546Sopenharmony_civoid *
114bf215546Sopenharmony_cisvga_buffer_transfer_map(struct pipe_context *pipe,
115bf215546Sopenharmony_ci                         struct pipe_resource *resource,
116bf215546Sopenharmony_ci                         unsigned level,
117bf215546Sopenharmony_ci                         unsigned usage,
118bf215546Sopenharmony_ci                         const struct pipe_box *box,
119bf215546Sopenharmony_ci                         struct pipe_transfer **ptransfer)
120bf215546Sopenharmony_ci{
121bf215546Sopenharmony_ci   struct svga_context *svga = svga_context(pipe);
122bf215546Sopenharmony_ci   struct svga_screen *ss = svga_screen(pipe->screen);
123bf215546Sopenharmony_ci   struct svga_buffer *sbuf = svga_buffer(resource);
124bf215546Sopenharmony_ci   struct pipe_transfer *transfer;
125bf215546Sopenharmony_ci   uint8_t *map = NULL;
126bf215546Sopenharmony_ci   int64_t begin = svga_get_time(svga);
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERTRANSFERMAP);
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   assert(box->y == 0);
131bf215546Sopenharmony_ci   assert(box->z == 0);
132bf215546Sopenharmony_ci   assert(box->height == 1);
133bf215546Sopenharmony_ci   assert(box->depth == 1);
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   transfer = MALLOC_STRUCT(pipe_transfer);
136bf215546Sopenharmony_ci   if (!transfer) {
137bf215546Sopenharmony_ci      goto done;
138bf215546Sopenharmony_ci   }
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   transfer->resource = resource;
141bf215546Sopenharmony_ci   transfer->level = level;
142bf215546Sopenharmony_ci   transfer->usage = usage;
143bf215546Sopenharmony_ci   transfer->box = *box;
144bf215546Sopenharmony_ci   transfer->stride = 0;
145bf215546Sopenharmony_ci   transfer->layer_stride = 0;
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   if (usage & PIPE_MAP_WRITE) {
148bf215546Sopenharmony_ci      /* If we write to the buffer for any reason, free any saved translated
149bf215546Sopenharmony_ci       * vertices.
150bf215546Sopenharmony_ci       */
151bf215546Sopenharmony_ci      pipe_resource_reference(&sbuf->translated_indices.buffer, NULL);
152bf215546Sopenharmony_ci   }
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   /* If it is a read transfer and the buffer is dirty or the buffer is bound
155bf215546Sopenharmony_ci    * to a uav, we will need to read the subresource content from the device.
156bf215546Sopenharmony_ci    */
157bf215546Sopenharmony_ci   if (need_buf_readback(svga, transfer)) {
158bf215546Sopenharmony_ci      /* Host-side buffers can be dirtied with vgpu10 features
159bf215546Sopenharmony_ci       * (streamout and buffer copy) and sm5 feature via uav.
160bf215546Sopenharmony_ci       */
161bf215546Sopenharmony_ci      assert(svga_have_vgpu10(svga));
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci      if (!sbuf->user) {
164bf215546Sopenharmony_ci         (void) svga_buffer_handle(svga, resource, sbuf->bind_flags);
165bf215546Sopenharmony_ci      }
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci      if (sbuf->dma.pending) {
168bf215546Sopenharmony_ci         svga_buffer_upload_flush(svga, sbuf);
169bf215546Sopenharmony_ci         svga_context_finish(svga);
170bf215546Sopenharmony_ci      }
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci      assert(sbuf->handle);
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci      SVGA_RETRY(svga, SVGA3D_ReadbackGBSurface(svga->swc, sbuf->handle));
175bf215546Sopenharmony_ci      svga->hud.num_readbacks++;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci      svga_context_finish(svga);
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ci      sbuf->dirty = FALSE;
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci      /* Mark the buffer surface state as UPDATED */
182bf215546Sopenharmony_ci      assert(sbuf->bufsurf);
183bf215546Sopenharmony_ci      sbuf->bufsurf->surface_state = SVGA_SURFACE_STATE_UPDATED;
184bf215546Sopenharmony_ci   }
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   if (usage & PIPE_MAP_WRITE) {
187bf215546Sopenharmony_ci      if ((usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) &&
188bf215546Sopenharmony_ci          !(resource->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT)) {
189bf215546Sopenharmony_ci         /*
190bf215546Sopenharmony_ci          * Flush any pending primitives, finish writing any pending DMA
191bf215546Sopenharmony_ci          * commands, and tell the host to discard the buffer contents on
192bf215546Sopenharmony_ci          * the next DMA operation.
193bf215546Sopenharmony_ci          */
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci         svga_hwtnl_flush_buffer(svga, resource);
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci         if (sbuf->dma.pending) {
198bf215546Sopenharmony_ci            svga_buffer_upload_flush(svga, sbuf);
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci            /*
201bf215546Sopenharmony_ci             * Instead of flushing the context command buffer, simply discard
202bf215546Sopenharmony_ci             * the current hwbuf, and start a new one.
203bf215546Sopenharmony_ci             * With GB objects, the map operation takes care of this
204bf215546Sopenharmony_ci             * if passed the PIPE_MAP_DISCARD_WHOLE_RESOURCE flag,
205bf215546Sopenharmony_ci             * and the old backing store is busy.
206bf215546Sopenharmony_ci             */
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci            if (!svga_have_gb_objects(svga))
209bf215546Sopenharmony_ci               svga_buffer_destroy_hw_storage(ss, sbuf);
210bf215546Sopenharmony_ci         }
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci         sbuf->map.num_ranges = 0;
213bf215546Sopenharmony_ci         sbuf->dma.flags.discard = TRUE;
214bf215546Sopenharmony_ci      }
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci      if (usage & PIPE_MAP_UNSYNCHRONIZED) {
217bf215546Sopenharmony_ci         if (!sbuf->map.num_ranges) {
218bf215546Sopenharmony_ci            /*
219bf215546Sopenharmony_ci             * No pending ranges to upload so far, so we can tell the host to
220bf215546Sopenharmony_ci             * not synchronize on the next DMA command.
221bf215546Sopenharmony_ci             */
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci            sbuf->dma.flags.unsynchronized = TRUE;
224bf215546Sopenharmony_ci         }
225bf215546Sopenharmony_ci      } else {
226bf215546Sopenharmony_ci         /*
227bf215546Sopenharmony_ci          * Synchronizing, so flush any pending primitives, finish writing any
228bf215546Sopenharmony_ci          * pending DMA command, and ensure the next DMA will be done in order.
229bf215546Sopenharmony_ci          */
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci         svga_hwtnl_flush_buffer(svga, resource);
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci         if (sbuf->dma.pending) {
234bf215546Sopenharmony_ci            svga_buffer_upload_flush(svga, sbuf);
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci            if (svga_buffer_has_hw_storage(sbuf)) {
237bf215546Sopenharmony_ci               /*
238bf215546Sopenharmony_ci                * We have a pending DMA upload from a hardware buffer, therefore
239bf215546Sopenharmony_ci                * we need to ensure that the host finishes processing that DMA
240bf215546Sopenharmony_ci                * command before the gallium frontend can start overwriting the
241bf215546Sopenharmony_ci                * hardware buffer.
242bf215546Sopenharmony_ci                *
243bf215546Sopenharmony_ci                * XXX: This could be avoided by tying the hardware buffer to
244bf215546Sopenharmony_ci                * the transfer (just as done with textures), which would allow
245bf215546Sopenharmony_ci                * overlapping DMAs commands to be queued on the same context
246bf215546Sopenharmony_ci                * buffer. However, due to the likelihood of software vertex
247bf215546Sopenharmony_ci                * processing, it is more convenient to hold on to the hardware
248bf215546Sopenharmony_ci                * buffer, allowing to quickly access the contents from the CPU
249bf215546Sopenharmony_ci                * without having to do a DMA download from the host.
250bf215546Sopenharmony_ci                */
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci               if (usage & PIPE_MAP_DONTBLOCK) {
253bf215546Sopenharmony_ci                  /*
254bf215546Sopenharmony_ci                   * Flushing the command buffer here will most likely cause
255bf215546Sopenharmony_ci                   * the map of the hwbuf below to block, so preemptively
256bf215546Sopenharmony_ci                   * return NULL here if DONTBLOCK is set to prevent unnecessary
257bf215546Sopenharmony_ci                   * command buffer flushes.
258bf215546Sopenharmony_ci                   */
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci                  FREE(transfer);
261bf215546Sopenharmony_ci                  goto done;
262bf215546Sopenharmony_ci               }
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci               svga_context_flush(svga, NULL);
265bf215546Sopenharmony_ci            }
266bf215546Sopenharmony_ci         }
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci         sbuf->dma.flags.unsynchronized = FALSE;
269bf215546Sopenharmony_ci      }
270bf215546Sopenharmony_ci   }
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci   if (!sbuf->swbuf && !svga_buffer_has_hw_storage(sbuf)) {
273bf215546Sopenharmony_ci      if (svga_buffer_create_hw_storage(ss, sbuf, sbuf->bind_flags) != PIPE_OK) {
274bf215546Sopenharmony_ci         /*
275bf215546Sopenharmony_ci          * We can't create a hardware buffer big enough, so create a malloc
276bf215546Sopenharmony_ci          * buffer instead.
277bf215546Sopenharmony_ci          */
278bf215546Sopenharmony_ci         if (0) {
279bf215546Sopenharmony_ci            debug_printf("%s: failed to allocate %u KB of DMA, "
280bf215546Sopenharmony_ci                         "splitting DMA transfers\n",
281bf215546Sopenharmony_ci                         __FUNCTION__,
282bf215546Sopenharmony_ci                         (sbuf->b.width0 + 1023)/1024);
283bf215546Sopenharmony_ci         }
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci         sbuf->swbuf = align_malloc(sbuf->b.width0, 16);
286bf215546Sopenharmony_ci         if (!sbuf->swbuf) {
287bf215546Sopenharmony_ci            FREE(transfer);
288bf215546Sopenharmony_ci            goto done;
289bf215546Sopenharmony_ci         }
290bf215546Sopenharmony_ci      }
291bf215546Sopenharmony_ci   }
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   if (sbuf->swbuf) {
294bf215546Sopenharmony_ci      /* User/malloc buffer */
295bf215546Sopenharmony_ci      map = sbuf->swbuf;
296bf215546Sopenharmony_ci   }
297bf215546Sopenharmony_ci   else if (svga_buffer_has_hw_storage(sbuf)) {
298bf215546Sopenharmony_ci      boolean retry;
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci      map = SVGA_TRY_MAP(svga_buffer_hw_storage_map
301bf215546Sopenharmony_ci                         (svga, sbuf, transfer->usage, &retry), retry);
302bf215546Sopenharmony_ci      if (map == NULL && retry) {
303bf215546Sopenharmony_ci         /*
304bf215546Sopenharmony_ci          * At this point, svga_buffer_get_transfer() has already
305bf215546Sopenharmony_ci          * hit the DISCARD_WHOLE_RESOURCE path and flushed HWTNL
306bf215546Sopenharmony_ci          * for this buffer.
307bf215546Sopenharmony_ci          */
308bf215546Sopenharmony_ci         svga_retry_enter(svga);
309bf215546Sopenharmony_ci         svga_context_flush(svga, NULL);
310bf215546Sopenharmony_ci         map = svga_buffer_hw_storage_map(svga, sbuf, transfer->usage, &retry);
311bf215546Sopenharmony_ci         svga_retry_exit(svga);
312bf215546Sopenharmony_ci      }
313bf215546Sopenharmony_ci   }
314bf215546Sopenharmony_ci   else {
315bf215546Sopenharmony_ci      map = NULL;
316bf215546Sopenharmony_ci   }
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   if (map) {
319bf215546Sopenharmony_ci      ++sbuf->map.count;
320bf215546Sopenharmony_ci      map += transfer->box.x;
321bf215546Sopenharmony_ci      *ptransfer = transfer;
322bf215546Sopenharmony_ci   } else {
323bf215546Sopenharmony_ci      FREE(transfer);
324bf215546Sopenharmony_ci   }
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   svga->hud.map_buffer_time += (svga_get_time(svga) - begin);
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_cidone:
329bf215546Sopenharmony_ci   SVGA_STATS_TIME_POP(svga_sws(svga));
330bf215546Sopenharmony_ci   return map;
331bf215546Sopenharmony_ci}
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_civoid
335bf215546Sopenharmony_cisvga_buffer_transfer_flush_region(struct pipe_context *pipe,
336bf215546Sopenharmony_ci                                  struct pipe_transfer *transfer,
337bf215546Sopenharmony_ci                                  const struct pipe_box *box)
338bf215546Sopenharmony_ci{
339bf215546Sopenharmony_ci   struct svga_screen *ss = svga_screen(pipe->screen);
340bf215546Sopenharmony_ci   struct svga_buffer *sbuf = svga_buffer(transfer->resource);
341bf215546Sopenharmony_ci   struct svga_context *svga = svga_context(pipe);
342bf215546Sopenharmony_ci   unsigned offset = transfer->box.x + box->x;
343bf215546Sopenharmony_ci   unsigned length = box->width;
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci   assert(transfer->usage & PIPE_MAP_WRITE);
346bf215546Sopenharmony_ci   assert(transfer->usage & PIPE_MAP_FLUSH_EXPLICIT);
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   if (!(svga->swc->force_coherent || sbuf->key.coherent) || sbuf->swbuf) {
349bf215546Sopenharmony_ci      mtx_lock(&ss->swc_mutex);
350bf215546Sopenharmony_ci      svga_buffer_add_range(sbuf, offset, offset + length);
351bf215546Sopenharmony_ci      mtx_unlock(&ss->swc_mutex);
352bf215546Sopenharmony_ci   }
353bf215546Sopenharmony_ci}
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_civoid
357bf215546Sopenharmony_cisvga_buffer_transfer_unmap(struct pipe_context *pipe,
358bf215546Sopenharmony_ci                           struct pipe_transfer *transfer)
359bf215546Sopenharmony_ci{
360bf215546Sopenharmony_ci   struct svga_screen *ss = svga_screen(pipe->screen);
361bf215546Sopenharmony_ci   struct svga_context *svga = svga_context(pipe);
362bf215546Sopenharmony_ci   struct svga_buffer *sbuf = svga_buffer(transfer->resource);
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_ci   SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERTRANSFERUNMAP);
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ci   mtx_lock(&ss->swc_mutex);
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   assert(sbuf->map.count);
369bf215546Sopenharmony_ci   if (sbuf->map.count) {
370bf215546Sopenharmony_ci      --sbuf->map.count;
371bf215546Sopenharmony_ci   }
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   if (svga_buffer_has_hw_storage(sbuf)) {
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci      /* Note: we may wind up flushing here and unmapping other buffers
376bf215546Sopenharmony_ci       * which leads to recursively locking ss->swc_mutex.
377bf215546Sopenharmony_ci       */
378bf215546Sopenharmony_ci      svga_buffer_hw_storage_unmap(svga, sbuf);
379bf215546Sopenharmony_ci   }
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci   if (transfer->usage & PIPE_MAP_WRITE) {
382bf215546Sopenharmony_ci      if (!(transfer->usage & PIPE_MAP_FLUSH_EXPLICIT)) {
383bf215546Sopenharmony_ci         /*
384bf215546Sopenharmony_ci          * Mapped range not flushed explicitly, so flush the whole buffer,
385bf215546Sopenharmony_ci          * and tell the host to discard the contents when processing the DMA
386bf215546Sopenharmony_ci          * command.
387bf215546Sopenharmony_ci          */
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci         SVGA_DBG(DEBUG_DMA, "flushing the whole buffer\n");
390bf215546Sopenharmony_ci
391bf215546Sopenharmony_ci         sbuf->dma.flags.discard = TRUE;
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci         if (!(svga->swc->force_coherent || sbuf->key.coherent) || sbuf->swbuf)
394bf215546Sopenharmony_ci            svga_buffer_add_range(sbuf, 0, sbuf->b.width0);
395bf215546Sopenharmony_ci      }
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci      if (sbuf->swbuf &&
398bf215546Sopenharmony_ci          (!sbuf->bind_flags || (sbuf->bind_flags & PIPE_BIND_CONSTANT_BUFFER))) {
399bf215546Sopenharmony_ci         /*
400bf215546Sopenharmony_ci          * Since the constant buffer is in system buffer, we need
401bf215546Sopenharmony_ci          * to set the constant buffer dirty bits, so that the context
402bf215546Sopenharmony_ci          * can update the changes in the device.
403bf215546Sopenharmony_ci          * According to the GL spec, buffer bound to other contexts will
404bf215546Sopenharmony_ci          * have to be explicitly rebound by the user to have the changes take
405bf215546Sopenharmony_ci          * into effect.
406bf215546Sopenharmony_ci          */
407bf215546Sopenharmony_ci         svga->dirty |= SVGA_NEW_CONST_BUFFER;
408bf215546Sopenharmony_ci      }
409bf215546Sopenharmony_ci   }
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   mtx_unlock(&ss->swc_mutex);
412bf215546Sopenharmony_ci   FREE(transfer);
413bf215546Sopenharmony_ci   SVGA_STATS_TIME_POP(svga_sws(svga));
414bf215546Sopenharmony_ci}
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_civoid
418bf215546Sopenharmony_cisvga_resource_destroy(struct pipe_screen *screen,
419bf215546Sopenharmony_ci                      struct pipe_resource *buf)
420bf215546Sopenharmony_ci{
421bf215546Sopenharmony_ci   if (buf->target == PIPE_BUFFER) {
422bf215546Sopenharmony_ci      struct svga_screen *ss = svga_screen(screen);
423bf215546Sopenharmony_ci      struct svga_buffer *sbuf = svga_buffer(buf);
424bf215546Sopenharmony_ci
425bf215546Sopenharmony_ci      assert(!p_atomic_read(&buf->reference.count));
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci      assert(!sbuf->dma.pending);
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci      if (sbuf->handle)
430bf215546Sopenharmony_ci         svga_buffer_destroy_host_surface(ss, sbuf);
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci      if (sbuf->uploaded.buffer)
433bf215546Sopenharmony_ci         pipe_resource_reference(&sbuf->uploaded.buffer, NULL);
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci      if (sbuf->hwbuf)
436bf215546Sopenharmony_ci         svga_buffer_destroy_hw_storage(ss, sbuf);
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci      if (sbuf->swbuf && !sbuf->user)
439bf215546Sopenharmony_ci         align_free(sbuf->swbuf);
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci      pipe_resource_reference(&sbuf->translated_indices.buffer, NULL);
442bf215546Sopenharmony_ci
443bf215546Sopenharmony_ci      ss->hud.total_resource_bytes -= sbuf->size;
444bf215546Sopenharmony_ci      assert(ss->hud.num_resources > 0);
445bf215546Sopenharmony_ci      if (ss->hud.num_resources > 0)
446bf215546Sopenharmony_ci         ss->hud.num_resources--;
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_ci      FREE(sbuf);
449bf215546Sopenharmony_ci   } else {
450bf215546Sopenharmony_ci      struct svga_screen *ss = svga_screen(screen);
451bf215546Sopenharmony_ci      struct svga_texture *tex = svga_texture(buf);
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci      ss->texture_timestamp++;
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci      svga_sampler_view_reference(&tex->cached_view, NULL);
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci      /*
458bf215546Sopenharmony_ci        DBG("%s deleting %p\n", __FUNCTION__, (void *) tex);
459bf215546Sopenharmony_ci      */
460bf215546Sopenharmony_ci      SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle);
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci      boolean to_invalidate = svga_was_texture_rendered_to(tex);
463bf215546Sopenharmony_ci      svga_screen_surface_destroy(ss, &tex->key, to_invalidate, &tex->handle);
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci      /* Destroy the backed surface handle if exists */
466bf215546Sopenharmony_ci      if (tex->backed_handle)
467bf215546Sopenharmony_ci         svga_screen_surface_destroy(ss, &tex->backed_key, to_invalidate, &tex->backed_handle);
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci      ss->hud.total_resource_bytes -= tex->size;
470bf215546Sopenharmony_ci
471bf215546Sopenharmony_ci      FREE(tex->defined);
472bf215546Sopenharmony_ci      FREE(tex->rendered_to);
473bf215546Sopenharmony_ci      FREE(tex->dirty);
474bf215546Sopenharmony_ci      FREE(tex);
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci      assert(ss->hud.num_resources > 0);
477bf215546Sopenharmony_ci      if (ss->hud.num_resources > 0)
478bf215546Sopenharmony_ci         ss->hud.num_resources--;
479bf215546Sopenharmony_ci   }
480bf215546Sopenharmony_ci}
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_cistruct pipe_resource *
483bf215546Sopenharmony_cisvga_buffer_create(struct pipe_screen *screen,
484bf215546Sopenharmony_ci                   const struct pipe_resource *template)
485bf215546Sopenharmony_ci{
486bf215546Sopenharmony_ci   struct svga_screen *ss = svga_screen(screen);
487bf215546Sopenharmony_ci   struct svga_buffer *sbuf;
488bf215546Sopenharmony_ci   unsigned bind_flags;
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_ci   SVGA_STATS_TIME_PUSH(ss->sws, SVGA_STATS_TIME_CREATEBUFFER);
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci   sbuf = CALLOC_STRUCT(svga_buffer);
493bf215546Sopenharmony_ci   if (!sbuf)
494bf215546Sopenharmony_ci      goto error1;
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   sbuf->b = *template;
497bf215546Sopenharmony_ci   pipe_reference_init(&sbuf->b.reference, 1);
498bf215546Sopenharmony_ci   sbuf->b.screen = screen;
499bf215546Sopenharmony_ci   bind_flags = template->bind & ~PIPE_BIND_CUSTOM;
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci   list_inithead(&sbuf->surfaces);
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   if (bind_flags & PIPE_BIND_CONSTANT_BUFFER) {
504bf215546Sopenharmony_ci      /* Constant buffers can only have the PIPE_BIND_CONSTANT_BUFFER
505bf215546Sopenharmony_ci       * flag set.
506bf215546Sopenharmony_ci       */
507bf215546Sopenharmony_ci      if (ss->sws->have_vgpu10) {
508bf215546Sopenharmony_ci         bind_flags = PIPE_BIND_CONSTANT_BUFFER;
509bf215546Sopenharmony_ci      }
510bf215546Sopenharmony_ci   }
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_ci   /* Although svga device only requires constant buffer size to be
513bf215546Sopenharmony_ci    * in multiples of 16, in order to allow bind_flags promotion,
514bf215546Sopenharmony_ci    * we are mandating all buffer size to be in multiples of 16.
515bf215546Sopenharmony_ci    */
516bf215546Sopenharmony_ci   sbuf->b.width0 = align(sbuf->b.width0, 16);
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   if (svga_buffer_needs_hw_storage(ss, template)) {
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci      /* If the buffer is not used for constant buffer, set
521bf215546Sopenharmony_ci       * the vertex/index bind flags as well so that the buffer will be
522bf215546Sopenharmony_ci       * accepted for those uses.
523bf215546Sopenharmony_ci       * Note that the PIPE_BIND_ flags we get from the gallium frontend are
524bf215546Sopenharmony_ci       * just a hint about how the buffer may be used.  And OpenGL buffer
525bf215546Sopenharmony_ci       * object may be used for many different things.
526bf215546Sopenharmony_ci       * Also note that we do not unconditionally set the streamout
527bf215546Sopenharmony_ci       * bind flag since streamout buffer is an output buffer and
528bf215546Sopenharmony_ci       * might have performance implication.
529bf215546Sopenharmony_ci       */
530bf215546Sopenharmony_ci      if (!(template->bind & PIPE_BIND_CONSTANT_BUFFER) &&
531bf215546Sopenharmony_ci          !(template->bind & PIPE_BIND_CUSTOM)) {
532bf215546Sopenharmony_ci         /* Not a constant- or staging buffer.
533bf215546Sopenharmony_ci          * The buffer may be used for vertex data or indexes.
534bf215546Sopenharmony_ci          */
535bf215546Sopenharmony_ci         bind_flags |= (PIPE_BIND_VERTEX_BUFFER |
536bf215546Sopenharmony_ci                        PIPE_BIND_INDEX_BUFFER);
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci         /* It may be used for shader resource as well. */
539bf215546Sopenharmony_ci         bind_flags |= PIPE_BIND_SAMPLER_VIEW;
540bf215546Sopenharmony_ci      }
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci      if (svga_buffer_create_host_surface(ss, sbuf, bind_flags) != PIPE_OK)
543bf215546Sopenharmony_ci         goto error2;
544bf215546Sopenharmony_ci   }
545bf215546Sopenharmony_ci   else {
546bf215546Sopenharmony_ci      sbuf->swbuf = align_malloc(sbuf->b.width0, 64);
547bf215546Sopenharmony_ci      if (!sbuf->swbuf)
548bf215546Sopenharmony_ci         goto error2;
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci      /* Since constant buffer is usually small, it is much cheaper to
551bf215546Sopenharmony_ci       * use system memory for the data just as it is being done for
552bf215546Sopenharmony_ci       * the default constant buffer.
553bf215546Sopenharmony_ci       */
554bf215546Sopenharmony_ci      if ((bind_flags & PIPE_BIND_CONSTANT_BUFFER) || !bind_flags)
555bf215546Sopenharmony_ci         sbuf->use_swbuf = TRUE;
556bf215546Sopenharmony_ci   }
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   debug_reference(&sbuf->b.reference,
559bf215546Sopenharmony_ci                   (debug_reference_descriptor)debug_describe_resource, 0);
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   sbuf->bind_flags = bind_flags;
562bf215546Sopenharmony_ci   sbuf->size = util_resource_size(&sbuf->b);
563bf215546Sopenharmony_ci   ss->hud.total_resource_bytes += sbuf->size;
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ci   ss->hud.num_resources++;
566bf215546Sopenharmony_ci   SVGA_STATS_TIME_POP(ss->sws);
567bf215546Sopenharmony_ci
568bf215546Sopenharmony_ci   return &sbuf->b;
569bf215546Sopenharmony_ci
570bf215546Sopenharmony_cierror2:
571bf215546Sopenharmony_ci   FREE(sbuf);
572bf215546Sopenharmony_cierror1:
573bf215546Sopenharmony_ci   SVGA_STATS_TIME_POP(ss->sws);
574bf215546Sopenharmony_ci   return NULL;
575bf215546Sopenharmony_ci}
576bf215546Sopenharmony_ci
577bf215546Sopenharmony_ci
578bf215546Sopenharmony_cistruct pipe_resource *
579bf215546Sopenharmony_cisvga_user_buffer_create(struct pipe_screen *screen,
580bf215546Sopenharmony_ci                        void *ptr,
581bf215546Sopenharmony_ci                        unsigned bytes,
582bf215546Sopenharmony_ci                        unsigned bind)
583bf215546Sopenharmony_ci{
584bf215546Sopenharmony_ci   struct svga_buffer *sbuf;
585bf215546Sopenharmony_ci   struct svga_screen *ss = svga_screen(screen);
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_ci   sbuf = CALLOC_STRUCT(svga_buffer);
588bf215546Sopenharmony_ci   if (!sbuf)
589bf215546Sopenharmony_ci      goto no_sbuf;
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   pipe_reference_init(&sbuf->b.reference, 1);
592bf215546Sopenharmony_ci   sbuf->b.screen = screen;
593bf215546Sopenharmony_ci   sbuf->b.format = PIPE_FORMAT_R8_UNORM; /* ?? */
594bf215546Sopenharmony_ci   sbuf->b.usage = PIPE_USAGE_IMMUTABLE;
595bf215546Sopenharmony_ci   sbuf->b.bind = bind;
596bf215546Sopenharmony_ci   sbuf->b.width0 = bytes;
597bf215546Sopenharmony_ci   sbuf->b.height0 = 1;
598bf215546Sopenharmony_ci   sbuf->b.depth0 = 1;
599bf215546Sopenharmony_ci   sbuf->b.array_size = 1;
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_ci   sbuf->bind_flags = bind;
602bf215546Sopenharmony_ci   sbuf->swbuf = ptr;
603bf215546Sopenharmony_ci   sbuf->user = TRUE;
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci   debug_reference(&sbuf->b.reference,
606bf215546Sopenharmony_ci                   (debug_reference_descriptor)debug_describe_resource, 0);
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   ss->hud.num_resources++;
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_ci   return &sbuf->b;
611bf215546Sopenharmony_ci
612bf215546Sopenharmony_cino_sbuf:
613bf215546Sopenharmony_ci   return NULL;
614bf215546Sopenharmony_ci}
615