Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/*
2
 * Copyright 2011 Joakim Sindholt 
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
 
28
#define DBG_CHANNEL DBG_STATEBLOCK
29
 
30
/* XXX TODO: handling of lights is broken */
31
 
32
HRESULT
33
NineStateBlock9_ctor( struct NineStateBlock9 *This,
34
                      struct NineUnknownParams *pParams,
35
                      enum nine_stateblock_type type )
36
{
37
    HRESULT hr = NineUnknown_ctor(&This->base, pParams);
38
 
39
    DBG("This=%p pParams=%p type=%d\n", This, pParams, type);
40
 
41
    if (FAILED(hr))
42
        return hr;
43
 
44
    This->type = type;
45
 
46
    This->state.vs_const_f = MALLOC(This->base.device->vs_const_size);
47
    This->state.ps_const_f = MALLOC(This->base.device->ps_const_size);
48
    if (!This->state.vs_const_f || !This->state.ps_const_f)
49
        return E_OUTOFMEMORY;
50
 
51
    return D3D_OK;
52
}
53
 
54
void
55
NineStateBlock9_dtor( struct NineStateBlock9 *This )
56
{
57
    struct nine_state *state = &This->state;
58
    struct nine_range *r;
59
    struct nine_range_pool *pool = &This->base.device->range_pool;
60
 
61
    nine_state_clear(state, FALSE);
62
 
63
    FREE(state->vs_const_f);
64
    FREE(state->ps_const_f);
65
 
66
    FREE(state->ff.light);
67
 
68
    FREE(state->ff.transform);
69
 
70
    if (This->state.changed.ps_const_f) {
71
        for (r = This->state.changed.ps_const_f; r->next; r = r->next);
72
        nine_range_pool_put_chain(pool, This->state.changed.ps_const_f, r);
73
    }
74
    if (This->state.changed.vs_const_f) {
75
        for (r = This->state.changed.vs_const_f; r->next; r = r->next);
76
        nine_range_pool_put_chain(pool, This->state.changed.vs_const_f, r);
77
    }
78
 
79
    NineUnknown_dtor(&This->base);
80
}
81
 
82
/* Copy state marked changed in @mask from @src to @dst.
83
 * If @apply is false, updating dst->changed can be omitted.
84
 * TODO: compare ?
85
 */
86
static void
87
nine_state_copy_common(struct nine_state *dst,
88
                       const struct nine_state *src,
89
                       struct nine_state *mask, /* aliases either src or dst */
90
                       const boolean apply,
91
                       struct nine_range_pool *pool)
92
{
93
    unsigned i, s;
94
 
95
    if (apply)
96
       dst->changed.group |= mask->changed.group;
97
 
98
    if (mask->changed.group & NINE_STATE_VIEWPORT)
99
        dst->viewport = src->viewport;
100
    if (mask->changed.group & NINE_STATE_SCISSOR)
101
        dst->scissor = src->scissor;
102
 
103
    if (mask->changed.group & NINE_STATE_VS)
104
        nine_bind(&dst->vs, src->vs);
105
    if (mask->changed.group & NINE_STATE_PS)
106
        nine_bind(&dst->ps, src->ps);
107
 
108
    /* Vertex constants.
109
     *
110
     * Various possibilities for optimization here, like creating a per-SB
111
     * constant buffer, or memcmp'ing for changes.
112
     * Will do that later depending on what works best for specific apps.
113
     */
114
    if (mask->changed.group & NINE_STATE_VS_CONST) {
115
        struct nine_range *r;
116
        for (r = mask->changed.vs_const_f; r; r = r->next) {
117
            memcpy(&dst->vs_const_f[r->bgn * 4],
118
                   &src->vs_const_f[r->bgn * 4],
119
                   (r->end - r->bgn) * 4 * sizeof(float));
120
            if (apply)
121
                nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end,
122
                                   pool);
123
        }
124
        if (mask->changed.vs_const_i) {
125
            uint16_t m = mask->changed.vs_const_i;
126
            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
127
                if (m & 1)
128
                    memcpy(dst->vs_const_i[i], src->vs_const_i[i], 4 * sizeof(int));
129
            if (apply)
130
                dst->changed.vs_const_i |= mask->changed.vs_const_i;
131
        }
132
        if (mask->changed.vs_const_b) {
133
            uint16_t m = mask->changed.vs_const_b;
134
            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
135
                if (m & 1)
136
                    dst->vs_const_b[i] = src->vs_const_b[i];
137
            if (apply)
138
                dst->changed.vs_const_b |= mask->changed.vs_const_b;
139
        }
140
    }
