+ context->changed.vtxbuf |= 1 << StreamNumber;
+}
+
+void
+nine_context_set_stream_source(struct NineDevice9 *device,
+ UINT StreamNumber,
+ struct NineVertexBuffer9 *pVBuf9,
+ UINT OffsetInBytes,
+ UINT Stride)
+{
+ struct pipe_resource *res = NULL;
+ unsigned offset = 0;
+
+ if (pVBuf9)
+ res = NineVertexBuffer9_GetResource(pVBuf9, &offset);
+ /* in the future when there is internal offset, add it
+ * to OffsetInBytes */
+
+ nine_context_set_stream_source_apply(device, StreamNumber,
+ res, offset + OffsetInBytes,
+ Stride);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_stream_source_freq,
+ ARG_VAL(UINT, StreamNumber),
+ ARG_VAL(UINT, Setting))
+{
+ struct nine_context *context = &device->context;
+
+ context->stream_freq[StreamNumber] = Setting;
+
+ if (Setting & D3DSTREAMSOURCE_INSTANCEDATA)
+ context->stream_instancedata_mask |= 1 << StreamNumber;
+ else
+ context->stream_instancedata_mask &= ~(1 << StreamNumber);
+
+ if (StreamNumber != 0)
+ context->changed.group |= NINE_STATE_STREAMFREQ;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_indices_apply,
+ ARG_BIND_RES(struct pipe_resource, res),
+ ARG_VAL(UINT, IndexSize),
+ ARG_VAL(UINT, OffsetInBytes))
+{
+ struct nine_context *context = &device->context;
+
+ context->idxbuf.index_size = IndexSize;
+ context->idxbuf.offset = OffsetInBytes;
+ pipe_resource_reference(&context->idxbuf.buffer, res);
+ context->idxbuf.user_buffer = NULL;
+
+ context->changed.group |= NINE_STATE_IDXBUF;
+}
+
+void
+nine_context_set_indices(struct NineDevice9 *device,
+ struct NineIndexBuffer9 *idxbuf)
+{
+ const struct pipe_index_buffer *pipe_idxbuf;
+ struct pipe_resource *res = NULL;
+ UINT IndexSize = 0;
+ UINT OffsetInBytes = 0;
+
+ if (idxbuf) {
+ pipe_idxbuf = NineIndexBuffer9_GetBuffer(idxbuf);
+ IndexSize = pipe_idxbuf->index_size;
+ res = pipe_idxbuf->buffer;
+ OffsetInBytes = pipe_idxbuf->offset;
+ }
+
+ nine_context_set_indices_apply(device, res, IndexSize, OffsetInBytes);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_vertex_declaration,
+ ARG_BIND_REF(struct NineVertexDeclaration9, vdecl))
+{
+ struct nine_context *context = &device->context;
+ BOOL was_programmable_vs = context->programmable_vs;
+
+ nine_bind(&context->vdecl, vdecl);
+
+ context->programmable_vs = context->vs && !(context->vdecl && context->vdecl->position_t);
+ if (was_programmable_vs != context->programmable_vs) {
+ context->commit |= NINE_STATE_COMMIT_CONST_VS;
+ context->changed.group |= NINE_STATE_VS;
+ }
+
+ context->changed.group |= NINE_STATE_VDECL;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader,
+ ARG_BIND_REF(struct NineVertexShader9, pShader))
+{
+ struct nine_context *context = &device->context;
+ BOOL was_programmable_vs = context->programmable_vs;
+
+ nine_bind(&context->vs, pShader);
+
+ context->programmable_vs = context->vs && !(context->vdecl && context->vdecl->position_t);
+
+ /* ff -> non-ff: commit back non-ff constants */
+ if (!was_programmable_vs && context->programmable_vs)
+ context->commit |= NINE_STATE_COMMIT_CONST_VS;
+
+ context->changed.group |= NINE_STATE_VS;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader_constant_f,
+ ARG_VAL(UINT, StartRegister),
+ ARG_MEM(float, pConstantData),
+ ARG_MEM_SIZE(unsigned, pConstantData_size),
+ ARG_VAL(UINT, Vector4fCount))
+{
+ struct nine_context *context = &device->context;
+ float *vs_const_f = device->may_swvp ? context->vs_const_f_swvp : context->vs_const_f;
+
+ memcpy(&vs_const_f[StartRegister * 4],
+ pConstantData,
+ pConstantData_size);
+
+ if (device->may_swvp) {
+ Vector4fCount = MIN2(StartRegister + Vector4fCount, NINE_MAX_CONST_F) - StartRegister;
+ if (StartRegister < NINE_MAX_CONST_F)
+ memcpy(&context->vs_const_f[StartRegister * 4],
+ pConstantData,
+ Vector4fCount * 4 * sizeof(context->vs_const_f[0]));
+ }
+
+ context->changed.vs_const_f = TRUE;
+ context->changed.group |= NINE_STATE_VS_CONST;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader_constant_i,
+ ARG_VAL(UINT, StartRegister),
+ ARG_MEM(int, pConstantData),
+ ARG_MEM_SIZE(unsigned, pConstantData_size),
+ ARG_VAL(UINT, Vector4iCount))
+{
+ struct nine_context *context = &device->context;
+ int i;
+
+ if (device->driver_caps.vs_integer) {
+ memcpy(&context->vs_const_i[4 * StartRegister],
+ pConstantData,
+ pConstantData_size);
+ } else {
+ for (i = 0; i < Vector4iCount; i++) {
+ context->vs_const_i[4 * (StartRegister + i)] = fui((float)(pConstantData[4 * i]));
+ context->vs_const_i[4 * (StartRegister + i) + 1] = fui((float)(pConstantData[4 * i + 1]));
+ context->vs_const_i[4 * (StartRegister + i) + 2] = fui((float)(pConstantData[4 * i + 2]));
+ context->vs_const_i[4 * (StartRegister + i) + 3] = fui((float)(pConstantData[4 * i + 3]));
+ }
+ }
+
+ context->changed.vs_const_i = TRUE;
+ context->changed.group |= NINE_STATE_VS_CONST;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_vertex_shader_constant_b,
+ ARG_VAL(UINT, StartRegister),
+ ARG_MEM(BOOL, pConstantData),
+ ARG_MEM_SIZE(unsigned, pConstantData_size),
+ ARG_VAL(UINT, BoolCount))
+{
+ struct nine_context *context = &device->context;
+ int i;
+ uint32_t bool_true = device->driver_caps.vs_integer ? 0xFFFFFFFF : fui(1.0f);
+
+ (void) pConstantData_size;
+
+ for (i = 0; i < BoolCount; i++)
+ context->vs_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0;
+
+ context->changed.vs_const_b = TRUE;
+ context->changed.group |= NINE_STATE_VS_CONST;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader,
+ ARG_BIND_REF(struct NinePixelShader9, ps))
+{
+ struct nine_context *context = &device->context;
+ unsigned old_mask = context->ps ? context->ps->rt_mask : 1;
+ unsigned mask;
+
+ /* ff -> non-ff: commit back non-ff constants */
+ if (!context->ps && ps)
+ context->commit |= NINE_STATE_COMMIT_CONST_PS;
+
+ nine_bind(&context->ps, ps);
+
+ context->changed.group |= NINE_STATE_PS;
+
+ mask = context->ps ? context->ps->rt_mask : 1;
+ /* We need to update cbufs if the pixel shader would
+ * write to different render targets */
+ if (mask != old_mask)
+ context->changed.group |= NINE_STATE_FB;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_f,
+ ARG_VAL(UINT, StartRegister),
+ ARG_MEM(float, pConstantData),
+ ARG_MEM_SIZE(unsigned, pConstantData_size),
+ ARG_VAL(UINT, Vector4fCount))
+{
+ struct nine_context *context = &device->context;
+
+ memcpy(&context->ps_const_f[StartRegister * 4],
+ pConstantData,
+ pConstantData_size);
+
+ context->changed.ps_const_f = TRUE;
+ context->changed.group |= NINE_STATE_PS_CONST;
+}
+
+/* For stateblocks */
+CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_i_transformed,
+ ARG_VAL(UINT, StartRegister),
+ ARG_MEM(int, pConstantData),
+ ARG_MEM_SIZE(unsigned, pConstantData_size),
+ ARG_VAL(UINT, Vector4iCount))
+{
+ struct nine_context *context = &device->context;
+
+ memcpy(&context->ps_const_i[StartRegister][0],
+ pConstantData,
+ Vector4iCount * sizeof(context->ps_const_i[0]));
+
+ context->changed.ps_const_i = TRUE;
+ context->changed.group |= NINE_STATE_PS_CONST;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_i,
+ ARG_VAL(UINT, StartRegister),
+ ARG_MEM(int, pConstantData),
+ ARG_MEM_SIZE(unsigned, pConstantData_size),
+ ARG_VAL(UINT, Vector4iCount))
+{
+ struct nine_context *context = &device->context;
+ int i;
+
+ if (device->driver_caps.ps_integer) {
+ memcpy(&context->ps_const_i[StartRegister][0],
+ pConstantData,
+ pConstantData_size);
+ } else {
+ for (i = 0; i < Vector4iCount; i++) {
+ context->ps_const_i[StartRegister+i][0] = fui((float)(pConstantData[4*i]));
+ context->ps_const_i[StartRegister+i][1] = fui((float)(pConstantData[4*i+1]));
+ context->ps_const_i[StartRegister+i][2] = fui((float)(pConstantData[4*i+2]));
+ context->ps_const_i[StartRegister+i][3] = fui((float)(pConstantData[4*i+3]));
+ }
+ }
+ context->changed.ps_const_i = TRUE;
+ context->changed.group |= NINE_STATE_PS_CONST;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_pixel_shader_constant_b,
+ ARG_VAL(UINT, StartRegister),
+ ARG_MEM(BOOL, pConstantData),
+ ARG_MEM_SIZE(unsigned, pConstantData_size),
+ ARG_VAL(UINT, BoolCount))
+{
+ struct nine_context *context = &device->context;
+ int i;
+ uint32_t bool_true = device->driver_caps.ps_integer ? 0xFFFFFFFF : fui(1.0f);
+
+ (void) pConstantData_size;
+
+ for (i = 0; i < BoolCount; i++)
+ context->ps_const_b[StartRegister + i] = pConstantData[i] ? bool_true : 0;
+
+ context->changed.ps_const_b = TRUE;
+ context->changed.group |= NINE_STATE_PS_CONST;
+}
+
+/* XXX: use resource, as resource might change */
+CSMT_ITEM_NO_WAIT(nine_context_set_render_target,
+ ARG_VAL(DWORD, RenderTargetIndex),
+ ARG_BIND_REF(struct NineSurface9, rt))
+{
+ struct nine_context *context = &device->context;
+ const unsigned i = RenderTargetIndex;
+
+ if (i == 0) {
+ context->viewport.X = 0;
+ context->viewport.Y = 0;
+ context->viewport.Width = rt->desc.Width;
+ context->viewport.Height = rt->desc.Height;
+ context->viewport.MinZ = 0.0f;
+ context->viewport.MaxZ = 1.0f;
+
+ context->scissor.minx = 0;
+ context->scissor.miny = 0;
+ context->scissor.maxx = rt->desc.Width;
+ context->scissor.maxy = rt->desc.Height;
+
+ context->changed.group |= NINE_STATE_VIEWPORT | NINE_STATE_SCISSOR | NINE_STATE_MULTISAMPLE;
+
+ if (context->rt[0] &&
+ (context->rt[0]->desc.MultiSampleType <= D3DMULTISAMPLE_NONMASKABLE) !=
+ (rt->desc.MultiSampleType <= D3DMULTISAMPLE_NONMASKABLE))
+ context->changed.group |= NINE_STATE_SAMPLE_MASK;
+ }
+
+ if (context->rt[i] != rt) {
+ nine_bind(&context->rt[i], rt);
+ context->changed.group |= NINE_STATE_FB;
+ }
+}
+
+/* XXX: use resource instead of ds, as resource might change */
+CSMT_ITEM_NO_WAIT(nine_context_set_depth_stencil,
+ ARG_BIND_REF(struct NineSurface9, ds))
+{
+ struct nine_context *context = &device->context;
+
+ nine_bind(&context->ds, ds);
+ context->changed.group |= NINE_STATE_FB;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_viewport,
+ ARG_COPY_REF(D3DVIEWPORT9, viewport))
+{
+ struct nine_context *context = &device->context;
+
+ context->viewport = *viewport;
+ context->changed.group |= NINE_STATE_VIEWPORT;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_scissor,
+ ARG_COPY_REF(struct pipe_scissor_state, scissor))
+{
+ struct nine_context *context = &device->context;
+
+ context->scissor = *scissor;
+ context->changed.group |= NINE_STATE_SCISSOR;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_transform,
+ ARG_VAL(D3DTRANSFORMSTATETYPE, State),
+ ARG_COPY_REF(D3DMATRIX, pMatrix))
+{
+ struct nine_context *context = &device->context;
+ D3DMATRIX *M = nine_state_access_transform(&context->ff, State, TRUE);
+
+ *M = *pMatrix;
+ context->ff.changed.transform[State / 32] |= 1 << (State % 32);
+ context->changed.group |= NINE_STATE_FF;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_material,
+ ARG_COPY_REF(D3DMATERIAL9, pMaterial))
+{
+ struct nine_context *context = &device->context;
+
+ context->ff.material = *pMaterial;
+ context->changed.group |= NINE_STATE_FF_MATERIAL;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_light,
+ ARG_VAL(DWORD, Index),
+ ARG_COPY_REF(D3DLIGHT9, pLight))
+{
+ struct nine_context *context = &device->context;
+
+ (void)nine_state_set_light(&context->ff, Index, pLight);
+ context->changed.group |= NINE_STATE_FF_LIGHTING;
+}
+
+
+/* For stateblocks */
+static void
+nine_context_light_enable_stateblock(struct NineDevice9 *device,
+ const uint16_t active_light[NINE_MAX_LIGHTS_ACTIVE], /* TODO: use pointer that convey size for csmt */
+ unsigned int num_lights_active)
+{
+ struct nine_context *context = &device->context;
+
+ /* TODO: Use CSMT_* to avoid calling nine_csmt_process */
+ nine_csmt_process(device);
+ memcpy(context->ff.active_light, active_light, NINE_MAX_LIGHTS_ACTIVE * sizeof(context->ff.active_light[0]));
+ context->ff.num_lights_active = num_lights_active;
+ context->changed.group |= NINE_STATE_FF_LIGHTING;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_light_enable,
+ ARG_VAL(DWORD, Index),
+ ARG_VAL(BOOL, Enable))
+{
+ struct nine_context *context = &device->context;
+
+ nine_state_light_enable(&context->ff, &context->changed.group, Index, Enable);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_texture_stage_state,
+ ARG_VAL(DWORD, Stage),
+ ARG_VAL(D3DTEXTURESTAGESTATETYPE, Type),
+ ARG_VAL(DWORD, Value))
+{
+ struct nine_context *context = &device->context;
+ int bumpmap_index = -1;
+
+ context->ff.tex_stage[Stage][Type] = Value;
+ switch (Type) {
+ case D3DTSS_BUMPENVMAT00:
+ bumpmap_index = 4 * Stage;
+ break;
+ case D3DTSS_BUMPENVMAT01:
+ bumpmap_index = 4 * Stage + 1;
+ break;
+ case D3DTSS_BUMPENVMAT10:
+ bumpmap_index = 4 * Stage + 2;
+ break;
+ case D3DTSS_BUMPENVMAT11:
+ bumpmap_index = 4 * Stage + 3;
+ break;
+ case D3DTSS_BUMPENVLSCALE:
+ bumpmap_index = 4 * 8 + 2 * Stage;
+ break;
+ case D3DTSS_BUMPENVLOFFSET:
+ bumpmap_index = 4 * 8 + 2 * Stage + 1;
+ break;
+ case D3DTSS_TEXTURETRANSFORMFLAGS:
+ context->changed.group |= NINE_STATE_PS1X_SHADER;
+ break;
+ default:
+ break;
+ }
+
+ if (bumpmap_index >= 0) {
+ context->bumpmap_vars[bumpmap_index] = Value;
+ context->changed.group |= NINE_STATE_PS_CONST;
+ }
+
+ context->changed.group |= NINE_STATE_FF_PSSTAGES;
+ context->ff.changed.tex_stage[Stage][Type / 32] |= 1 << (Type % 32);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_clip_plane,
+ ARG_VAL(DWORD, Index),
+ ARG_COPY_REF(struct nine_clipplane, pPlane))
+{
+ struct nine_context *context = &device->context;
+
+ memcpy(&context->clip.ucp[Index][0], pPlane, sizeof(context->clip.ucp[0]));
+ context->changed.ucp = TRUE;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_set_swvp,
+ ARG_VAL(boolean, swvp))
+{
+ struct nine_context *context = &device->context;
+
+ context->swvp = swvp;
+ context->changed.group |= NINE_STATE_SWVP;
+}
+
+#if 0
+
+void
+nine_context_apply_stateblock(struct NineDevice9 *device,
+ const struct nine_state *src)
+{
+ struct nine_context *context = &device->context;
+ int i;
+
+ context->changed.group |= src->changed.group;
+
+ for (i = 0; i < ARRAY_SIZE(src->changed.rs); ++i) {
+ uint32_t m = src->changed.rs[i];
+ while (m) {
+ const int r = ffs(m) - 1;
+ m &= ~(1 << r);
+ context->rs[i * 32 + r] = nine_fix_render_state_value(i * 32 + r, src->rs_advertised[i * 32 + r]);
+ }
+ }
+
+ /* Textures */
+ if (src->changed.texture) {
+ uint32_t m = src->changed.texture;
+ unsigned s;
+
+ for (s = 0; m; ++s, m >>= 1) {
+ struct NineBaseTexture9 *tex = src->texture[s];
+ if (!(m & 1))
+ continue;
+ nine_context_set_texture(device, s, tex);
+ }
+ }
+
+ /* Sampler state */
+ if (src->changed.group & NINE_STATE_SAMPLER) {
+ unsigned s;
+
+ for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
+ uint32_t m = src->changed.sampler[s];
+ while (m) {
+ const int i = ffs(m) - 1;
+ m &= ~(1 << i);
+ if (nine_check_sampler_state_value(i, src->samp_advertised[s][i]))
+ context->samp[s][i] = src->samp_advertised[s][i];
+ }
+ context->changed.sampler[s] |= src->changed.sampler[s];
+ }
+ }
+
+ /* Vertex buffers */
+ if (src->changed.vtxbuf | src->changed.stream_freq) {
+ uint32_t m = src->changed.vtxbuf | src->changed.stream_freq;
+ for (i = 0; m; ++i, m >>= 1) {
+ if (src->changed.vtxbuf & (1 << i)) {
+ if (src->stream[i]) {
+ unsigned offset = 0;
+ pipe_resource_reference(&context->vtxbuf[i].buffer,
+ src->stream[i] ? NineVertexBuffer9_GetResource(src->stream[i], &offset) : NULL);
+ context->vtxbuf[i].buffer_offset = src->vtxbuf[i].buffer_offset + offset;
+ context->vtxbuf[i].stride = src->vtxbuf[i].stride;
+ }
+ }
+ if (src->changed.stream_freq & (1 << i)) {
+ context->stream_freq[i] = src->stream_freq[i];
+ if (src->stream_freq[i] & D3DSTREAMSOURCE_INSTANCEDATA)
+ context->stream_instancedata_mask |= 1 << i;
+ else
+ context->stream_instancedata_mask &= ~(1 << i);
+ }
+ }
+ context->changed.vtxbuf |= src->changed.vtxbuf;
+ }
+
+ /* Index buffer */
+ if (src->changed.group & NINE_STATE_IDXBUF)
+ nine_context_set_indices(device, src->idxbuf);
+
+ /* Vertex declaration */
+ if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl)
+ nine_context_set_vertex_declaration(device, src->vdecl);
+
+ /* Vertex shader */
+ if (src->changed.group & NINE_STATE_VS)
+ nine_bind(&context->vs, src->vs);
+
+ context->programmable_vs = context->vs && !(context->vdecl && context->vdecl->position_t);
+
+ /* Pixel shader */
+ if (src->changed.group & NINE_STATE_PS)
+ nine_bind(&context->ps, src->ps);
+
+ /* Vertex constants */
+ if (src->changed.group & NINE_STATE_VS_CONST) {
+ struct nine_range *r;
+ if (device->may_swvp) {
+ for (r = src->changed.vs_const_f; r; r = r->next) {
+ int bgn = r->bgn;
+ int end = r->end;
+ memcpy(&context->vs_const_f_swvp[bgn * 4],
+ &src->vs_const_f[bgn * 4],
+ (end - bgn) * 4 * sizeof(float));
+ if (bgn < device->max_vs_const_f) {
+ end = MIN2(end, device->max_vs_const_f);
+ memcpy(&context->vs_const_f[bgn * 4],
+ &src->vs_const_f[bgn * 4],
+ (end - bgn) * 4 * sizeof(float));
+ }
+ }
+ } else {
+ for (r = src->changed.vs_const_f; r; r = r->next) {
+ memcpy(&context->vs_const_f[r->bgn * 4],
+ &src->vs_const_f[r->bgn * 4],
+ (r->end - r->bgn) * 4 * sizeof(float));
+ }
+ }
+ for (r = src->changed.vs_const_i; r; r = r->next) {
+ memcpy(&context->vs_const_i[r->bgn * 4],
+ &src->vs_const_i[r->bgn * 4],
+ (r->end - r->bgn) * 4 * sizeof(int));
+ }
+ for (r = src->changed.vs_const_b; r; r = r->next) {
+ memcpy(&context->vs_const_b[r->bgn],
+ &src->vs_const_b[r->bgn],
+ (r->end - r->bgn) * sizeof(int));
+ }
+ context->changed.vs_const_f = !!src->changed.vs_const_f;
+ context->changed.vs_const_i = !!src->changed.vs_const_i;
+ context->changed.vs_const_b = !!src->changed.vs_const_b;
+ }
+
+ /* Pixel constants */
+ if (src->changed.group & NINE_STATE_PS_CONST) {
+ struct nine_range *r;
+ for (r = src->changed.ps_const_f; r; r = r->next) {
+ memcpy(&context->ps_const_f[r->bgn * 4],
+ &src->ps_const_f[r->bgn * 4],
+ (r->end - r->bgn) * 4 * sizeof(float));
+ }
+ if (src->changed.ps_const_i) {
+ uint16_t m = src->changed.ps_const_i;
+ for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+ if (m & 1)
+ memcpy(context->ps_const_i[i], src->ps_const_i[i], 4 * sizeof(int));
+ }
+ if (src->changed.ps_const_b) {
+ uint16_t m = src->changed.ps_const_b;
+ for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+ if (m & 1)
+ context->ps_const_b[i] = src->ps_const_b[i];
+ }
+ context->changed.ps_const_f = !!src->changed.ps_const_f;
+ context->changed.ps_const_i = !!src->changed.ps_const_i;
+ context->changed.ps_const_b = !!src->changed.ps_const_b;
+ }
+
+ /* Viewport */
+ if (src->changed.group & NINE_STATE_VIEWPORT)
+ context->viewport = src->viewport;
+
+ /* Scissor */
+ if (src->changed.group & NINE_STATE_SCISSOR)
+ context->scissor = src->scissor;
+
+ /* User Clip Planes */
+ if (src->changed.ucp) {
+ for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i)
+ if (src->changed.ucp & (1 << i))
+ memcpy(context->clip.ucp[i],
+ src->clip.ucp[i], sizeof(src->clip.ucp[0]));
+ context->changed.ucp = TRUE;
+ }
+
+ if (!(src->changed.group & NINE_STATE_FF))
+ return;
+
+ /* Fixed function state. */
+
+ if (src->changed.group & NINE_STATE_FF_MATERIAL)
+ context->ff.material = src->ff.material;
+
+ if (src->changed.group & NINE_STATE_FF_PSSTAGES) {
+ unsigned s;
+ for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) {
+ for (i = 0; i < NINED3DTSS_COUNT; ++i)
+ if (src->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32)))
+ context->ff.tex_stage[s][i] = src->ff.tex_stage[s][i];
+ }
+ }
+ if (src->changed.group & NINE_STATE_FF_LIGHTING) {
+ unsigned num_lights = MAX2(context->ff.num_lights, src->ff.num_lights);
+ /* Can happen if the stateblock had recorded the creation of
+ * new lights. */
+ if (context->ff.num_lights < num_lights) {
+ context->ff.light = REALLOC(context->ff.light,
+ context->ff.num_lights * sizeof(D3DLIGHT9),
+ num_lights * sizeof(D3DLIGHT9));
+ memset(&context->ff.light[context->ff.num_lights], 0, (num_lights - context->ff.num_lights) * sizeof(D3DLIGHT9));
+ for (i = context->ff.num_lights; i < num_lights; ++i)
+ context->ff.light[i].Type = (D3DLIGHTTYPE)NINED3DLIGHT_INVALID;
+ context->ff.num_lights = num_lights;
+ }
+ /* src->ff.num_lights < num_lights has been handled before */
+ assert (src->ff.num_lights == num_lights);
+
+ for (i = 0; i < num_lights; ++i)
+ if (src->ff.light[i].Type != NINED3DLIGHT_INVALID)
+ context->ff.light[i] = src->ff.light[i];
+
+ memcpy(context->ff.active_light, src->ff.active_light, sizeof(src->ff.active_light) );
+ context->ff.num_lights_active = src->ff.num_lights_active;
+ }
+ if (src->changed.group & NINE_STATE_FF_VSTRANSF) {
+ for (i = 0; i < ARRAY_SIZE(src->ff.changed.transform); ++i) {
+ unsigned s;
+ if (!src->ff.changed.transform[i])
+ continue;
+ for (s = i * 32; s < (i * 32 + 32); ++s) {
+ if (!(src->ff.changed.transform[i] & (1 << (s % 32))))
+ continue;
+ *nine_state_access_transform(&context->ff, s, TRUE) =
+ *nine_state_access_transform( /* const because !alloc */
+ (struct nine_ff_state *)&src->ff, s, FALSE);
+ }
+ context->ff.changed.transform[i] |= src->ff.changed.transform[i];
+ }
+ }
+}
+
+#endif
+
+/* Do not write to nine_context directly. Slower,
+ * but works with csmt. TODO: write a special csmt version that
+ * would record the list of commands as much as possible,
+ * and use the version above else.
+ */
+void
+nine_context_apply_stateblock(struct NineDevice9 *device,
+ const struct nine_state *src)
+{
+ int i;
+
+ /* No need to apply src->changed.group, since all calls do
+ * set context->changed.group */
+
+ for (i = 0; i < ARRAY_SIZE(src->changed.rs); ++i) {
+ uint32_t m = src->changed.rs[i];
+ while (m) {
+ const int r = ffs(m) - 1;
+ m &= ~(1 << r);
+ nine_context_set_render_state(device, i * 32 + r, src->rs_advertised[i * 32 + r]);
+ }
+ }
+
+ /* Textures */
+ if (src->changed.texture) {
+ uint32_t m = src->changed.texture;
+ unsigned s;
+
+ for (s = 0; m; ++s, m >>= 1) {
+ struct NineBaseTexture9 *tex = src->texture[s];
+ if (!(m & 1))
+ continue;
+ nine_context_set_texture(device, s, tex);
+ }
+ }
+
+ /* Sampler state */
+ if (src->changed.group & NINE_STATE_SAMPLER) {
+ unsigned s;
+
+ for (s = 0; s < NINE_MAX_SAMPLERS; ++s) {
+ uint32_t m = src->changed.sampler[s];
+ while (m) {
+ const int i = ffs(m) - 1;
+ m &= ~(1 << i);
+ nine_context_set_sampler_state(device, s, i, src->samp_advertised[s][i]);
+ }
+ }
+ }
+
+ /* Vertex buffers */
+ if (src->changed.vtxbuf | src->changed.stream_freq) {
+ uint32_t m = src->changed.vtxbuf | src->changed.stream_freq;
+ for (i = 0; m; ++i, m >>= 1) {
+ if (src->changed.vtxbuf & (1 << i))
+ nine_context_set_stream_source(device, i, src->stream[i], src->vtxbuf[i].buffer_offset, src->vtxbuf[i].stride);
+ if (src->changed.stream_freq & (1 << i))
+ nine_context_set_stream_source_freq(device, i, src->stream_freq[i]);
+ }
+ }
+
+ /* Index buffer */
+ if (src->changed.group & NINE_STATE_IDXBUF)
+ nine_context_set_indices(device, src->idxbuf);
+
+ /* Vertex declaration */
+ if ((src->changed.group & NINE_STATE_VDECL) && src->vdecl)
+ nine_context_set_vertex_declaration(device, src->vdecl);
+
+ /* Vertex shader */
+ if (src->changed.group & NINE_STATE_VS)
+ nine_context_set_vertex_shader(device, src->vs);
+
+ /* Pixel shader */
+ if (src->changed.group & NINE_STATE_PS)
+ nine_context_set_pixel_shader(device, src->ps);
+
+ /* Vertex constants */
+ if (src->changed.group & NINE_STATE_VS_CONST) {
+ struct nine_range *r;
+ for (r = src->changed.vs_const_f; r; r = r->next)
+ nine_context_set_vertex_shader_constant_f(device, r->bgn,
+ &src->vs_const_f[r->bgn * 4],
+ sizeof(float[4]) * (r->end - r->bgn),
+ r->end - r->bgn);
+ for (r = src->changed.vs_const_i; r; r = r->next)
+ nine_context_set_vertex_shader_constant_i(device, r->bgn,
+ &src->vs_const_i[r->bgn * 4],
+ sizeof(int[4]) * (r->end - r->bgn),
+ r->end - r->bgn);
+ for (r = src->changed.vs_const_b; r; r = r->next)
+ nine_context_set_vertex_shader_constant_b(device, r->bgn,
+ &src->vs_const_b[r->bgn * 4],
+ sizeof(BOOL) * (r->end - r->bgn),
+ r->end - r->bgn);
+ }
+
+ /* Pixel constants */
+ if (src->changed.group & NINE_STATE_PS_CONST) {
+ struct nine_range *r;
+ for (r = src->changed.ps_const_f; r; r = r->next)
+ nine_context_set_pixel_shader_constant_f(device, r->bgn,
+ &src->ps_const_f[r->bgn * 4],
+ sizeof(float[4]) * (r->end - r->bgn),
+ r->end - r->bgn);
+ if (src->changed.ps_const_i) {
+ uint16_t m = src->changed.ps_const_i;
+ for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+ if (m & 1)
+ nine_context_set_pixel_shader_constant_i_transformed(device, i,
+ src->ps_const_i[i], sizeof(int[4]), 1);
+ }
+ if (src->changed.ps_const_b) {
+ uint16_t m = src->changed.ps_const_b;
+ for (i = ffs(m) - 1, m >>= i; m; ++i, m >>= 1)
+ if (m & 1)
+ nine_context_set_pixel_shader_constant_b(device, i,
+ &src->ps_const_b[i], sizeof(BOOL), 1);
+ }
+ }
+
+ /* Viewport */
+ if (src->changed.group & NINE_STATE_VIEWPORT)
+ nine_context_set_viewport(device, &src->viewport);
+
+ /* Scissor */
+ if (src->changed.group & NINE_STATE_SCISSOR)
+ nine_context_set_scissor(device, &src->scissor);
+
+ /* User Clip Planes */
+ if (src->changed.ucp)
+ for (i = 0; i < PIPE_MAX_CLIP_PLANES; ++i)
+ if (src->changed.ucp & (1 << i))
+ nine_context_set_clip_plane(device, i, (struct nine_clipplane*)&src->clip.ucp[i][0]);
+
+ if (!(src->changed.group & NINE_STATE_FF))
+ return;
+
+ /* Fixed function state. */
+
+ if (src->changed.group & NINE_STATE_FF_MATERIAL)
+ nine_context_set_material(device, &src->ff.material);
+
+ if (src->changed.group & NINE_STATE_FF_PSSTAGES) {
+ unsigned s;
+ for (s = 0; s < NINE_MAX_TEXTURE_STAGES; ++s) {
+ for (i = 0; i < NINED3DTSS_COUNT; ++i)
+ if (src->ff.changed.tex_stage[s][i / 32] & (1 << (i % 32)))
+ nine_context_set_texture_stage_state(device, s, i, src->ff.tex_stage[s][i]);
+ }
+ }
+ if (src->changed.group & NINE_STATE_FF_LIGHTING) {
+ for (i = 0; i < src->ff.num_lights; ++i)
+ if (src->ff.light[i].Type != NINED3DLIGHT_INVALID)
+ nine_context_set_light(device, i, &src->ff.light[i]);
+
+ nine_context_light_enable_stateblock(device, src->ff.active_light, src->ff.num_lights_active);
+ }
+ if (src->changed.group & NINE_STATE_FF_VSTRANSF) {
+ for (i = 0; i < ARRAY_SIZE(src->ff.changed.transform); ++i) {
+ unsigned s;
+ if (!src->ff.changed.transform[i])
+ continue;
+ for (s = i * 32; s < (i * 32 + 32); ++s) {
+ if (!(src->ff.changed.transform[i] & (1 << (s % 32))))
+ continue;
+ nine_context_set_transform(device, s,
+ nine_state_access_transform(
+ (struct nine_ff_state *)&src->ff,
+ s, FALSE));
+ }
+ }
+ }
+}
+
+static void
+nine_update_state_framebuffer_clear(struct NineDevice9 *device)
+{
+ struct nine_context *context = &device->context;
+
+ if (context->changed.group & NINE_STATE_FB)
+ update_framebuffer(device, TRUE);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_clear_fb,
+ ARG_VAL(DWORD, Count),
+ ARG_COPY_REF(D3DRECT, pRects),
+ ARG_VAL(DWORD, Flags),
+ ARG_VAL(D3DCOLOR, Color),
+ ARG_VAL(float, Z),
+ ARG_VAL(DWORD, Stencil))
+{
+ struct nine_context *context = &device->context;
+ const int sRGB = context->rs[D3DRS_SRGBWRITEENABLE] ? 1 : 0;
+ struct pipe_surface *cbuf, *zsbuf;
+ struct pipe_context *pipe = context->pipe;
+ struct NineSurface9 *zsbuf_surf = context->ds;
+ struct NineSurface9 *rt;
+ unsigned bufs = 0;
+ unsigned r, i;
+ union pipe_color_union rgba;
+ unsigned rt_mask = 0;
+ D3DRECT rect;
+
+ nine_update_state_framebuffer_clear(device);
+
+ if (Flags & D3DCLEAR_TARGET) bufs |= PIPE_CLEAR_COLOR;
+ /* Ignore Z buffer if not bound */
+ if (context->pipe_data.fb.zsbuf != NULL) {
+ if (Flags & D3DCLEAR_ZBUFFER) bufs |= PIPE_CLEAR_DEPTH;
+ if (Flags & D3DCLEAR_STENCIL) bufs |= PIPE_CLEAR_STENCIL;
+ }
+ if (!bufs)
+ return;
+ d3dcolor_to_pipe_color_union(&rgba, Color);
+
+ rect.x1 = context->viewport.X;
+ rect.y1 = context->viewport.Y;
+ rect.x2 = context->viewport.Width + rect.x1;
+ rect.y2 = context->viewport.Height + rect.y1;
+
+ /* Both rectangles apply, which is weird, but that's D3D9. */
+ if (context->rs[D3DRS_SCISSORTESTENABLE]) {
+ rect.x1 = MAX2(rect.x1, context->scissor.minx);
+ rect.y1 = MAX2(rect.y1, context->scissor.miny);
+ rect.x2 = MIN2(rect.x2, context->scissor.maxx);
+ rect.y2 = MIN2(rect.y2, context->scissor.maxy);
+ }
+
+ if (Count) {
+ /* Maybe apps like to specify a large rect ? */
+ if (pRects[0].x1 <= rect.x1 && pRects[0].x2 >= rect.x2 &&
+ pRects[0].y1 <= rect.y1 && pRects[0].y2 >= rect.y2) {
+ DBG("First rect covers viewport.\n");
+ Count = 0;
+ pRects = NULL;
+ }
+ }
+
+ if (rect.x1 >= context->pipe_data.fb.width || rect.y1 >= context->pipe_data.fb.height)
+ return;
+
+ for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) {
+ if (context->rt[i] && context->rt[i]->desc.Format != D3DFMT_NULL)
+ rt_mask |= 1 << i;
+ }
+
+ /* fast path, clears everything at once */
+ if (!Count &&
+ (!(bufs & PIPE_CLEAR_COLOR) || (rt_mask == context->rt_mask)) &&
+ rect.x1 == 0 && rect.y1 == 0 &&
+ /* Case we clear only render target. Check clear region vs rt. */
+ ((!(bufs & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) &&
+ rect.x2 >= context->pipe_data.fb.width &&
+ rect.y2 >= context->pipe_data.fb.height) ||
+ /* Case we clear depth buffer (and eventually rt too).
+ * depth buffer size is always >= rt size. Compare to clear region */
+ ((bufs & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) &&
+ rect.x2 >= zsbuf_surf->desc.Width &&
+ rect.y2 >= zsbuf_surf->desc.Height))) {
+ DBG("Clear fast path\n");
+ pipe->clear(pipe, bufs, &rgba, Z, Stencil);
+ return;
+ }
+
+ if (!Count) {
+ Count = 1;
+ pRects = ▭
+ }
+
+ for (i = 0; i < device->caps.NumSimultaneousRTs; ++i) {
+ rt = context->rt[i];
+ if (!rt || rt->desc.Format == D3DFMT_NULL ||
+ !(bufs & PIPE_CLEAR_COLOR))
+ continue; /* save space, compiler should hoist this */
+ cbuf = NineSurface9_GetSurface(rt, sRGB);
+ for (r = 0; r < Count; ++r) {
+ /* Don't trust users to pass these in the right order. */
+ unsigned x1 = MIN2(pRects[r].x1, pRects[r].x2);
+ unsigned y1 = MIN2(pRects[r].y1, pRects[r].y2);
+ unsigned x2 = MAX2(pRects[r].x1, pRects[r].x2);
+ unsigned y2 = MAX2(pRects[r].y1, pRects[r].y2);
+#ifndef NINE_LAX
+ /* Drop negative rectangles (like wine expects). */
+ if (pRects[r].x1 > pRects[r].x2) continue;
+ if (pRects[r].y1 > pRects[r].y2) continue;
+#endif
+
+ x1 = MAX2(x1, rect.x1);
+ y1 = MAX2(y1, rect.y1);
+ x2 = MIN3(x2, rect.x2, rt->desc.Width);
+ y2 = MIN3(y2, rect.y2, rt->desc.Height);
+
+ DBG("Clearing (%u..%u)x(%u..%u)\n", x1, x2, y1, y2);
+ pipe->clear_render_target(pipe, cbuf, &rgba,
+ x1, y1, x2 - x1, y2 - y1, false);
+ }
+ }
+ if (!(bufs & PIPE_CLEAR_DEPTHSTENCIL))
+ return;
+
+ bufs &= PIPE_CLEAR_DEPTHSTENCIL;
+
+ for (r = 0; r < Count; ++r) {
+ unsigned x1 = MIN2(pRects[r].x1, pRects[r].x2);
+ unsigned y1 = MIN2(pRects[r].y1, pRects[r].y2);
+ unsigned x2 = MAX2(pRects[r].x1, pRects[r].x2);
+ unsigned y2 = MAX2(pRects[r].y1, pRects[r].y2);
+#ifndef NINE_LAX
+ /* Drop negative rectangles. */
+ if (pRects[r].x1 > pRects[r].x2) continue;
+ if (pRects[r].y1 > pRects[r].y2) continue;
+#endif
+
+ x1 = MIN2(x1, rect.x1);
+ y1 = MIN2(y1, rect.y1);
+ x2 = MIN3(x2, rect.x2, zsbuf_surf->desc.Width);
+ y2 = MIN3(y2, rect.y2, zsbuf_surf->desc.Height);
+
+ zsbuf = NineSurface9_GetSurface(zsbuf_surf, 0);
+ assert(zsbuf);
+ pipe->clear_depth_stencil(pipe, zsbuf, bufs, Z, Stencil,
+ x1, y1, x2 - x1, y2 - y1, false);
+ }
+ return;
+}
+
+
+static inline void
+init_draw_info(struct pipe_draw_info *info,
+ struct NineDevice9 *dev, D3DPRIMITIVETYPE type, UINT count)
+{
+ info->mode = d3dprimitivetype_to_pipe_prim(type);
+ info->count = prim_count_to_vertex_count(type, count);
+ info->start_instance = 0;
+ info->instance_count = 1;
+ if (dev->context.stream_instancedata_mask & dev->context.stream_usage_mask)
+ info->instance_count = MAX2(dev->context.stream_freq[0] & 0x7FFFFF, 1);
+ info->primitive_restart = FALSE;
+ info->restart_index = 0;
+ info->count_from_stream_output = NULL;
+ info->indirect = NULL;
+ info->indirect_params = NULL;
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_draw_primitive,
+ ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType),
+ ARG_VAL(UINT, StartVertex),
+ ARG_VAL(UINT, PrimitiveCount))
+{
+ struct nine_context *context = &device->context;
+ struct pipe_draw_info info;
+
+ nine_update_state(device);
+
+ init_draw_info(&info, device, PrimitiveType, PrimitiveCount);
+ info.indexed = FALSE;
+ info.start = StartVertex;
+ info.index_bias = 0;
+ info.min_index = info.start;
+ info.max_index = info.count - 1;
+
+ context->pipe->draw_vbo(context->pipe, &info);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_draw_indexed_primitive,
+ ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType),
+ ARG_VAL(INT, BaseVertexIndex),
+ ARG_VAL(UINT, MinVertexIndex),
+ ARG_VAL(UINT, NumVertices),
+ ARG_VAL(UINT, StartIndex),
+ ARG_VAL(UINT, PrimitiveCount))
+{
+ struct nine_context *context = &device->context;
+ struct pipe_draw_info info;
+
+ nine_update_state(device);
+
+ init_draw_info(&info, device, PrimitiveType, PrimitiveCount);
+ info.indexed = TRUE;
+ info.start = StartIndex;
+ info.index_bias = BaseVertexIndex;
+ /* These don't include index bias: */
+ info.min_index = MinVertexIndex;
+ info.max_index = MinVertexIndex + NumVertices - 1;
+
+ context->pipe->draw_vbo(context->pipe, &info);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_draw_primitive_from_vtxbuf,
+ ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType),
+ ARG_VAL(UINT, PrimitiveCount),
+ ARG_BIND_BUF(struct pipe_vertex_buffer, vtxbuf))
+{
+ struct nine_context *context = &device->context;
+ struct pipe_draw_info info;
+
+ nine_update_state(device);
+
+ init_draw_info(&info, device, PrimitiveType, PrimitiveCount);
+ info.indexed = FALSE;
+ info.start = 0;
+ info.index_bias = 0;
+ info.min_index = 0;
+ info.max_index = info.count - 1;
+
+ context->pipe->set_vertex_buffers(context->pipe, 0, 1, vtxbuf);
+
+ context->pipe->draw_vbo(context->pipe, &info);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_draw_indexed_primitive_from_vtxbuf_idxbuf,
+ ARG_VAL(D3DPRIMITIVETYPE, PrimitiveType),
+ ARG_VAL(UINT, MinVertexIndex),
+ ARG_VAL(UINT, NumVertices),
+ ARG_VAL(UINT, PrimitiveCount),
+ ARG_BIND_BUF(struct pipe_vertex_buffer, vbuf),
+ ARG_BIND_BUF(struct pipe_index_buffer, ibuf))
+{
+ struct nine_context *context = &device->context;
+ struct pipe_draw_info info;
+
+ nine_update_state(device);
+
+ init_draw_info(&info, device, PrimitiveType, PrimitiveCount);
+ info.indexed = TRUE;
+ info.start = 0;
+ info.index_bias = 0;
+ info.min_index = MinVertexIndex;
+ info.max_index = MinVertexIndex + NumVertices - 1;
+ context->pipe->set_vertex_buffers(context->pipe, 0, 1, vbuf);
+ context->pipe->set_index_buffer(context->pipe, ibuf);
+
+ context->pipe->draw_vbo(context->pipe, &info);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_resource_copy_region,
+ ARG_BIND_REF(struct NineUnknown, dst),
+ ARG_BIND_REF(struct NineUnknown, src),
+ ARG_BIND_RES(struct pipe_resource, dst_res),
+ ARG_VAL(unsigned, dst_level),
+ ARG_COPY_REF(struct pipe_box, dst_box),
+ ARG_BIND_RES(struct pipe_resource, src_res),
+ ARG_VAL(unsigned, src_level),
+ ARG_COPY_REF(struct pipe_box, src_box))
+{
+ struct nine_context *context = &device->context;
+
+ (void) dst;
+ (void) src;
+
+ context->pipe->resource_copy_region(context->pipe,
+ dst_res, dst_level,
+ dst_box->x, dst_box->y, dst_box->z,
+ src_res, src_level,
+ src_box);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_blit,
+ ARG_BIND_REF(struct NineUnknown, dst),
+ ARG_BIND_REF(struct NineUnknown, src),
+ ARG_BIND_BLIT(struct pipe_blit_info, blit))
+{
+ struct nine_context *context = &device->context;
+
+ (void) dst;
+ (void) src;
+
+ context->pipe->blit(context->pipe, blit);
+}
+
+CSMT_ITEM_NO_WAIT(nine_context_clear_render_target,
+ ARG_BIND_REF(struct NineSurface9, surface),
+ ARG_VAL(D3DCOLOR, color),
+ ARG_VAL(UINT, x),
+ ARG_VAL(UINT, y),
+ ARG_VAL(UINT, width),
+ ARG_VAL(UINT, height))
+{
+ struct nine_context *context = &device->context;
+ struct pipe_surface *surf;
+ union pipe_color_union rgba;