1b8e80941Smrg/****************************************************************************
2b8e80941Smrg * Copyright (C) 2015 Intel Corporation.   All Rights Reserved.
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg ***************************************************************************/
23b8e80941Smrg
24b8e80941Smrg#include "swr_context.h"
25b8e80941Smrg#include "swr_memory.h"
26b8e80941Smrg#include "swr_screen.h"
27b8e80941Smrg#include "swr_resource.h"
28b8e80941Smrg#include "swr_scratch.h"
29b8e80941Smrg#include "swr_query.h"
30b8e80941Smrg#include "swr_fence.h"
31b8e80941Smrg
32b8e80941Smrg#include "util/u_memory.h"
33b8e80941Smrg#include "util/u_inlines.h"
34b8e80941Smrg#include "util/u_format.h"
35b8e80941Smrg#include "util/u_atomic.h"
36b8e80941Smrg#include "util/u_upload_mgr.h"
37b8e80941Smrg#include "util/u_transfer.h"
38b8e80941Smrg#include "util/u_surface.h"
39b8e80941Smrg
40b8e80941Smrg#include "api.h"
41b8e80941Smrg#include "backend.h"
42b8e80941Smrg#include "knobs.h"
43b8e80941Smrg
44b8e80941Smrgstatic struct pipe_surface *
45b8e80941Smrgswr_create_surface(struct pipe_context *pipe,
46b8e80941Smrg                   struct pipe_resource *pt,
47b8e80941Smrg                   const struct pipe_surface *surf_tmpl)
48b8e80941Smrg{
49b8e80941Smrg   struct pipe_surface *ps;
50b8e80941Smrg
51b8e80941Smrg   ps = CALLOC_STRUCT(pipe_surface);
52b8e80941Smrg   if (ps) {
53b8e80941Smrg      pipe_reference_init(&ps->reference, 1);
54b8e80941Smrg      pipe_resource_reference(&ps->texture, pt);
55b8e80941Smrg      ps->context = pipe;
56b8e80941Smrg      ps->format = surf_tmpl->format;
57b8e80941Smrg      if (pt->target != PIPE_BUFFER) {
58b8e80941Smrg         assert(surf_tmpl->u.tex.level <= pt->last_level);
59b8e80941Smrg         ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level);
60b8e80941Smrg         ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level);
61b8e80941Smrg         ps->u.tex.level = surf_tmpl->u.tex.level;
62b8e80941Smrg         ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
63b8e80941Smrg         ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
64b8e80941Smrg      } else {
65b8e80941Smrg         /* setting width as number of elements should get us correct
66b8e80941Smrg          * renderbuffer width */
67b8e80941Smrg         ps->width = surf_tmpl->u.buf.last_element
68b8e80941Smrg            - surf_tmpl->u.buf.first_element + 1;
69b8e80941Smrg         ps->height = pt->height0;
70b8e80941Smrg         ps->u.buf.first_element = surf_tmpl->u.buf.first_element;
71b8e80941Smrg         ps->u.buf.last_element = surf_tmpl->u.buf.last_element;
72b8e80941Smrg         assert(ps->u.buf.first_element <= ps->u.buf.last_element);
73b8e80941Smrg         assert(ps->u.buf.last_element < ps->width);
74b8e80941Smrg      }
75b8e80941Smrg   }
76b8e80941Smrg   return ps;
77b8e80941Smrg}
78b8e80941Smrg
79b8e80941Smrgstatic void
80b8e80941Smrgswr_surface_destroy(struct pipe_context *pipe, struct pipe_surface *surf)
81b8e80941Smrg{
82b8e80941Smrg   assert(surf->texture);
83b8e80941Smrg   struct pipe_resource *resource = surf->texture;
84b8e80941Smrg
85b8e80941Smrg   /* If the resource has been drawn to, store tiles. */
86b8e80941Smrg   swr_store_dirty_resource(pipe, resource, SWR_TILE_RESOLVED);
87b8e80941Smrg
88b8e80941Smrg   pipe_resource_reference(&resource, NULL);
89b8e80941Smrg   FREE(surf);
90b8e80941Smrg}
91b8e80941Smrg
92b8e80941Smrg
93b8e80941Smrgstatic void *
94b8e80941Smrgswr_transfer_map(struct pipe_context *pipe,
95b8e80941Smrg                 struct pipe_resource *resource,
96b8e80941Smrg                 unsigned level,
97b8e80941Smrg                 unsigned usage,
98b8e80941Smrg                 const struct pipe_box *box,
99b8e80941Smrg                 struct pipe_transfer **transfer)
100b8e80941Smrg{
101b8e80941Smrg   struct swr_screen *screen = swr_screen(pipe->screen);
102b8e80941Smrg   struct swr_resource *spr = swr_resource(resource);
103b8e80941Smrg   struct pipe_transfer *pt;
104b8e80941Smrg   enum pipe_format format = resource->format;
105b8e80941Smrg
106b8e80941Smrg   assert(resource);
107b8e80941Smrg   assert(level <= resource->last_level);
108b8e80941Smrg
109b8e80941Smrg   /* If mapping an attached rendertarget, store tiles to surface and set
110b8e80941Smrg    * postStoreTileState to SWR_TILE_INVALID so tiles get reloaded on next use
111b8e80941Smrg    * and nothing needs to be done at unmap. */
112b8e80941Smrg   swr_store_dirty_resource(pipe, resource, SWR_TILE_INVALID);
113b8e80941Smrg
114b8e80941Smrg   if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
115b8e80941Smrg      /* If resource is in use, finish fence before mapping.
116b8e80941Smrg       * Unless requested not to block, then if not done return NULL map */
117b8e80941Smrg      if (usage & PIPE_TRANSFER_DONTBLOCK) {
118b8e80941Smrg         if (swr_is_fence_pending(screen->flush_fence))
119b8e80941Smrg            return NULL;
120b8e80941Smrg      } else {
121b8e80941Smrg         if (spr->status) {
122b8e80941Smrg            /* But, if there's no fence pending, submit one.
123b8e80941Smrg             * XXX: Remove once draw timestamps are finished. */
124b8e80941Smrg            if (!swr_is_fence_pending(screen->flush_fence))
125b8e80941Smrg               swr_fence_submit(swr_context(pipe), screen->flush_fence);
126b8e80941Smrg
127b8e80941Smrg            swr_fence_finish(pipe->screen, NULL, screen->flush_fence, 0);
128b8e80941Smrg            swr_resource_unused(resource);
129b8e80941Smrg         }
130b8e80941Smrg      }
131b8e80941Smrg   }
132b8e80941Smrg
133b8e80941Smrg   pt = CALLOC_STRUCT(pipe_transfer);
134b8e80941Smrg   if (!pt)
135b8e80941Smrg      return NULL;
136b8e80941Smrg   pipe_resource_reference(&pt->resource, resource);
137b8e80941Smrg   pt->usage = (pipe_transfer_usage)usage;
138b8e80941Smrg   pt->level = level;
139b8e80941Smrg   pt->box = *box;
140b8e80941Smrg   pt->stride = spr->swr.pitch;
141b8e80941Smrg   pt->layer_stride = spr->swr.qpitch * spr->swr.pitch;
142b8e80941Smrg
143b8e80941Smrg   /* if we're mapping the depth/stencil, copy in stencil for the section
144b8e80941Smrg    * being read in
145b8e80941Smrg    */
146b8e80941Smrg   if (usage & PIPE_TRANSFER_READ && spr->has_depth && spr->has_stencil) {
147b8e80941Smrg      size_t zbase, sbase;
148b8e80941Smrg      for (int z = box->z; z < box->z + box->depth; z++) {
149b8e80941Smrg         zbase = (z * spr->swr.qpitch + box->y) * spr->swr.pitch +
150b8e80941Smrg            spr->mip_offsets[level];
151b8e80941Smrg         sbase = (z * spr->secondary.qpitch + box->y) * spr->secondary.pitch +
152b8e80941Smrg            spr->secondary_mip_offsets[level];
153b8e80941Smrg         for (int y = box->y; y < box->y + box->height; y++) {
154b8e80941Smrg            if (spr->base.format == PIPE_FORMAT_Z24_UNORM_S8_UINT) {
155b8e80941Smrg               for (int x = box->x; x < box->x + box->width; x++)
156b8e80941Smrg                  ((uint8_t*)(spr->swr.xpBaseAddress))[zbase + 4 * x + 3] =
157b8e80941Smrg                     ((uint8_t*)(spr->secondary.xpBaseAddress))[sbase + x];
158b8e80941Smrg            } else if (spr->base.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
159b8e80941Smrg               for (int x = box->x; x < box->x + box->width; x++)
160b8e80941Smrg                  ((uint8_t*)(spr->swr.xpBaseAddress))[zbase + 8 * x + 4] =
161b8e80941Smrg                     ((uint8_t*)(spr->secondary.xpBaseAddress))[sbase + x];
162b8e80941Smrg            }
163b8e80941Smrg            zbase += spr->swr.pitch;
164b8e80941Smrg            sbase += spr->secondary.pitch;
165b8e80941Smrg         }
166b8e80941Smrg      }
167b8e80941Smrg   }
168b8e80941Smrg
169b8e80941Smrg   unsigned offset = box->z * pt->layer_stride +
170b8e80941Smrg      util_format_get_nblocksy(format, box->y) * pt->stride +
171b8e80941Smrg      util_format_get_stride(format, box->x);
172b8e80941Smrg
173b8e80941Smrg   *transfer = pt;
174b8e80941Smrg
175b8e80941Smrg   return (void*)(spr->swr.xpBaseAddress + offset + spr->mip_offsets[level]);
176b8e80941Smrg}
177b8e80941Smrg
178b8e80941Smrgstatic void
179b8e80941Smrgswr_transfer_flush_region(struct pipe_context *pipe,
180b8e80941Smrg                          struct pipe_transfer *transfer,
181b8e80941Smrg                          const struct pipe_box *flush_box)
182b8e80941Smrg{
183b8e80941Smrg   assert(transfer->resource);
184b8e80941Smrg   assert(transfer->usage & PIPE_TRANSFER_WRITE);
185b8e80941Smrg
186b8e80941Smrg   struct swr_resource *spr = swr_resource(transfer->resource);
187b8e80941Smrg   if (!spr->has_depth || !spr->has_stencil)
188b8e80941Smrg      return;
189b8e80941Smrg
190b8e80941Smrg   size_t zbase, sbase;
191b8e80941Smrg   struct pipe_box box = *flush_box;
192b8e80941Smrg   box.x += transfer->box.x;
193b8e80941Smrg   box.y += transfer->box.y;
194b8e80941Smrg   box.z += transfer->box.z;
195b8e80941Smrg   for (int z = box.z; z < box.z + box.depth; z++) {
196b8e80941Smrg      zbase = (z * spr->swr.qpitch + box.y) * spr->swr.pitch +
197b8e80941Smrg         spr->mip_offsets[transfer->level];
198b8e80941Smrg      sbase = (z * spr->secondary.qpitch + box.y) * spr->secondary.pitch +
199b8e80941Smrg         spr->secondary_mip_offsets[transfer->level];
200b8e80941Smrg      for (int y = box.y; y < box.y + box.height; y++) {
201b8e80941Smrg         if (spr->base.format == PIPE_FORMAT_Z24_UNORM_S8_UINT) {
202b8e80941Smrg            for (int x = box.x; x < box.x + box.width; x++)
203b8e80941Smrg               ((uint8_t*)(spr->secondary.xpBaseAddress))[sbase + x] =
204b8e80941Smrg                  ((uint8_t*)(spr->swr.xpBaseAddress))[zbase + 4 * x + 3];
205b8e80941Smrg         } else if (spr->base.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
206b8e80941Smrg            for (int x = box.x; x < box.x + box.width; x++)
207b8e80941Smrg               ((uint8_t*)(spr->secondary.xpBaseAddress))[sbase + x] =
208b8e80941Smrg                  ((uint8_t*)(spr->swr.xpBaseAddress))[zbase + 8 * x + 4];
209b8e80941Smrg         }
210b8e80941Smrg         zbase += spr->swr.pitch;
211b8e80941Smrg         sbase += spr->secondary.pitch;
212b8e80941Smrg      }
213b8e80941Smrg   }
214b8e80941Smrg}
215b8e80941Smrg
216b8e80941Smrgstatic void
217b8e80941Smrgswr_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer)
218b8e80941Smrg{
219b8e80941Smrg   assert(transfer->resource);
220b8e80941Smrg
221b8e80941Smrg   struct swr_resource *spr = swr_resource(transfer->resource);
222b8e80941Smrg   /* if we're mapping the depth/stencil, copy in stencil for the section
223b8e80941Smrg    * being written out
224b8e80941Smrg    */
225b8e80941Smrg   if (transfer->usage & PIPE_TRANSFER_WRITE &&
226b8e80941Smrg       !(transfer->usage & PIPE_TRANSFER_FLUSH_EXPLICIT) &&
227b8e80941Smrg       spr->has_depth && spr->has_stencil) {
228b8e80941Smrg      struct pipe_box box;
229b8e80941Smrg      u_box_3d(0, 0, 0, transfer->box.width, transfer->box.height,
230b8e80941Smrg               transfer->box.depth, &box);
231b8e80941Smrg      swr_transfer_flush_region(pipe, transfer, &box);
232b8e80941Smrg   }
233b8e80941Smrg
234b8e80941Smrg   pipe_resource_reference(&transfer->resource, NULL);
235b8e80941Smrg   FREE(transfer);
236b8e80941Smrg}
237b8e80941Smrg
238b8e80941Smrg
239b8e80941Smrgstatic void
240b8e80941Smrgswr_resource_copy(struct pipe_context *pipe,
241b8e80941Smrg                  struct pipe_resource *dst,
242b8e80941Smrg                  unsigned dst_level,
243b8e80941Smrg                  unsigned dstx,
244b8e80941Smrg                  unsigned dsty,
245b8e80941Smrg                  unsigned dstz,
246b8e80941Smrg                  struct pipe_resource *src,
247b8e80941Smrg                  unsigned src_level,
248b8e80941Smrg                  const struct pipe_box *src_box)
249b8e80941Smrg{
250b8e80941Smrg   struct swr_screen *screen = swr_screen(pipe->screen);
251b8e80941Smrg
252b8e80941Smrg   /* If either the src or dst is a renderTarget, store tiles before copy */
253b8e80941Smrg   swr_store_dirty_resource(pipe, src, SWR_TILE_RESOLVED);
254b8e80941Smrg   swr_store_dirty_resource(pipe, dst, SWR_TILE_RESOLVED);
255b8e80941Smrg
256b8e80941Smrg   swr_fence_finish(pipe->screen, NULL, screen->flush_fence, 0);
257b8e80941Smrg   swr_resource_unused(src);
258b8e80941Smrg   swr_resource_unused(dst);
259b8e80941Smrg
260b8e80941Smrg   if ((dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER)
261b8e80941Smrg       || (dst->target != PIPE_BUFFER && src->target != PIPE_BUFFER)) {
262b8e80941Smrg      util_resource_copy_region(
263b8e80941Smrg         pipe, dst, dst_level, dstx, dsty, dstz, src, src_level, src_box);
264b8e80941Smrg      return;
265b8e80941Smrg   }
266b8e80941Smrg
267b8e80941Smrg   debug_printf("unhandled swr_resource_copy\n");
268b8e80941Smrg}
269b8e80941Smrg
270b8e80941Smrg
271b8e80941Smrgstatic void
272b8e80941Smrgswr_blit(struct pipe_context *pipe, const struct pipe_blit_info *blit_info)
273b8e80941Smrg{
274b8e80941Smrg   struct swr_context *ctx = swr_context(pipe);
275b8e80941Smrg   /* Make a copy of the const blit_info, so we can modify it */
276b8e80941Smrg   struct pipe_blit_info info = *blit_info;
277b8e80941Smrg
278b8e80941Smrg   if (info.render_condition_enable && !swr_check_render_cond(pipe))
279b8e80941Smrg      return;
280b8e80941Smrg
281b8e80941Smrg   if (info.src.resource->nr_samples > 1 && info.dst.resource->nr_samples <= 1
282b8e80941Smrg       && !util_format_is_depth_or_stencil(info.src.resource->format)
283b8e80941Smrg       && !util_format_is_pure_integer(info.src.resource->format)) {
284b8e80941Smrg      debug_printf("swr_blit: color resolve : %d -> %d\n",
285b8e80941Smrg            info.src.resource->nr_samples, info.dst.resource->nr_samples);
286b8e80941Smrg
287b8e80941Smrg      /* Resolve is done as part of the surface store. */
288b8e80941Smrg      swr_store_dirty_resource(pipe, info.src.resource, SWR_TILE_RESOLVED);
289b8e80941Smrg
290b8e80941Smrg      struct pipe_resource *src_resource = info.src.resource;
291b8e80941Smrg      struct pipe_resource *resolve_target =
292b8e80941Smrg         swr_resource(src_resource)->resolve_target;
293b8e80941Smrg
294b8e80941Smrg      /* The resolve target becomes the new source for the blit. */
295b8e80941Smrg      info.src.resource = resolve_target;
296b8e80941Smrg   }
297b8e80941Smrg
298b8e80941Smrg   if (util_try_blit_via_copy_region(pipe, &info)) {
299b8e80941Smrg      return; /* done */
300b8e80941Smrg   }
301b8e80941Smrg
302b8e80941Smrg   if (info.mask & PIPE_MASK_S) {
303b8e80941Smrg      debug_printf("swr: cannot blit stencil, skipping\n");
304b8e80941Smrg      info.mask &= ~PIPE_MASK_S;
305b8e80941Smrg   }
306b8e80941Smrg
307b8e80941Smrg   if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
308b8e80941Smrg      debug_printf("swr: blit unsupported %s -> %s\n",
309b8e80941Smrg                   util_format_short_name(info.src.resource->format),
310b8e80941Smrg                   util_format_short_name(info.dst.resource->format));
311b8e80941Smrg      return;
312b8e80941Smrg   }
313b8e80941Smrg
314b8e80941Smrg   if (ctx->active_queries) {
315b8e80941Smrg      ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, FALSE);
316b8e80941Smrg      ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, FALSE);
317b8e80941Smrg   }
318b8e80941Smrg
319b8e80941Smrg   util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertex_buffer);
320b8e80941Smrg   util_blitter_save_vertex_elements(ctx->blitter, (void *)ctx->velems);
321b8e80941Smrg   util_blitter_save_vertex_shader(ctx->blitter, (void *)ctx->vs);
322b8e80941Smrg   util_blitter_save_geometry_shader(ctx->blitter, (void*)ctx->gs);
323b8e80941Smrg   util_blitter_save_so_targets(
324b8e80941Smrg      ctx->blitter,
325b8e80941Smrg      ctx->num_so_targets,
326b8e80941Smrg      (struct pipe_stream_output_target **)ctx->so_targets);
327b8e80941Smrg   util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer);
328b8e80941Smrg   util_blitter_save_viewport(ctx->blitter, &ctx->viewport);
329b8e80941Smrg   util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
330b8e80941Smrg   util_blitter_save_fragment_shader(ctx->blitter, ctx->fs);
331b8e80941Smrg   util_blitter_save_blend(ctx->blitter, (void *)ctx->blend);
332b8e80941Smrg   util_blitter_save_depth_stencil_alpha(ctx->blitter,
333b8e80941Smrg                                         (void *)ctx->depth_stencil);
334b8e80941Smrg   util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
335b8e80941Smrg   util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask);
336b8e80941Smrg   util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer);
337b8e80941Smrg   util_blitter_save_fragment_sampler_states(
338b8e80941Smrg      ctx->blitter,
339b8e80941Smrg      ctx->num_samplers[PIPE_SHADER_FRAGMENT],
340b8e80941Smrg      (void **)ctx->samplers[PIPE_SHADER_FRAGMENT]);
341b8e80941Smrg   util_blitter_save_fragment_sampler_views(
342b8e80941Smrg      ctx->blitter,
343b8e80941Smrg      ctx->num_sampler_views[PIPE_SHADER_FRAGMENT],
344b8e80941Smrg      ctx->sampler_views[PIPE_SHADER_FRAGMENT]);
345b8e80941Smrg   util_blitter_save_render_condition(ctx->blitter,
346b8e80941Smrg                                      ctx->render_cond_query,
347b8e80941Smrg                                      ctx->render_cond_cond,
348b8e80941Smrg                                      ctx->render_cond_mode);
349b8e80941Smrg
350b8e80941Smrg   util_blitter_blit(ctx->blitter, &info);
351b8e80941Smrg
352b8e80941Smrg   if (ctx->active_queries) {
353b8e80941Smrg      ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, TRUE);
354b8e80941Smrg      ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, TRUE);
355b8e80941Smrg   }
356b8e80941Smrg}
357b8e80941Smrg
358b8e80941Smrg
359b8e80941Smrgstatic void
360b8e80941Smrgswr_destroy(struct pipe_context *pipe)
361b8e80941Smrg{
362b8e80941Smrg   struct swr_context *ctx = swr_context(pipe);
363b8e80941Smrg   struct swr_screen *screen = swr_screen(pipe->screen);
364b8e80941Smrg
365b8e80941Smrg   if (ctx->blitter)
366b8e80941Smrg      util_blitter_destroy(ctx->blitter);
367b8e80941Smrg
368b8e80941Smrg   for (unsigned i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
369b8e80941Smrg      if (ctx->framebuffer.cbufs[i]) {
370b8e80941Smrg         struct swr_resource *res = swr_resource(ctx->framebuffer.cbufs[i]->texture);
371b8e80941Smrg         /* NULL curr_pipe, so we don't have a reference to a deleted pipe */
372b8e80941Smrg         res->curr_pipe = NULL;
373b8e80941Smrg         pipe_surface_reference(&ctx->framebuffer.cbufs[i], NULL);
374b8e80941Smrg      }
375b8e80941Smrg   }
376b8e80941Smrg
377b8e80941Smrg   if (ctx->framebuffer.zsbuf) {
378b8e80941Smrg      struct swr_resource *res = swr_resource(ctx->framebuffer.zsbuf->texture);
379b8e80941Smrg      /* NULL curr_pipe, so we don't have a reference to a deleted pipe */
380b8e80941Smrg      res->curr_pipe = NULL;
381b8e80941Smrg      pipe_surface_reference(&ctx->framebuffer.zsbuf, NULL);
382b8e80941Smrg   }
383b8e80941Smrg
384b8e80941Smrg   for (unsigned i = 0; i < ARRAY_SIZE(ctx->sampler_views[0]); i++) {
385b8e80941Smrg      pipe_sampler_view_reference(&ctx->sampler_views[PIPE_SHADER_FRAGMENT][i], NULL);
386b8e80941Smrg   }
387b8e80941Smrg
388b8e80941Smrg   for (unsigned i = 0; i < ARRAY_SIZE(ctx->sampler_views[0]); i++) {
389b8e80941Smrg      pipe_sampler_view_reference(&ctx->sampler_views[PIPE_SHADER_VERTEX][i], NULL);
390b8e80941Smrg   }
391b8e80941Smrg
392b8e80941Smrg   if (ctx->pipe.stream_uploader)
393b8e80941Smrg      u_upload_destroy(ctx->pipe.stream_uploader);
394b8e80941Smrg
395b8e80941Smrg   /* Idle core after destroying buffer resources, but before deleting
396b8e80941Smrg    * context.  Destroying resources has potentially called StoreTiles.*/
397b8e80941Smrg   ctx->api.pfnSwrWaitForIdle(ctx->swrContext);
398b8e80941Smrg
399b8e80941Smrg   if (ctx->swrContext)
400b8e80941Smrg      ctx->api.pfnSwrDestroyContext(ctx->swrContext);
401b8e80941Smrg
402b8e80941Smrg   delete ctx->blendJIT;
403b8e80941Smrg
404b8e80941Smrg   swr_destroy_scratch_buffers(ctx);
405b8e80941Smrg
406b8e80941Smrg   /* Only update screen->pipe if current context is being destroyed */
407b8e80941Smrg   assert(screen);
408b8e80941Smrg   if (screen->pipe == pipe)
409b8e80941Smrg      screen->pipe = NULL;
410b8e80941Smrg
411b8e80941Smrg   AlignedFree(ctx);
412b8e80941Smrg}
413b8e80941Smrg
414b8e80941Smrg
415b8e80941Smrgstatic void
416b8e80941Smrgswr_render_condition(struct pipe_context *pipe,
417b8e80941Smrg                     struct pipe_query *query,
418b8e80941Smrg                     boolean condition,
419b8e80941Smrg                     enum pipe_render_cond_flag mode)
420b8e80941Smrg{
421b8e80941Smrg   struct swr_context *ctx = swr_context(pipe);
422b8e80941Smrg
423b8e80941Smrg   ctx->render_cond_query = query;
424b8e80941Smrg   ctx->render_cond_mode = mode;
425b8e80941Smrg   ctx->render_cond_cond = condition;
426b8e80941Smrg}
427b8e80941Smrg
428b8e80941Smrgstatic void
429b8e80941Smrgswr_UpdateStats(HANDLE hPrivateContext, const SWR_STATS *pStats)
430b8e80941Smrg{
431b8e80941Smrg   swr_draw_context *pDC = (swr_draw_context*)hPrivateContext;
432b8e80941Smrg
433b8e80941Smrg   if (!pDC)
434b8e80941Smrg      return;
435b8e80941Smrg
436b8e80941Smrg   struct swr_query_result *pqr = pDC->pStats;
437b8e80941Smrg
438b8e80941Smrg   SWR_STATS *pSwrStats = &pqr->core;
439b8e80941Smrg
440b8e80941Smrg   pSwrStats->DepthPassCount += pStats->DepthPassCount;
441b8e80941Smrg   pSwrStats->PsInvocations += pStats->PsInvocations;
442b8e80941Smrg   pSwrStats->CsInvocations += pStats->CsInvocations;
443b8e80941Smrg}
444b8e80941Smrg
445b8e80941Smrgstatic void
446b8e80941Smrgswr_UpdateStatsFE(HANDLE hPrivateContext, const SWR_STATS_FE *pStats)
447b8e80941Smrg{
448b8e80941Smrg   swr_draw_context *pDC = (swr_draw_context*)hPrivateContext;
449b8e80941Smrg
450b8e80941Smrg   if (!pDC)
451b8e80941Smrg      return;
452b8e80941Smrg
453b8e80941Smrg   struct swr_query_result *pqr = pDC->pStats;
454b8e80941Smrg
455b8e80941Smrg   SWR_STATS_FE *pSwrStats = &pqr->coreFE;
456b8e80941Smrg   p_atomic_add(&pSwrStats->IaVertices, pStats->IaVertices);
457b8e80941Smrg   p_atomic_add(&pSwrStats->IaPrimitives, pStats->IaPrimitives);
458b8e80941Smrg   p_atomic_add(&pSwrStats->VsInvocations, pStats->VsInvocations);
459b8e80941Smrg   p_atomic_add(&pSwrStats->HsInvocations, pStats->HsInvocations);
460b8e80941Smrg   p_atomic_add(&pSwrStats->DsInvocations, pStats->DsInvocations);
461b8e80941Smrg   p_atomic_add(&pSwrStats->GsInvocations, pStats->GsInvocations);
462b8e80941Smrg   p_atomic_add(&pSwrStats->CInvocations, pStats->CInvocations);
463b8e80941Smrg   p_atomic_add(&pSwrStats->CPrimitives, pStats->CPrimitives);
464b8e80941Smrg   p_atomic_add(&pSwrStats->GsPrimitives, pStats->GsPrimitives);
465b8e80941Smrg
466b8e80941Smrg   for (unsigned i = 0; i < 4; i++) {
467b8e80941Smrg      p_atomic_add(&pSwrStats->SoPrimStorageNeeded[i],
468b8e80941Smrg            pStats->SoPrimStorageNeeded[i]);
469b8e80941Smrg      p_atomic_add(&pSwrStats->SoNumPrimsWritten[i],
470b8e80941Smrg            pStats->SoNumPrimsWritten[i]);
471b8e80941Smrg   }
472b8e80941Smrg}
473b8e80941Smrg
474b8e80941Smrgstruct pipe_context *
475b8e80941Smrgswr_create_context(struct pipe_screen *p_screen, void *priv, unsigned flags)
476b8e80941Smrg{
477b8e80941Smrg   struct swr_context *ctx = (struct swr_context *)
478b8e80941Smrg      AlignedMalloc(sizeof(struct swr_context), KNOB_SIMD_BYTES);
479b8e80941Smrg   memset(ctx, 0, sizeof(struct swr_context));
480b8e80941Smrg
481b8e80941Smrg   swr_screen(p_screen)->pfnSwrGetInterface(ctx->api);
482b8e80941Smrg   ctx->swrDC.pAPI = &ctx->api;
483b8e80941Smrg
484b8e80941Smrg   ctx->blendJIT =
485b8e80941Smrg      new std::unordered_map<BLEND_COMPILE_STATE, PFN_BLEND_JIT_FUNC>;
486b8e80941Smrg
487b8e80941Smrg   ctx->max_draws_in_flight = KNOB_MAX_DRAWS_IN_FLIGHT;
488b8e80941Smrg
489b8e80941Smrg   SWR_CREATECONTEXT_INFO createInfo;
490b8e80941Smrg   memset(&createInfo, 0, sizeof(createInfo));
491b8e80941Smrg   createInfo.privateStateSize = sizeof(swr_draw_context);
492b8e80941Smrg   createInfo.pfnLoadTile = swr_LoadHotTile;
493b8e80941Smrg   createInfo.pfnStoreTile = swr_StoreHotTile;
494b8e80941Smrg   createInfo.pfnClearTile = swr_StoreHotTileClear;
495b8e80941Smrg   createInfo.pfnUpdateStats = swr_UpdateStats;
496b8e80941Smrg   createInfo.pfnUpdateStatsFE = swr_UpdateStatsFE;
497b8e80941Smrg   createInfo.pfnMakeGfxPtr = swr_MakeGfxPtr;
498b8e80941Smrg
499b8e80941Smrg   SWR_THREADING_INFO threadingInfo {0};
500b8e80941Smrg
501b8e80941Smrg   threadingInfo.MAX_WORKER_THREADS        = KNOB_MAX_WORKER_THREADS;
502b8e80941Smrg   threadingInfo.MAX_NUMA_NODES            = KNOB_MAX_NUMA_NODES;
503b8e80941Smrg   threadingInfo.MAX_CORES_PER_NUMA_NODE   = KNOB_MAX_CORES_PER_NUMA_NODE;
504b8e80941Smrg   threadingInfo.MAX_THREADS_PER_CORE      = KNOB_MAX_THREADS_PER_CORE;
505b8e80941Smrg   threadingInfo.SINGLE_THREADED           = KNOB_SINGLE_THREADED;
506b8e80941Smrg
507b8e80941Smrg   // Use non-standard settings for KNL
508b8e80941Smrg   if (swr_screen(p_screen)->is_knl)
509b8e80941Smrg   {
510b8e80941Smrg      if (nullptr == getenv("KNOB_MAX_THREADS_PER_CORE"))
511b8e80941Smrg         threadingInfo.MAX_THREADS_PER_CORE  = 2;
512b8e80941Smrg
513b8e80941Smrg      if (nullptr == getenv("KNOB_MAX_DRAWS_IN_FLIGHT"))
514b8e80941Smrg      {
515b8e80941Smrg         ctx->max_draws_in_flight = 2048;
516b8e80941Smrg         createInfo.MAX_DRAWS_IN_FLIGHT = ctx->max_draws_in_flight;
517b8e80941Smrg      }
518b8e80941Smrg   }
519b8e80941Smrg
520b8e80941Smrg   createInfo.pThreadInfo = &threadingInfo;
521b8e80941Smrg
522b8e80941Smrg   ctx->swrContext = ctx->api.pfnSwrCreateContext(&createInfo);
523b8e80941Smrg
524b8e80941Smrg   ctx->api.pfnSwrInit();
525b8e80941Smrg
526b8e80941Smrg   if (ctx->swrContext == NULL)
527b8e80941Smrg      goto fail;
528b8e80941Smrg
529b8e80941Smrg   ctx->pipe.screen = p_screen;
530b8e80941Smrg   ctx->pipe.destroy = swr_destroy;
531b8e80941Smrg   ctx->pipe.priv = priv;
532b8e80941Smrg   ctx->pipe.create_surface = swr_create_surface;
533b8e80941Smrg   ctx->pipe.surface_destroy = swr_surface_destroy;
534b8e80941Smrg   ctx->pipe.transfer_map = swr_transfer_map;
535b8e80941Smrg   ctx->pipe.transfer_unmap = swr_transfer_unmap;
536b8e80941Smrg   ctx->pipe.transfer_flush_region = swr_transfer_flush_region;
537b8e80941Smrg
538b8e80941Smrg   ctx->pipe.buffer_subdata = u_default_buffer_subdata;
539b8e80941Smrg   ctx->pipe.texture_subdata = u_default_texture_subdata;
540b8e80941Smrg
541b8e80941Smrg   ctx->pipe.clear_texture = util_clear_texture;
542b8e80941Smrg   ctx->pipe.resource_copy_region = swr_resource_copy;
543b8e80941Smrg   ctx->pipe.render_condition = swr_render_condition;
544b8e80941Smrg
545b8e80941Smrg   swr_state_init(&ctx->pipe);
546b8e80941Smrg   swr_clear_init(&ctx->pipe);
547b8e80941Smrg   swr_draw_init(&ctx->pipe);
548b8e80941Smrg   swr_query_init(&ctx->pipe);
549b8e80941Smrg
550b8e80941Smrg   ctx->pipe.stream_uploader = u_upload_create_default(&ctx->pipe);
551b8e80941Smrg   if (!ctx->pipe.stream_uploader)
552b8e80941Smrg      goto fail;
553b8e80941Smrg   ctx->pipe.const_uploader = ctx->pipe.stream_uploader;
554b8e80941Smrg
555b8e80941Smrg   ctx->pipe.blit = swr_blit;
556b8e80941Smrg   ctx->blitter = util_blitter_create(&ctx->pipe);
557b8e80941Smrg   if (!ctx->blitter)
558b8e80941Smrg      goto fail;
559b8e80941Smrg
560b8e80941Smrg   swr_init_scratch_buffers(ctx);
561b8e80941Smrg
562b8e80941Smrg   return &ctx->pipe;
563b8e80941Smrg
564b8e80941Smrgfail:
565b8e80941Smrg   /* Should really validate the init steps and fail gracefully */
566b8e80941Smrg   swr_destroy(&ctx->pipe);
567b8e80941Smrg   return NULL;
568b8e80941Smrg}
569