141
 
142
    /* Pixel constants. */
143
    if (mask->changed.group & NINE_STATE_PS_CONST) {
144
        struct nine_range *r;
145
        for (r = mask->changed.ps_const_f; r; r = r->next) {
146
            memcpy(&dst->ps_const_f[r->bgn * 4],
147
                   &src->ps_const_f[r->bgn * 4],
148
                   (r->end - r->bgn) * 4 * sizeof(float));
149
            if (apply)
150
                nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end,
151
                                   pool);
152
        }
153
        if (mask->changed.ps_const_i) {
154
            uint16_t m = mask->changed.ps_const_i;
155
            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
156
                if (m & 1)
157
                    memcpy(dst->ps_const_i[i], src->ps_const_i[i], 4 * sizeof(int));
158
            if (apply)
159
                dst->changed.ps_const_i |= mask->changed.ps_const_i;
160
        }
161
        if (mask->changed.ps_const_b) {
162
            uint16_t m = mask->changed.ps_const_b;
163
            for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
164
                if (m & 1)
165
                    dst->ps_const_b[i] = src->ps_const_b[i];
166
            if (apply)
167
                dst->changed.ps_const_b |= mask->changed.ps_const_b;
168
        }
169
    }
170
 
171
    /* Render states.
172
     * TODO: Maybe build a list ?
173
     */
174
    for (i = 0; i < Elements(dst->changed.rs); ++i) {
175
        uint32_t m = mask->changed.rs[i];
176
        if (apply)
177
            dst->changed.rs[i] |= m;
178
        while (m) {
179
            const int r = ffs(m) - 1;
180
            m &= ~(1 << r);
181
            dst->rs[i * 32 + r] = src->rs[i * 32 + r];
182
        }
183
    }
184
 
185
 
186
    /* Clip planes. */
187
    if (mask->changed.ucp) {
188
        for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i)
189
            if (mask->changed.ucp & (1 << i))
190
                memcpy(dst->clip.ucp[i],
191
                       src->clip.ucp[i], sizeof(src->clip.ucp[0]));
192
        if (apply)
193
           dst->changed.ucp |= mask->changed.ucp;
194
    }
195
 
196
    /* Sampler state. */
197
    if (mask->changed.group & NINE_STATE_SAMPLER) {
198
        for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
199
            if (mask->changed.sampler[s] == 0x3ffe) {
200
                memcpy(&dst->samp[s], &src->samp[s], sizeof(dst->samp[s]));
201
            } else {
202
                uint32_t m = mask->changed.sampler[s];
203
                while (m) {
204
                    const int i = ffs(m) - 1;
205
                    m &= ~(1 << i);
206
                    dst->samp[s][i] = src->samp[s][i];
207
                }
208
            }
209
            if (apply)
210
                dst->changed.sampler[s] |= mask->changed.sampler[s];
211
        }
212
    }
213
 
214
    /* Index buffer. */
215
    if (mask->changed.group & NINE_STATE_IDXBUF)
216
        nine_bind(&dst->idxbuf, src->idxbuf);
217
 
218
    /* Vertex streams. */
219
    if (mask->changed.vtxbuf | mask->changed.stream_freq) {
220
        uint32_t m = mask->changed.vtxbuf | mask->changed.stream_freq;
221
        for (i = 0; m; ++i, m >>= 1) {
222
            if (mask->changed.vtxbuf & (1 << i)) {
223
                nine_bind(&dst->stream[i], src->stream[i]);
224
                if (src->stream[i]) {
225
                    dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset;
226
                    dst->vtxbuf[i].buffer = src->vtxbuf[i].buffer;
227
                    dst->vtxbuf[i].stride = src->vtxbuf[i].stride;
228
                }
229
            }
230
            if (mask->changed.stream_freq & (1 << i))
231
                dst->stream_freq[i] = src->stream_freq[i];
232
        }
233
        dst->stream_instancedata_mask &= ~mask->changed.stream_freq;
234
        dst->stream_instancedata_mask |=
235
            src->stream_instancedata_mask & mask->changed.stream_freq;
236
        if (apply) {
237
            dst->changed.vtxbuf |= mask->changed.vtxbuf;
238
            dst->changed.stream_freq |= mask->changed.stream_freq;
239
        }
240
    }
