svga: avoid emitting redundant SetShaderResource command
[mesa.git] / src / gallium / drivers / svga / svga_state_sampler.c
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_shader.h"
44 #include "svga_state.h"
45 #include "svga_sampler_view.h"
46
47
48 /** Get resource handle for a texture or buffer */
49 static inline struct svga_winsys_surface *
50 svga_resource_handle(struct pipe_resource *res)
51 {
52 if (res->target == PIPE_BUFFER) {
53 return svga_buffer(res)->handle;
54 }
55 else {
56 return svga_texture(res)->handle;
57 }
58 }
59
60
61 /**
62 * This helper function returns TRUE if the specified resource collides with
63 * any of the resources bound to any of the currently bound sampler views.
64 */
65 boolean
66 svga_check_sampler_view_resource_collision(struct svga_context *svga,
67 struct svga_winsys_surface *res,
68 unsigned shader)
69 {
70 struct pipe_screen *screen = svga->pipe.screen;
71 unsigned i;
72
73 if (svga_screen(screen)->debug.no_surface_view) {
74 return FALSE;
75 }
76
77 for (i = 0; i < svga->curr.num_sampler_views[shader]; i++) {
78 struct svga_pipe_sampler_view *sv =
79 svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
80
81 if (sv && res == svga_resource_handle(sv->base.texture)) {
82 return TRUE;
83 }
84 }
85
86 return FALSE;
87 }
88
89
90 /**
91 * Create a DX ShaderResourceSamplerView for the given pipe_sampler_view,
92 * if needed.
93 */
94 enum pipe_error
95 svga_validate_pipe_sampler_view(struct svga_context *svga,
96 struct svga_pipe_sampler_view *sv)
97 {
98 enum pipe_error ret = PIPE_OK;
99
100 if (sv->id == SVGA3D_INVALID_ID) {
101 struct svga_screen *ss = svga_screen(svga->pipe.screen);
102 struct pipe_resource *texture = sv->base.texture;
103 struct svga_winsys_surface *surface = svga_resource_handle(texture);
104 SVGA3dSurfaceFormat format;
105 SVGA3dResourceType resourceDim;
106 SVGA3dShaderResourceViewDesc viewDesc;
107 enum pipe_format pformat = sv->base.format;
108
109 /* vgpu10 cannot create a BGRX view for a BGRA resource, so force it to
110 * create a BGRA view (and vice versa).
111 */
112 if (pformat == PIPE_FORMAT_B8G8R8X8_UNORM &&
113 sv->base.texture->format == PIPE_FORMAT_B8G8R8A8_UNORM) {
114 pformat = PIPE_FORMAT_B8G8R8A8_UNORM;
115 }
116 else if (pformat == PIPE_FORMAT_B8G8R8A8_UNORM &&
117 sv->base.texture->format == PIPE_FORMAT_B8G8R8X8_UNORM) {
118 pformat = PIPE_FORMAT_B8G8R8X8_UNORM;
119 }
120
121 format = svga_translate_format(ss, pformat,
122 PIPE_BIND_SAMPLER_VIEW);
123 assert(format != SVGA3D_FORMAT_INVALID);
124
125 /* Convert the format to a sampler-friendly format, if needed */
126 format = svga_sampler_format(format);
127
128 if (texture->target == PIPE_BUFFER) {
129 unsigned elem_size = util_format_get_blocksize(sv->base.format);
130
131 viewDesc.buffer.firstElement = sv->base.u.buf.offset / elem_size;
132 viewDesc.buffer.numElements = sv->base.u.buf.size / elem_size;
133 }
134 else {
135 viewDesc.tex.mostDetailedMip = sv->base.u.tex.first_level;
136 viewDesc.tex.firstArraySlice = sv->base.u.tex.first_layer;
137 viewDesc.tex.mipLevels = (sv->base.u.tex.last_level -
138 sv->base.u.tex.first_level + 1);
139 }
140
141 /* arraySize in viewDesc specifies the number of array slices in a
142 * texture array. For 3D texture, last_layer in
143 * pipe_sampler_view specifies the last slice of the texture
144 * which is different from the last slice in a texture array,
145 * hence we need to set arraySize to 1 explicitly.
146 */
147 viewDesc.tex.arraySize =
148 (texture->target == PIPE_TEXTURE_3D ||
149 texture->target == PIPE_BUFFER) ? 1 :
150 (sv->base.u.tex.last_layer - sv->base.u.tex.first_layer + 1);
151
152 switch (texture->target) {
153 case PIPE_BUFFER:
154 resourceDim = SVGA3D_RESOURCE_BUFFER;
155 break;
156 case PIPE_TEXTURE_1D:
157 case PIPE_TEXTURE_1D_ARRAY:
158 resourceDim = SVGA3D_RESOURCE_TEXTURE1D;
159 break;
160 case PIPE_TEXTURE_RECT:
161 case PIPE_TEXTURE_2D:
162 case PIPE_TEXTURE_2D_ARRAY:
163 resourceDim = SVGA3D_RESOURCE_TEXTURE2D;
164 break;
165 case PIPE_TEXTURE_3D:
166 resourceDim = SVGA3D_RESOURCE_TEXTURE3D;
167 break;
168 case PIPE_TEXTURE_CUBE:
169 case PIPE_TEXTURE_CUBE_ARRAY:
170 resourceDim = SVGA3D_RESOURCE_TEXTURECUBE;
171 break;
172
173 default:
174 assert(!"Unexpected texture type");
175 resourceDim = SVGA3D_RESOURCE_TEXTURE2D;
176 }
177
178 sv->id = util_bitmask_add(svga->sampler_view_id_bm);
179
180 ret = SVGA3D_vgpu10_DefineShaderResourceView(svga->swc,
181 sv->id,
182 surface,
183 format,
184 resourceDim,
185 &viewDesc);
186 if (ret != PIPE_OK) {
187 util_bitmask_clear(svga->sampler_view_id_bm, sv->id);
188 sv->id = SVGA3D_INVALID_ID;
189 }
190 }
191
192 return ret;
193 }
194
195
196 static enum pipe_error
197 update_sampler_resources(struct svga_context *svga, unsigned dirty)
198 {
199 enum pipe_error ret = PIPE_OK;
200 unsigned shader;
201
202 if (!svga_have_vgpu10(svga))
203 return PIPE_OK;
204
205 for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) {
206 SVGA3dShaderResourceViewId ids[PIPE_MAX_SAMPLERS];
207 struct svga_winsys_surface *surfaces[PIPE_MAX_SAMPLERS];
208 struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS];
209 unsigned count;
210 unsigned nviews;
211 unsigned i;
212
213 count = svga->curr.num_sampler_views[shader];
214 for (i = 0; i < count; i++) {
215 struct svga_pipe_sampler_view *sv =
216 svga_pipe_sampler_view(svga->curr.sampler_views[shader][i]);
217
218 if (sv) {
219 surfaces[i] = svga_resource_handle(sv->base.texture);
220
221 ret = svga_validate_pipe_sampler_view(svga, sv);
222 if (ret != PIPE_OK)
223 return ret;
224
225 assert(sv->id != SVGA3D_INVALID_ID);
226 ids[i] = sv->id;
227 sampler_views[i] = &sv->base;
228 }
229 else {
230 surfaces[i] = NULL;
231 ids[i] = SVGA3D_INVALID_ID;
232 sampler_views[i] = NULL;
233 }
234 }
235
236 for (; i < svga->state.hw_draw.num_sampler_views[shader]; i++) {
237 ids[i] = SVGA3D_INVALID_ID;
238 surfaces[i] = NULL;
239 sampler_views[i] = NULL;
240 }
241
242 /* Number of ShaderResources that need to be modified. This includes
243 * the one that need to be unbound.
244 */
245 nviews = MAX2(svga->state.hw_draw.num_sampler_views[shader], count);
246 if (nviews > 0) {
247 if (count != svga->state.hw_draw.num_sampler_views[shader] ||
248 memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader],
249 count * sizeof(sampler_views[0])) != 0) {
250 ret = SVGA3D_vgpu10_SetShaderResources(svga->swc,
251 svga_shader_type(shader),
252 0, /* startView */
253 nviews,
254 ids,
255 surfaces);
256 if (ret != PIPE_OK)
257 return ret;
258
259 /* Save referenced sampler views in the hw draw state. */
260 svga->state.hw_draw.num_sampler_views[shader] = count;
261 for (i = 0; i < nviews; i++) {
262 pipe_sampler_view_reference(
263 &svga->state.hw_draw.sampler_views[shader][i],
264 sampler_views[i]);
265 }
266 }
267 }
268 }
269
270 /* Handle polygon stipple sampler view */
271 if (svga->curr.rast->templ.poly_stipple_enable) {
272 const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
273 struct svga_pipe_sampler_view *sv = svga->polygon_stipple.sampler_view;
274 struct svga_winsys_surface *surface;
275
276 assert(sv);
277 if (!sv) {
278 return PIPE_OK; /* probably out of memory */
279 }
280
281 ret = svga_validate_pipe_sampler_view(svga, sv);
282 if (ret != PIPE_OK)
283 return ret;
284
285 surface = svga_resource_handle(sv->base.texture);
286 ret = SVGA3D_vgpu10_SetShaderResources(
287 svga->swc,
288 svga_shader_type(PIPE_SHADER_FRAGMENT),
289 unit, /* startView */
290 1,
291 &sv->id,
292 &surface);
293 }
294 return ret;
295 }
296
297
298 struct svga_tracked_state svga_hw_sampler_bindings = {
299 "shader resources emit",
300 SVGA_NEW_STIPPLE |
301 SVGA_NEW_TEXTURE_BINDING,
302 update_sampler_resources
303 };
304
305
306
307 static enum pipe_error
308 update_samplers(struct svga_context *svga, unsigned dirty )
309 {
310 enum pipe_error ret = PIPE_OK;
311 unsigned shader;
312
313 if (!svga_have_vgpu10(svga))
314 return PIPE_OK;
315
316 for (shader = PIPE_SHADER_VERTEX; shader <= PIPE_SHADER_GEOMETRY; shader++) {
317 const unsigned count = svga->curr.num_samplers[shader];
318 SVGA3dSamplerId ids[PIPE_MAX_SAMPLERS];
319 unsigned i;
320 unsigned nsamplers;
321
322 for (i = 0; i < count; i++) {
323 if (svga->curr.sampler[shader][i]) {
324 ids[i] = svga->curr.sampler[shader][i]->id;
325 assert(ids[i] != SVGA3D_INVALID_ID);
326 }
327 else {
328 ids[i] = SVGA3D_INVALID_ID;
329 }
330 }
331
332 for (; i < svga->state.hw_draw.num_samplers[shader]; i++) {
333 ids[i] = SVGA3D_INVALID_ID;
334 }
335
336 nsamplers = MAX2(svga->state.hw_draw.num_samplers[shader], count);
337 if (nsamplers > 0) {
338 if (count != svga->state.hw_draw.num_samplers[shader] ||
339 memcmp(ids, svga->state.hw_draw.samplers[shader],
340 count * sizeof(ids[0])) != 0) {
341 /* HW state is really changing */
342 ret = SVGA3D_vgpu10_SetSamplers(svga->swc,
343 nsamplers,
344 0, /* start */
345 svga_shader_type(shader), /* type */
346 ids);
347 if (ret != PIPE_OK)
348 return ret;
349 memcpy(svga->state.hw_draw.samplers[shader], ids,
350 nsamplers * sizeof(ids[0]));
351 svga->state.hw_draw.num_samplers[shader] = count;
352 }
353 }
354 }
355
356 /* Handle polygon stipple sampler texture */
357 if (svga->curr.rast->templ.poly_stipple_enable) {
358 const unsigned unit = svga->state.hw_draw.fs->pstipple_sampler_unit;
359 struct svga_sampler_state *sampler = svga->polygon_stipple.sampler;
360
361 assert(sampler);
362 if (!sampler) {
363 return PIPE_OK; /* probably out of memory */
364 }
365
366 if (svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit]
367 != sampler->id) {
368 ret = SVGA3D_vgpu10_SetSamplers(svga->swc,
369 1, /* count */
370 unit, /* start */
371 SVGA3D_SHADERTYPE_PS,
372 &sampler->id);
373 if (ret != PIPE_OK)
374 return ret;
375
376 /* save the polygon stipple sampler in the hw draw state */
377 svga->state.hw_draw.samplers[PIPE_SHADER_FRAGMENT][unit] =
378 sampler->id;
379 }
380 }
381
382 return ret;
383 }
384
385
386 struct svga_tracked_state svga_hw_sampler = {
387 "texture sampler emit",
388 (SVGA_NEW_SAMPLER |
389 SVGA_NEW_STIPPLE |
390 SVGA_NEW_TEXTURE_FLAGS),
391 update_samplers
392 };