st/va: Check NULL pointer
[mesa.git] / src / gallium / state_trackers / nine / stateblock9.c
1 /*
2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 #include "stateblock9.h"
24 #include "device9.h"
25 #include "basetexture9.h"
26 #include "nine_helpers.h"
27 #include "vertexdeclaration9.h"
28
29 #define DBG_CHANNEL DBG_STATEBLOCK
30
31 /* XXX TODO: handling of lights is broken */
32
33 HRESULT
34 NineStateBlock9_ctor( struct NineStateBlock9 *This,
35 struct NineUnknownParams *pParams,
36 enum nine_stateblock_type type )
37 {
38 HRESULT hr = NineUnknown_ctor(&This->base, pParams);
39
40 DBG("This=%p pParams=%p type=%d\n", This, pParams, type);
41
42 if (FAILED(hr))
43 return hr;
44
45 This->type = type;
46
47 This->state.vs_const_f = MALLOC(This->base.device->vs_const_size);
48 This->state.ps_const_f = MALLOC(This->base.device->ps_const_size);
49 if (!This->state.vs_const_f || !This->state.ps_const_f)
50 return E_OUTOFMEMORY;
51
52 return D3D_OK;
53 }
54
55 void
56 NineStateBlock9_dtor( struct NineStateBlock9 *This )
57 {
58 struct nine_state *state = &This->state;
59 struct nine_range *r;
60 struct nine_range_pool *pool = &This->base.device->range_pool;
61
62 nine_state_clear(state, FALSE);
63
64 FREE(state->vs_const_f);
65 FREE(state->ps_const_f);
66
67 FREE(state->ff.light);
68
69 FREE(state->ff.transform);
70
71 if (This->state.changed.ps_const_f) {
72 for (r = This->state.changed.ps_const_f; r->next; r = r->next);
73 nine_range_pool_put_chain(pool, This->state.changed.ps_const_f, r);
74 }
75 if (This->state.changed.vs_const_f) {
76 for (r = This->state.changed.vs_const_f; r->next; r = r->next);
77 nine_range_pool_put_chain(pool, This->state.changed.vs_const_f, r);
78 }
79
80 NineUnknown_dtor(&This->base);
81 }
82
83 /* Copy state marked changed in @mask from @src to @dst.
84 * If @apply is false, updating dst->changed can be omitted.
85 * TODO: compare ?
86 */
87 static void
88 nine_state_copy_common(struct nine_state *dst,
89 struct nine_state *src,
90 struct nine_state *mask, /* aliases either src or dst */
91 const boolean apply,
92 struct nine_range_pool *pool)
93 {
94 unsigned i, s;
95
96 if (apply)
97 dst->changed.group |= mask->changed.group;
98
99 if (mask->changed.group & NINE_STATE_VIEWPORT)
100 dst->viewport = src->viewport;
101 if (mask->changed.group & NINE_STATE_SCISSOR)
102 dst->scissor = src->scissor;
103
104 if (mask->changed.group & NINE_STATE_VS)
105 nine_bind(&dst->vs, src->vs);
106 if (mask->changed.group & NINE_STATE_PS)
107 nine_bind(&dst->ps, src->ps);
108
109 /* Vertex constants.
110 *
111 * Various possibilities for optimization here, like creating a per-SB
112 * constant buffer, or memcmp'ing for changes.
113 * Will do that later depending on what works best for specific apps.
114 */
115 if (mask->changed.group & NINE_STATE_VS_CONST) {
116 struct nine_range *r;
117 for (r = mask->changed.vs_const_f; r; r = r->next) {
118 memcpy(&dst->vs_const_f[r->bgn * 4],
119 &src->vs_const_f[r->bgn * 4],
120 (r->end - r->bgn) * 4 * sizeof(float));
121 if (apply)
122 nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end,
123 pool);
124 }
125 if (mask->changed.vs_const_i) {
126 uint16_t m = mask->changed.vs_const_i;
127 for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
128 if (m & 1)
129 memcpy(dst->vs_const_i[i], src->vs_const_i[i], 4 * sizeof(int));
130 if (apply)
131 dst->changed.vs_const_i |= mask->changed.vs_const_i;
132 }
133 if (mask->changed.vs_const_b) {
134 uint16_t m = mask->changed.vs_const_b;
135 for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
136 if (m & 1)
137 dst->vs_const_b[i] = src->vs_const_b[i];
138 if (apply)
139 dst->changed.vs_const_b |= mask->changed.vs_const_b;
140 }
141 }
142
143 /* Pixel constants. */
144 if (mask->changed.group & NINE_STATE_PS_CONST) {
145 struct nine_range *r;
146 for (r = mask->changed.ps_const_f; r; r = r->next) {
147 memcpy(&dst->ps_const_f[r->bgn * 4],
148 &src->ps_const_f[r->bgn * 4],
149 (r->end - r->bgn) * 4 * sizeof(float));
150 if (apply)
151 nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end,
152 pool);
153 }
154 if (mask->changed.ps_const_i) {
155 uint16_t m = mask->changed.ps_const_i;
156 for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
157 if (m & 1)
158 memcpy(dst->ps_const_i[i], src->ps_const_i[i], 4 * sizeof(int));
159 if (apply)
160 dst->changed.ps_const_i |= mask->changed.ps_const_i;
161 }
162 if (mask->changed.ps_const_b) {
163 uint16_t m = mask->changed.ps_const_b;
164 for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
165 if (m & 1)
166 dst->ps_const_b[i] = src->ps_const_b[i];
167 if (apply)
168 dst->changed.ps_const_b |= mask->changed.ps_const_b;
169 }
170 }
171
172 /* Render states.
173 * TODO: Maybe build a list ?
174 */
175 for (i = 0; i < ARRAY_SIZE(dst->changed.rs); ++i) {
176 uint32_t m = mask->changed.rs[i];
177 if (apply)
178 dst->changed.rs[i] |= m;
179 while (m) {
180 const int r = ffs(m) - 1;
181 m &= ~(1 << r);
182 dst->rs[i * 32 + r] = src->rs[i * 32 + r];
183 dst->rs_advertised[i * 32 + r] = src->rs_advertised[i * 32 + r];
184 }
185 }
186
187
188 /* Clip planes. */
189 if (mask->changed.ucp) {
190 for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i)
191 if (mask->changed.ucp & (1 << i))
192 memcpy(dst->clip.ucp[i],
193 src->clip.ucp[i], sizeof(src->clip.ucp[0]));
194 if (apply)
195 dst->changed.ucp |= mask->changed.ucp;
196 }
197
198 /* Sampler state. */
199 if (mask->changed.group & NINE_STATE_SAMPLER) {
200 for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
201 if (mask->changed.sampler[s] == 0x3ffe) {
202 memcpy(&dst->samp[s], &src->samp[s], sizeof(dst->samp[s]));
203 } else {
204 uint32_t m = mask->changed.sampler[s];
205 while (m) {
206 const int i = ffs(m) - 1;
207 m &= ~(1 << i);
208 dst->samp[s][i] = src->samp[s][i];
209 }
210 }
211 if (apply)
212 dst->changed.sampler[s] |= mask->changed.sampler[s];
213 }
214 }
215
216 /* Index buffer. */
217 if (mask->changed.group & NINE_STATE_IDXBUF)
218 nine_bind(&dst->idxbuf, src->idxbuf);
219
220 /* Vertex streams. */
221 if (mask->changed.vtxbuf | mask->changed.stream_freq) {
222 uint32_t m = mask->changed.vtxbuf | mask->changed.stream_freq;
223 for (i = 0; m; ++i, m >>= 1) {
224 if (mask->changed.vtxbuf & (1 << i)) {
225 nine_bind(&dst->stream[i], src->stream[i]);
226 if (src->stream[i]) {
227 dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset;
228 pipe_resource_reference(&dst->vtxbuf[i].buffer, src->vtxbuf[i].buffer);
229 dst->vtxbuf[i].stride = src->vtxbuf[i].stride;
230 }
231 }
232 if (mask->changed.stream_freq & (1 << i))
233 dst->stream_freq[i] = src->stream_freq[i];
234 }
235 dst->stream_instancedata_mask &= ~mask->changed.stream_freq;
236 dst->stream_instancedata_mask |=
237 src->stream_instancedata_mask & mask->changed.stream_freq;
238 if (apply) {
239 dst->changed.vtxbuf |= mask->changed.vtxbuf;
240 dst->changed.stream_freq |= mask->changed.stream_freq;
241 }
242 }
243
244 if (!(mask->changed.group & NINE_STATE_FF))
245 return;
246 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
247
248 /* Fixed function state. */
249 if (apply)
250 dst->ff.changed.group |= src->ff.changed.group;
251
252 if (mask->changed.group & NINE_STATE_FF_MATERIAL)
253 dst->ff.material = src->ff.material;
254
255 if (mask->changed.group & NINE_STATE_FF_PSSTAGES) {
256 for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) {
257 for (i = 0; i < NINED3DTSS_COUNT; ++i)
258 if (mask->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32)))
259 dst->ff.tex_stage[s][i] = src->ff.tex_stage[s][i];
260 if (apply) {
261 /* TODO: it's 32 exactly, just offset by 1 as 0 is unused */
262 dst->ff.changed.tex_stage[s][0] |=
263 mask->ff.changed.tex_stage[s][0];
264 dst->ff.changed.tex_stage[s][1] |=
265 mask->ff.changed.tex_stage[s][1];
266 }
267 }
268 }
269 if (mask->changed.group & NINE_STATE_FF_LIGHTING) {
270 unsigned num_lights = MAX2(dst->ff.num_lights, src->ff.num_lights);
271 /* Can happen in Capture() if device state has created new lights after
272 * the stateblock was created.
273 * Can happen in Apply() if the stateblock had recorded the creation of
274 * new lights. */
275 if (dst->ff.num_lights < num_lights) {
276 dst->ff.light = REALLOC(dst->ff.light,
277 dst->ff.num_lights * sizeof(D3DLIGHT9),
278 num_lights * sizeof(D3DLIGHT9));
279 memset(&dst->ff.light[dst->ff.num_lights], 0, (num_lights - dst->ff.num_lights) * sizeof(D3DLIGHT9));
280 /* if mask == dst, a Type of 0 will trigger
281 * "dst->ff.light[i] = src->ff.light[i];" later,
282 * which is what we want in that case. */
283 if (mask != dst) {
284 for (i = src->ff.num_lights; i < num_lights; ++i)
285 src->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
286 }
287 dst->ff.num_lights = num_lights;
288 }
289 /* Can happen in Capture() if the stateblock had recorded the creation of
290 * new lights.
291 * Can happen in Apply() if device state has created new lights after
292 * the stateblock was created. */
293 if (src->ff.num_lights < num_lights) {
294 src->ff.light = REALLOC(src->ff.light,
295 src->ff.num_lights * sizeof(D3DLIGHT9),
296 num_lights * sizeof(D3DLIGHT9));
297 memset(&src->ff.light[src->ff.num_lights], 0, (num_lights - src->ff.num_lights) * sizeof(D3DLIGHT9));
298 for (i = src->ff.num_lights; i < num_lights; ++i)
299 src->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
300 src->ff.num_lights = num_lights;
301 }
302 /* Note: mask is either src or dst, so at this point src, dst and mask
303 * have num_lights lights. */
304 for (i = 0; i < num_lights; ++i)
305 if (mask->ff.light[i].Type != NINED3DLIGHT_INVALID)
306 dst->ff.light[i] = src->ff.light[i];
307
308 memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) );
309 dst->ff.num_lights_active = src->ff.num_lights_active;
310 }
311 if (mask->changed.group & NINE_STATE_FF_VSTRANSF) {
312 for (i = 0; i < ARRAY_SIZE(mask->ff.changed.transform); ++i) {
313 if (!mask->ff.changed.transform[i])
314 continue;
315 for (s = i * 32; s < (i * 32 + 32); ++s) {
316 if (!(mask->ff.changed.transform[i] & (1 << (s % 32))))
317 continue;
318 *nine_state_access_transform(dst, s, TRUE) =
319 *nine_state_access_transform( /* const because !alloc */
320 (struct nine_state *)src, s, FALSE);
321 }
322 if (apply)
323 dst->ff.changed.transform[i] |= mask->ff.changed.transform[i];
324 }
325 }
326 }
327
328 static void
329 nine_state_copy_common_all(struct nine_state *dst,
330 const struct nine_state *src,
331 struct nine_state *help,
332 const boolean apply,
333 struct nine_range_pool *pool,
334 const int MaxStreams)
335 {
336 unsigned i;
337
338 if (apply)
339 dst->changed.group |= src->changed.group;
340
341 dst->viewport = src->viewport;
342 dst->scissor = src->scissor;
343
344 nine_bind(&dst->vs, src->vs);
345 nine_bind(&dst->ps, src->ps);
346
347 /* Vertex constants.
348 *
349 * Various possibilities for optimization here, like creating a per-SB
350 * constant buffer, or memcmp'ing for changes.
351 * Will do that later depending on what works best for specific apps.
352 */
353 if (1) {
354 struct nine_range *r = help->changed.vs_const_f;
355 memcpy(&dst->vs_const_f[0],
356 &src->vs_const_f[0], (r->end - r->bgn) * 4 * sizeof(float));
357 if (apply)
358 nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end, pool);
359
360 memcpy(dst->vs_const_i, src->vs_const_i, sizeof(dst->vs_const_i));
361 memcpy(dst->vs_const_b, src->vs_const_b, sizeof(dst->vs_const_b));
362 if (apply) {
363 dst->changed.vs_const_i |= src->changed.vs_const_i;
364 dst->changed.vs_const_b |= src->changed.vs_const_b;
365 }
366 }
367
368 /* Pixel constants. */
369 if (1) {
370 struct nine_range *r = help->changed.ps_const_f;
371 memcpy(&dst->ps_const_f[0],
372 &src->ps_const_f[0], (r->end - r->bgn) * 4 * sizeof(float));
373 if (apply)
374 nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end, pool);
375
376 memcpy(dst->ps_const_i, src->ps_const_i, sizeof(dst->ps_const_i));
377 memcpy(dst->ps_const_b, src->ps_const_b, sizeof(dst->ps_const_b));
378 if (apply) {
379 dst->changed.ps_const_i |= src->changed.ps_const_i;
380 dst->changed.ps_const_b |= src->changed.ps_const_b;
381 }
382 }
383
384 /* Render states. */
385 memcpy(dst->rs, src->rs, sizeof(dst->rs));
386 memcpy(dst->rs_advertised, src->rs_advertised, sizeof(dst->rs_advertised));
387 if (apply)
388 memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs));
389
390
391 /* Clip planes. */
392 memcpy(&dst->clip, &src->clip, sizeof(dst->clip));
393 if (apply)
394 dst->changed.ucp = src->changed.ucp;
395
396 /* Sampler state. */
397 memcpy(dst->samp, src->samp, sizeof(dst->samp));
398 if (apply)
399 memcpy(dst->changed.sampler,
400 src->changed.sampler, sizeof(dst->changed.sampler));
401
402 /* Index buffer. */
403 nine_bind(&dst->idxbuf, src->idxbuf);
404
405 /* Vertex streams. */
406 if (1) {
407 for (i = 0; i < ARRAY_SIZE(dst->stream); ++i) {
408 nine_bind(&dst->stream[i], src->stream[i]);
409 if (src->stream[i]) {
410 dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset;
411 pipe_resource_reference(&dst->vtxbuf[i].buffer, src->vtxbuf[i].buffer);
412 dst->vtxbuf[i].stride = src->vtxbuf[i].stride;
413 }
414 dst->stream_freq[i] = src->stream_freq[i];
415 }
416 dst->stream_instancedata_mask = src->stream_instancedata_mask;
417 if (apply) {
418 dst->changed.vtxbuf = (1ULL << MaxStreams) - 1;
419 dst->changed.stream_freq = (1ULL << MaxStreams) - 1;
420 }
421 }
422
423 /* keep this check in case we want to disable FF */
424 if (!(help->changed.group & NINE_STATE_FF))
425 return;
426 WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
427
428 /* Fixed function state. */
429 if (apply)
430 dst->ff.changed.group = src->ff.changed.group;
431
432 dst->ff.material = src->ff.material;
433
434 memcpy(dst->ff.tex_stage, src->ff.tex_stage, sizeof(dst->ff.tex_stage));
435 if (apply) /* TODO: memset */
436 memcpy(dst->ff.changed.tex_stage,
437 src->ff.changed.tex_stage, sizeof(dst->ff.changed.tex_stage));
438
439 /* Lights. */
440 if (1) {
441 if (dst->ff.num_lights < src->ff.num_lights) {
442 dst->ff.light = REALLOC(dst->ff.light,
443 dst->ff.num_lights * sizeof(D3DLIGHT9),
444 src->ff.num_lights * sizeof(D3DLIGHT9));
445 dst->ff.num_lights = src->ff.num_lights;
446 }
447 memcpy(dst->ff.light,
448 src->ff.light, src->ff.num_lights * sizeof(dst->ff.light[0]));
449
450 memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) );
451 dst->ff.num_lights_active = src->ff.num_lights_active;
452 }
453
454 /* Transforms. */
455 if (1) {
456 if (dst->ff.num_transforms < src->ff.num_transforms) {
457 dst->ff.transform = REALLOC(dst->ff.transform,
458 dst->ff.num_transforms * sizeof(dst->ff.transform[0]),
459 src->ff.num_transforms * sizeof(src->ff.transform[0]));
460 dst->ff.num_transforms = src->ff.num_transforms;
461 }
462 memcpy(dst->ff.transform,
463 src->ff.transform, src->ff.num_transforms * sizeof(D3DMATRIX));
464 if (apply) /* TODO: memset */
465 memcpy(dst->ff.changed.transform,
466 src->ff.changed.transform, sizeof(dst->ff.changed.transform));
467 }
468 }
469
470 /* Capture those bits of current device state that have been changed between
471 * BeginStateBlock and EndStateBlock.
472 */
473 HRESULT NINE_WINAPI
474 NineStateBlock9_Capture( struct NineStateBlock9 *This )
475 {
476 struct nine_state *dst = &This->state;
477 struct nine_state *src = &This->base.device->state;
478 const int MaxStreams = This->base.device->caps.MaxStreams;
479 unsigned s;
480
481 DBG("This=%p\n", This);
482
483 if (This->type == NINESBT_ALL)
484 nine_state_copy_common_all(dst, src, dst, FALSE, NULL, MaxStreams);
485 else
486 nine_state_copy_common(dst, src, dst, FALSE, NULL);
487
488 if (dst->changed.group & NINE_STATE_VDECL)
489 nine_bind(&dst->vdecl, src->vdecl);
490
491 /* Textures */
492 if (dst->changed.texture) {
493 uint32_t m = dst->changed.texture;
494 for (s = 0; m; ++s, m >>= 1)
495 if (m & 1)
496 nine_bind(&dst->texture[s], src->texture[s]);
497 }
498
499 return D3D_OK;
500 }
501
502 /* Set state managed by this StateBlock as current device state. */
503 HRESULT NINE_WINAPI
504 NineStateBlock9_Apply( struct NineStateBlock9 *This )
505 {
506 struct nine_state *dst = &This->base.device->state;
507 struct nine_state *src = &This->state;
508 struct nine_range_pool *pool = &This->base.device->range_pool;
509 const int MaxStreams = This->base.device->caps.MaxStreams;
510 unsigned s;
511
512 DBG("This=%p\n", This);
513
514 if (This->type == NINESBT_ALL)
515 nine_state_copy_common_all(dst, src, src, TRUE, pool, MaxStreams);
516 else
517 nine_state_copy_common(dst, src, src, TRUE, pool);
518
519 if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl)
520 NineDevice9_SetVertexDeclaration(This->base.device, (IDirect3DVertexDeclaration9 *)src->vdecl);
521
522 /* Recomputing it is needed if we changed vs but not vdecl */
523 dst->programmable_vs = dst->vs && !(dst->vdecl && dst->vdecl->position_t);
524
525 /* Textures */
526 if (src->changed.texture) {
527 uint32_t m = src->changed.texture;
528 dst->changed.texture |= m;
529
530 dst->samplers_shadow &= ~m;
531
532 for (s = 0; m; ++s, m >>= 1) {
533 struct NineBaseTexture9 *tex = src->texture[s];
534 if (!(m & 1))
535 continue;
536 if (tex) {
537 tex->bind_count++;
538 if ((tex->managed.dirty | tex->dirty_mip) && LIST_IS_EMPTY(&tex->list))
539 list_add(&tex->list, &This->base.device->update_textures);
540 dst->samplers_shadow |= tex->shadow << s;
541 }
542 if (src->texture[s])
543 src->texture[s]->bind_count--;
544 nine_bind(&dst->texture[s], src->texture[s]);
545 }
546 }
547
548 return D3D_OK;
549 }
550
551 IDirect3DStateBlock9Vtbl NineStateBlock9_vtable = {
552 (void *)NineUnknown_QueryInterface,
553 (void *)NineUnknown_AddRef,
554 (void *)NineUnknown_Release,
555 (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */
556 (void *)NineStateBlock9_Capture,
557 (void *)NineStateBlock9_Apply
558 };
559
560 static const GUID *NineStateBlock9_IIDs[] = {
561 &IID_IDirect3DStateBlock9,
562 &IID_IUnknown,
563 NULL
564 };
565
566 HRESULT
567 NineStateBlock9_new( struct NineDevice9 *pDevice,
568 struct NineStateBlock9 **ppOut,
569 enum nine_stateblock_type type)
570 {
571 NINE_DEVICE_CHILD_NEW(StateBlock9, ppOut, pDevice, type);
572 }