1/*
2 * Copyright 2013 VMware, Inc.  All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25
26/**
27 * VGPU10 sampler and sampler view functions.
28 */
29
30
31#include "pipe/p_defines.h"
32#include "util/u_bitmask.h"
33#include "util/u_format.h"
34#include "util/u_inlines.h"
35#include "util/u_math.h"
36#include "util/u_memory.h"
37
38#include "svga_cmd.h"
39#include "svga_context.h"
40#include "svga_format.h"
41#include "svga_resource_buffer.h"
42#include "svga_resource_texture.h"
43#include "svga_sampler_view.h"
44#include "svga_shader.h"
45#include "svga_state.h"
46#include "svga_surface.h"
47#include "svga3d_surfacedefs.h"
48
49/** Get resource handle for a texture or buffer */
50static inline struct svga_winsys_surface *
51svga_resource_handle(struct pipe_resource *res)
52{
53   if (res->target == PIPE_BUFFER) {
54      return svga_buffer(res)->handle;
55   }
56   else {
57      return svga_texture(res)->handle;
58   }
59}
60
61
62/**
63 * This helper function returns TRUE if the specified resource collides with
64 * any of the resources bound to any of the currently bound sampler views.
65 */
66boolean
67svga_check_sampler_view_resource_collision(const struct svga_context *svga,
68                                           const struct svga_winsys_surface *res,
69                                           enum pipe_shader_type shader)
70{
71   struct pipe_screen *screen = svga->pipe.screen;
72   unsigned i;
73
74   if (svga_screen(screen)->debug.no_surface_view) {
75      return FALSE;
76   }
77
78   for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) {
79      struct svga_pipe_sampler_view *sv =
80         svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
81
82      if (sv && res == svga_resource_handle(sv->base.texture)) {
83         return TRUE;
84      }
85   }
86
87   return FALSE;
88}
89
90
91/**
92 * Check if there are any resources that are both bound to a render target
93 * and bound as a shader resource for the given type of shader.
94 */
95boolean
96svga_check_sampler_framebuffer_resource_collision(struct svga_context *svga,
97                                                  enum pipe_shader_type shader)
98{
99   struct svga_surface *surf;
100   unsigned i;
101
102   for (i = 0; i < svga->curr.framebuffer.nr_cbufs; i++) {
103      surf = svga_surface(svga->curr.framebuffer.cbufs[i]);
104      if (surf &&
105          svga_check_sampler_view_resource_collision(svga, surf->handle,
106                                                     shader)) {
107         return TRUE;
108      }
109   }
110
111   surf = svga_surface(svga->curr.framebuffer.zsbuf);
112   if (surf &&
113       svga_check_sampler_view_resource_collision(svga, surf->handle, shader)) {
114      return TRUE;
115   }
116
117   return FALSE;
118}
119
120
121/**
122 * Create a DX ShaderResourceSamplerView for the given pipe_sampler_view,
123 * if needed.
124 */
125enum pipe_error
126svga_validate_pipe_sampler_view(struct svga_context *svga,
127                                struct svga_pipe_sampler_view *sv)
128{
129   enum pipe_error ret = PIPE_OK;
130
131   if (sv->id == SVGA3D_INVALID_ID) {
132      struct svga_screen *ss = svga_screen(svga->pipe.screen);
133      struct pipe_resource *texture = sv->base.texture;
134      struct svga_winsys_surface *surface = svga_resource_handle(texture);
135      SVGA3dSurfaceFormat format;
136      SVGA3dResourceType resourceDim;
137      SVGA3dShaderResourceViewDesc viewDesc;
138      enum pipe_format viewFormat = sv->base.format;
139
140      /* vgpu10 cannot create a BGRX view for a BGRA resource, so force it to
141       * create a BGRA view (and vice versa).
142       */
143      if (viewFormat == PIPE_FORMAT_B8G8R8X8_UNORM &&
144          svga_texture_device_format_has_alpha(texture)) {
145         viewFormat = PIPE_FORMAT_B8G8R8A8_UNORM;
146      }
147      else if (viewFormat == PIPE_FORMAT_B8G8R8A8_UNORM &&
148               !svga_texture_device_format_has_alpha(texture)) {
149         viewFormat = PIPE_FORMAT_B8G8R8X8_UNORM;
150      }
151
152      if (texture->target == PIPE_BUFFER) {
153         unsigned pf_flags;
154         svga_translate_texture_buffer_view_format(viewFormat,
155                                                   &format,
156                                                   &pf_flags);
157      }
158      else {
159         format = svga_translate_format(ss, viewFormat,
160                                        PIPE_BIND_SAMPLER_VIEW);
161
162         /* Convert the format to a sampler-friendly format, if needed */
163         format = svga_sampler_format(format);
164      }
165
166      assert(format != SVGA3D_FORMAT_INVALID);
167
168      if (texture->target == PIPE_BUFFER) {
169         unsigned elem_size = util_format_get_blocksize(sv->base.format);
170
171         viewDesc.buffer.firstElement = sv->base.u.buf.offset / elem_size;
172         viewDesc.buffer.numElements = sv->base.u.buf.size / elem_size;
173      }
174      else {
175         viewDesc.tex.mostDetailedMip = sv->base.u.tex.first_level;
176         viewDesc.tex.firstArraySlice = sv->base.u.tex.first_layer;
177         viewDesc.tex.mipLevels = (sv->base.u.tex.last_level -
178                                   sv->base.u.tex.first_level + 1);
179      }
180
181      /* arraySize in viewDesc specifies the number of array slices in a
182       * texture array. For 3D texture, last_layer in
183       * pipe_sampler_view specifies the last slice of the texture
184       * which is different from the last slice in a texture array,
185       * hence we need to set arraySize to 1 explicitly.
186       */
187      viewDesc.tex.arraySize =
188         (texture->target == PIPE_TEXTURE_3D ||
189          texture->target == PIPE_BUFFER) ? 1 :
190            (sv->base.u.tex.last_layer - sv->base.u.tex.first_layer + 1);
191
192      switch (texture->target) {
193      case PIPE_BUFFER:
194         resourceDim = SVGA3D_RESOURCE_BUFFER;
195         break;
196      case PIPE_TEXTURE_1D:
197      case PIPE_TEXTURE_1D_ARRAY:
198         resourceDim = SVGA3D_RESOURCE_TEXTURE1D;
199         break;
200      case PIPE_TEXTURE_RECT:
201      case PIPE_TEXTURE_2D:
202      case PIPE_TEXTURE_2D_ARRAY:
203         resourceDim = SVGA3D_RESOURCE_TEXTURE2D;
204         break;
205      case PIPE_TEXTURE_3D:
206         resourceDim = SVGA3D_RESOURCE_TEXTURE3D;
207         break;
208      case PIPE_TEXTURE_CUBE:
209      case PIPE_TEXTURE_CUBE_ARRAY:
210         resourceDim = SVGA3D_RESOURCE_TEXTURECUBE;
211         break;
212
213      default:
214         assert(!"Unexpected texture type");
215         resourceDim = SVGA3D_RESOURCE_TEXTURE2D;
216      }
217
218      sv->id = util_bitmask_add(svga->sampler_view_id_bm);
219
220      ret = SVGA3D_vgpu10_DefineShaderResourceView(svga->swc,
221                                                   sv->id,
222                                                   surface,
223                                                   format,
224                                                   resourceDim,
225                                                   &viewDesc);
226      if (ret != PIPE_OK) {
227         util_bitmask_clear(svga->sampler_view_id_bm, sv->id);
228         sv->id = SVGA3D_INVALID_ID;
229      }
230   }
231
232   return ret;
233}
234
235
236static enum pipe_error
237update_sampler_resources(struct svga_context *svga, unsigned dirty)
238{
239   enum pipe_error ret = PIPE_OK;
240   enum pipe_shader_type shader;
241
242   if (!svga_have_vgpu10(svga))
243      return PIPE_OK;
244
245   for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) {
246      SVGA3dShaderResourceViewId ids[PIPE_MAX_SAMPLERS];
247      struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS];
248      struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
249      unsigned count;
250      unsigned nviews;
251      unsigned i;
252
253      count = svga->curr.num_sampler_views[shader];
254      for (i = 0; i < count; i++) {
255         struct svga_pipe_sampler_view *sv =
256            svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
257
258         if (sv) {
259            surfaces[i] = svga_resource_handle(sv->base.texture);
260
261            ret = svga_validate_pipe_sampler_view(svga, sv);
262            if (ret != PIPE_OK)
263               return ret;
264
265            assert(sv->id != SVGA3D_INVALID_ID);
266            ids[i] = sv->id;
267            sampler_views[i] = &sv->base;
268         }
269         else {
270            surfaces[i] = NULL;
271            ids[i] = SVGA3D_INVALID_ID;
272            sampler_views[i] = NULL;
273         }
274      }
275
276      for (; i < svga->state.hw_draw.num_sampler_views[shader]; i++) {
277         ids[i] = SVGA3D_INVALID_ID;
278         surfaces[i] = NULL;
279         sampler_views[i] = NULL;
280      }
281
282      /* Number of ShaderResources that need to be modified. This includes
283       * the one that need to be unbound.
284       */
285      nviews = MAX2(svga->state.hw_draw.num_sampler_views[shader], count);
286      if (nviews > 0) {
287         if (count != svga->state.hw_draw.num_sampler_views[shader] ||
288             memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader],
289                    count * sizeof(sampler_views[0])) != 0) {
290            SVGA3dShaderResourceViewId *pIds = ids;
291            struct svga_winsys_surface **pSurf = surfaces;
292            unsigned numSR = 0;
293
294            /* Loop through the sampler view list to only emit
295             * the sampler views that are not already in the
296             * corresponding entries in the device's
297             * shader resource list.
298             */
299            for (i = 0; i < nviews; i++) {
300                boolean emit;
301
302                emit = sampler_views[i] ==
303                       svga->state.hw_draw.sampler_views[shader][i];
304
305                if (!emit && i == nviews-1) {
306                   /* Include the last sampler view in the next emit
307                    * if it is different.
308                    */
309                   emit = TRUE;
310                   numSR++;
311                   i++;
312                }
313
314                if (emit) {
315                   /* numSR can only be 0 if the first entry of the list
316                    * is the same as the one in the device list.
317                    * In this case, * there is nothing to send yet.
318                    */
319                   if (numSR) {
320                      ret = SVGA3D_vgpu10_SetShaderResources(
321                               svga->swc,
322                               svga_shader_type(shader),
323                               i - numSR, /* startView */
324                               numSR,
325                               pIds,
326                               pSurf);
327
328                      if (ret != PIPE_OK)
329                         return ret;
330                   }
331                   pIds += (numSR + 1);
332                   pSurf += (numSR + 1);
333                   numSR = 0;
334                }
335                else
336                   numSR++;
337            }
338
339            /* Save referenced sampler views in the hw draw state.  */
340            svga->state.hw_draw.num_sampler_views[shader] = count;
341            for (i = 0; i < nviews; i++) {
342               pipe_sampler_view_reference(
343                  &svga->state.hw_draw.sampler_views[shader][i],
344                  sampler_views[i]);
345            }
346         }
347      }
348   }
349
350   /* Handle polygon stipple sampler view */
351   if (svga->curr.rast->templ.poly_stipple_enable) {
352      const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
353      struct svga_pipe_sampler_view *sv = svga->polygon_stipple.sampler_view;
354      struct svga_winsys_surface *surface;
355
356      assert(sv);
357      if (!sv) {
358         return PIPE_OK;  /* probably out of memory */
359      }
360
361      ret = svga_validate_pipe_sampler_view(svga, sv);
362      if (ret != PIPE_OK)
363         return ret;
364
365      surface = svga_resource_handle(sv->base.texture);
366      ret = SVGA3D_vgpu10_SetShaderResources(
367               svga->swc,
368               svga_shader_type(PIPE_SHADER_FRAGMENT),
369               unit, /* startView */
370               1,
371               &sv->id,
372               &surface);
373   }
374   return ret;
375}
376
377
378struct svga_tracked_state svga_hw_sampler_bindings = {
379   "shader resources emit",
380   SVGA_NEW_STIPPLE |
381   SVGA_NEW_TEXTURE_BINDING,
382   update_sampler_resources
383};
384
385
386
387static enum pipe_error
388update_samplers(struct svga_context *svga, unsigned dirty )
389{
390   enum pipe_error ret = PIPE_OK;
391   enum pipe_shader_type shader;
392
393   if (!svga_have_vgpu10(svga))
394      return PIPE_OK;
395
396   for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) {
397      const unsigned count = svga->curr.num_samplers[shader];
398      SVGA3dSamplerId ids[PIPE_MAX_SAMPLERS];
399      unsigned i;
400      unsigned nsamplers;
401
402      for (i = 0; i < count; i++) {
403         bool fs_shadow = false;
404
405         /* _NEW_FS */
406         if (shader == PIPE_SHADER_FRAGMENT) {
407            struct svga_shader_variant *fs = svga->state.hw_draw.fs;
408            /* If the fragment shader is doing the shadow comparison
409             * for this texture unit, don't enable shadow compare in
410             * the texture sampler state.
411             */
412            if (fs && (fs->fs_shadow_compare_units & (1 << i))) {
413               fs_shadow = true;
414            }
415         }
416
417         if (svga->curr.sampler[shader][i]) {
418            ids[i] = svga->curr.sampler[shader][i]->id[fs_shadow];
419            assert(ids[i] != SVGA3D_INVALID_ID);
420         }
421         else {
422            ids[i] = SVGA3D_INVALID_ID;
423         }
424      }
425
426      for (; i < svga->state.hw_draw.num_samplers[shader]; i++) {
427         ids[i] = SVGA3D_INVALID_ID;
428      }
429
430      nsamplers = MAX2(svga->state.hw_draw.num_samplers[shader], count);
431      if (nsamplers > 0) {
432         if (count != svga->state.hw_draw.num_samplers[shader] ||
433             memcmp(ids, svga->state.hw_draw.samplers[shader],
434                    count * sizeof(ids[0])) != 0) {
435            /* HW state is really changing */
436            ret = SVGA3D_vgpu10_SetSamplers(svga->swc,
437                                            nsamplers,
438                                            0,                       /* start */
439                                            svga_shader_type(shader), /* type */
440                                            ids);
441            if (ret != PIPE_OK)
442               return ret;
443            memcpy(svga->state.hw_draw.samplers[shader], ids,
444                   nsamplers * sizeof(ids[0]));
445            svga->state.hw_draw.num_samplers[shader] = count;
446         }
447      }
448   }
449
450   /* Handle polygon stipple sampler texture */
451   if (svga->curr.rast->templ.poly_stipple_enable) {
452      const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
453      struct svga_sampler_state *sampler = svga->polygon_stipple.sampler;
454
455      assert(sampler);
456      if (!sampler) {
457         return PIPE_OK; /* probably out of memory */
458      }
459
460      if (svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit]
461          != sampler->id[0]) {
462         ret = SVGA3D_vgpu10_SetSamplers(svga->swc,
463                                         1, /* count */
464                                         unit, /* start */
465                                         SVGA3D_SHADERTYPE_PS,
466                                         &sampler->id[0]);
467         if (ret != PIPE_OK)
468            return ret;
469
470         /* save the polygon stipple sampler in the hw draw state */
471         svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit] =
472            sampler->id[0];
473      }
474   }
475
476   return ret;
477}
478
479
480struct svga_tracked_state svga_hw_sampler = {
481   "texture sampler emit",
482   (SVGA_NEW_FS |
483    SVGA_NEW_SAMPLER |
484    SVGA_NEW_STIPPLE),
485   update_samplers
486};
487