241
 
242
    if (!(mask->changed.group & NINE_STATE_FF))
243
        return;
244
    WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
245
 
246
    /* Fixed function state. */
247
    if (apply)
248
        dst->ff.changed.group |= src->ff.changed.group;
249
 
250
    if (mask->changed.group & NINE_STATE_FF_MATERIAL)
251
        dst->ff.material = src->ff.material;
252
 
253
    if (mask->changed.group & NINE_STATE_FF_PSSTAGES) {
254
        for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
255
            for (i = 0; i < NINED3DTSS_COUNT; ++i)
256
                if (mask->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32)))
257
                    dst->ff.tex_stage[s][i] = src->ff.tex_stage[s][i];
258
            if (apply) {
259
                /* TODO: it's 32 exactly, just offset by 1 as 0 is unused */
260
                dst->ff.changed.tex_stage[s][0] |=
261
                    mask->ff.changed.tex_stage[s][0];
262
                dst->ff.changed.tex_stage[s][1] |=
263
                    mask->ff.changed.tex_stage[s][1];
264
            }
265
        }
266
    }
267
    if (mask->changed.group & NINE_STATE_FF_LIGHTING) {
268
        if (dst->ff.num_lights < mask->ff.num_lights) {
269
            dst->ff.light = REALLOC(dst->ff.light,
270
                                    dst->ff.num_lights * sizeof(D3DLIGHT9),
271
                                    mask->ff.num_lights * sizeof(D3DLIGHT9));
272
            dst->ff.num_lights = mask->ff.num_lights;
273
        }
274
        for (i = 0; i < mask->ff.num_lights; ++i)
275
            if (mask->ff.light[i].Type != NINED3DLIGHT_INVALID)
276
                dst->ff.light[i] = src->ff.light[i];
277
 
278
        memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) );
279
        dst->ff.num_lights_active = src->ff.num_lights_active;
280
    }
281
    if (mask->changed.group & NINE_STATE_FF_VSTRANSF) {
282
        for (i = 0; i < Elements(mask->ff.changed.transform); ++i) {
283
            if (!mask->ff.changed.transform[i])
284
                continue;
285
            for (s = i * 32; s < (i * 32 + 32); ++s) {
286
                if (!(mask->ff.changed.transform[i] & (1 << (s % 32))))
287
                    continue;
288
                *nine_state_access_transform(dst, s, TRUE) =
289
                    *nine_state_access_transform( /* const because !alloc */
290
                        (struct nine_state *)src, s, FALSE);
291
            }
292
            if (apply)
293
                dst->ff.changed.transform[i] |= mask->ff.changed.transform[i];
294
        }
295
    }
296
}
297
 
298
static void
299
nine_state_copy_common_all(struct nine_state *dst,
300
                           const struct nine_state *src,
301
                           struct nine_state *help,
302
                           const boolean apply,
303
                           struct nine_range_pool *pool,
304
                           const int MaxStreams)
305
{
306
    unsigned i;
307
 
308
    if (apply)
309
       dst->changed.group |= src->changed.group;
310
 
311
    dst->viewport = src->viewport;
312
    dst->scissor = src->scissor;
313
 
314
    nine_bind(&dst->vs, src->vs);
315
    nine_bind(&dst->ps, src->ps);
316
 
317
    /* Vertex constants.
318
     *
319
     * Various possibilities for optimization here, like creating a per-SB
320
     * constant buffer, or memcmp'ing for changes.
321
     * Will do that later depending on what works best for specific apps.
322
     */
323
    if (1) {
324
        struct nine_range *r = help->changed.vs_const_f;
325
        memcpy(&dst->vs_const_f[0],
326
               &src->vs_const_f[0], (r->end - r->bgn) * 4 * sizeof(float));
327
        if (apply)
328
            nine_ranges_insert(&dst->changed.vs_const_f, r->bgn, r->end, pool);
329
 
330
        memcpy(dst->vs_const_i, src->vs_const_i, sizeof(dst->vs_const_i));
331
        memcpy(dst->vs_const_b, src->vs_const_b, sizeof(dst->vs_const_b));
332
        if (apply) {
333
            dst->changed.vs_const_i |= src->changed.vs_const_i;
334
            dst->changed.vs_const_b |= src->changed.vs_const_b;
335
        }
336
    }
337
 
338
    /* Pixel constants. */
339
    if (1) {
340
        struct nine_range *r = help->changed.ps_const_f;
341
        memcpy(&dst->ps_const_f[0],
342
               &src->ps_const_f[0], (r->end - r->bgn) * 4 * sizeof(float));
343
        if (apply)
344
            nine_ranges_insert(&dst->changed.ps_const_f, r->bgn, r->end, pool);
345
 
346
        memcpy(dst->ps_const_i, src->ps_const_i, sizeof(dst->ps_const_i));
347
        memcpy(dst->ps_const_b, src->ps_const_b, sizeof(dst->ps_const_b));
348
        if (apply) {
349
            dst->changed.ps_const_i |= src->changed.ps_const_i;
350
            dst->changed.ps_const_b |= src->changed.ps_const_b;
351
        }
352
    }
353
 
354
    /* Render states. */
355
    memcpy(dst->rs, src->rs, sizeof(dst->rs));
356
    if (apply)
357
        memcpy(dst->changed.rs, src->changed.rs, sizeof(dst->changed.rs));
358
 
359
 
360
    /* Clip planes. */
361
    memcpy(&dst->clip, &src->clip, sizeof(dst->clip));
362
    if (apply)
363
        dst->changed.ucp = src->changed.ucp;
364
 
365
    /* Sampler state. */
366
    memcpy(dst->samp, src->samp, sizeof(dst->samp));
367
    if (apply)
368
        memcpy(dst->changed.sampler,
369
               src->changed.sampler, sizeof(dst->changed.sampler));
370
 
371
    /* Index buffer. */
372
    nine_bind(&dst->idxbuf, src->idxbuf);
373
 
374
    /* Vertex streams. */
375
    if (1) {
376
        for (i = 0; i < Elements(dst->stream); ++i) {
377
            nine_bind(&dst->stream[i], src->stream[i]);
378
            if (src->stream[i]) {
379
                dst->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset;
380
                dst->vtxbuf[i].buffer = src->vtxbuf[i].buffer;
381
                dst->vtxbuf[i].stride = src->vtxbuf[i].stride;
382
            }
383
            dst->stream_freq[i] = src->stream_freq[i];
384
        }
385
        dst->stream_instancedata_mask = src->stream_instancedata_mask;
386
        if (apply) {
387
            dst->changed.vtxbuf = (1ULL << MaxStreams) - 1;
388
            dst->changed.stream_freq = (1ULL << MaxStreams) - 1;
389
        }
390
    }
391
 
392
    /* keep this check in case we want to disable FF */
393
    if (!(help->changed.group & NINE_STATE_FF))
394
        return;
395
    WARN_ONCE("Fixed function state not handled properly by StateBlocks.\n");
396
 
397
    /* Fixed function state. */
398
    if (apply)
399
        dst->ff.changed.group = src->ff.changed.group;
400
 
401
    dst->ff.material = src->ff.material;
402
 
403
    memcpy(dst->ff.tex_stage, src->ff.tex_stage, sizeof(dst->ff.tex_stage));
404
    if (apply) /* TODO: memset */
405
        memcpy(dst->ff.changed.tex_stage,
406
               src->ff.changed.tex_stage, sizeof(dst->ff.changed.tex_stage));
407
 
408
    /* Lights. */
409
    if (1) {
410
        if (dst->ff.num_lights < src->ff.num_lights) {
411
            dst->ff.light = REALLOC(dst->ff.light,
412
                                    dst->ff.num_lights * sizeof(D3DLIGHT9),
413
                                    src->ff.num_lights * sizeof(D3DLIGHT9));
414
            dst->ff.num_lights = src->ff.num_lights;
415
        }
416
        memcpy(dst->ff.light,
417
               src->ff.light, src->ff.num_lights * sizeof(dst->ff.light[0]));
418
 
419
        memcpy(dst->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) );
420
        dst->ff.num_lights_active = src->ff.num_lights_active;
421
    }
422
 
423
    /* Transforms. */
424
    if (1) {
425
        if (dst->ff.num_transforms < src->ff.num_transforms) {
426
            dst->ff.transform = REALLOC(dst->ff.transform,
427
                dst->ff.num_transforms * sizeof(dst->ff.transform[0]),
428
                src->ff.num_transforms * sizeof(src->ff.transform[0]));
429
            dst->ff.num_transforms = src->ff.num_transforms;
430
        }
431
        memcpy(dst->ff.transform,
432
               src->ff.transform, src->ff.num_transforms * sizeof(D3DMATRIX));
433
        if (apply) /* TODO: memset */
434
            memcpy(dst->ff.changed.transform,
435
                   src->ff.changed.transform, sizeof(dst->ff.changed.transform));
436
    }
437
}
438
 
439
/* Capture those bits of current device state that have been changed between
440
 * BeginStateBlock and EndStateBlock.
441
 */
442
HRESULT WINAPI
443
NineStateBlock9_Capture( struct NineStateBlock9 *This )
444
{
445
    struct nine_state *dst = &This->state;
446
    struct nine_state *src = &This->base.device->state;
447
    const int MaxStreams = This->base.device->caps.MaxStreams;
448
    unsigned s;
449
 
450
    DBG("This=%p\n", This);
451
 
452
    if (This->type == NINESBT_ALL)
453
        nine_state_copy_common_all(dst, src, dst, FALSE, NULL, MaxStreams);
454
    else
455
        nine_state_copy_common(dst, src, dst, FALSE, NULL);
456
 
457
    if (dst->changed.group & NINE_STATE_VDECL)
458
        nine_bind(&dst->vdecl, src->vdecl);
459
 
460
    /* Textures */
461
    if (dst->changed.texture) {
462
        uint32_t m = dst->changed.texture;
463
        for (s = 0; m; ++s, m >>= 1)
464
            if (m & 1)
465
                nine_bind(&dst->texture[s], src->texture[s]);
466
    }
467
 
468
    return D3D_OK;
469
}
470
 
471
/* Set state managed by this StateBlock as current device state. */
472
HRESULT WINAPI
473
NineStateBlock9_Apply( struct NineStateBlock9 *This )
474
{
475
    struct nine_state *dst = &This->base.device->state;
476
    struct nine_state *src = &This->state;
477
    struct nine_range_pool *pool = &This->base.device->range_pool;
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, src, TRUE, pool, MaxStreams);
485
    else
486
        nine_state_copy_common(dst, src, src, TRUE, pool);
487
 
488
    if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl)
489
        nine_bind(&dst->vdecl, src->vdecl);
490
 
491
    /* Textures */
492
    if (src->changed.texture) {
493
        uint32_t m = src->changed.texture;
494
        dst->changed.texture |= m;
495
 
496
        dst->samplers_shadow &= ~m;
497
 
498
        for (s = 0; m; ++s, m >>= 1) {
499
            struct NineBaseTexture9 *tex = src->texture[s];
500
            if (!(m & 1))
501
                continue;
502
            if (tex) {
503
                tex->bind_count++;
504
                if ((tex->managed.dirty | tex->dirty_mip) && LIST_IS_EMPTY(&tex->list))
505
                    list_add(&tex->list, &This->base.device->update_textures);
506
                dst->samplers_shadow |= tex->shadow << s;
507
            }
508
            if (src->texture[s])
509
                src->texture[s]->bind_count--;
510
            nine_bind(&dst->texture[s], src->texture[s]);
511
        }
512
    }
513
 
514
    return D3D_OK;
515
}
516
 
517
IDirect3DStateBlock9Vtbl NineStateBlock9_vtable = {
518
    (void *)NineUnknown_QueryInterface,
519
    (void *)NineUnknown_AddRef,
520
    (void *)NineUnknown_Release,
521
    (void *)NineUnknown_GetDevice, /* actually part of StateBlock9 iface */
522
    (void *)NineStateBlock9_Capture,
523
    (void *)NineStateBlock9_Apply
524
};
525
 
526
static const GUID *NineStateBlock9_IIDs[] = {
527
    &IID_IDirect3DStateBlock9,
528
    &IID_IUnknown,
529
    NULL
530
};
531
 
532
HRESULT
533
NineStateBlock9_new( struct NineDevice9 *pDevice,
534
                     struct NineStateBlock9 **ppOut,
535
                     enum nine_stateblock_type type)
536
{
537
    NINE_DEVICE_CHILD_NEW(StateBlock9, ppOut, pDevice, type);
538
}