2 * Context and render target management in wined3d
4 * Copyright 2002-2004 Jason Edmeades
5 * Copyright 2002-2004 Raphael Junqueira
6 * Copyright 2004 Christian Costa
7 * Copyright 2005 Oliver Stieber
8 * Copyright 2006, 2008 Henri Verbeet
9 * Copyright 2007-2011, 2013 Stefan Dösinger for CodeWeavers
10 * Copyright 2009-2011 Henri Verbeet for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "wined3d_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
30 WINE_DECLARE_DEBUG_CHANNEL(d3d_perf
);
32 void context_resource_released(const struct wined3d_device
*device
, struct wined3d_resource
*resource
)
36 for (i
= 0; i
< device
->context_count
; ++i
)
38 struct wined3d_context
*context
= device
->contexts
[i
];
40 if (&context
->current_rt
.texture
->resource
== resource
)
42 context
->current_rt
.texture
= NULL
;
43 context
->current_rt
.sub_resource_idx
= 0;
48 void wined3d_context_cleanup(struct wined3d_context
*context
)
52 /* This is used when a context for render target A is active, but a separate context is
53 * needed to access the WGL framebuffer for render target B. Re-acquire a context for rt
54 * A to avoid breaking caller code. */
55 void context_restore(struct wined3d_context
*context
, struct wined3d_texture
*texture
, unsigned int sub_resource_idx
)
57 if (context
->current_rt
.texture
!= texture
|| context
->current_rt
.sub_resource_idx
!= sub_resource_idx
)
59 context_release(context
);
60 context
= context_acquire(texture
->resource
.device
, texture
, sub_resource_idx
);
63 context_release(context
);
66 void context_invalidate_compute_state(struct wined3d_context
*context
, DWORD state_id
)
68 DWORD representative
= context
->state_table
[state_id
].representative
- STATE_COMPUTE_OFFSET
;
69 unsigned int index
, shift
;
71 index
= representative
/ (sizeof(*context
->dirty_compute_states
) * CHAR_BIT
);
72 shift
= representative
& (sizeof(*context
->dirty_compute_states
) * CHAR_BIT
- 1);
73 context
->dirty_compute_states
[index
] |= (1u << shift
);
76 void context_invalidate_state(struct wined3d_context
*context
, unsigned int state_id
)
78 unsigned int representative
= context
->state_table
[state_id
].representative
;
79 unsigned int index
, shift
;
82 ERR("Invalidating representative 0, state_id %u.\n", state_id
);
84 index
= representative
/ (sizeof(*context
->dirty_graphics_states
) * CHAR_BIT
);
85 shift
= representative
& ((sizeof(*context
->dirty_graphics_states
) * CHAR_BIT
) - 1);
86 context
->dirty_graphics_states
[index
] |= (1u << shift
);
89 void wined3d_context_init(struct wined3d_context
*context
, struct wined3d_swapchain
*swapchain
)
91 struct wined3d_device
*device
= swapchain
->device
;
94 context
->d3d_info
= &device
->adapter
->d3d_info
;
95 context
->state_table
= device
->state_table
;
97 /* Mark all states dirty to force a proper initialization of the states on
98 * the first use of the context. Compute states do not need initialization. */
99 for (state
= 0; state
<= STATE_HIGHEST
; ++state
)
101 if (context
->state_table
[state
].representative
&& !STATE_IS_COMPUTE(state
))
102 context_invalidate_state(context
, state
);
105 context
->device
= device
;
106 context
->swapchain
= swapchain
;
107 context
->current_rt
.texture
= swapchain
->front_buffer
;
108 context
->current_rt
.sub_resource_idx
= 0;
110 context
->shader_update_mask
= (1u << WINED3D_SHADER_TYPE_PIXEL
)
111 | (1u << WINED3D_SHADER_TYPE_VERTEX
)
112 | (1u << WINED3D_SHADER_TYPE_GEOMETRY
)
113 | (1u << WINED3D_SHADER_TYPE_HULL
)
114 | (1u << WINED3D_SHADER_TYPE_DOMAIN
)
115 | (1u << WINED3D_SHADER_TYPE_COMPUTE
);
117 context
->update_primitive_type
= 1;
118 context
->update_patch_vertex_count
= 1;
119 context
->update_multisample_state
= 1;
122 HRESULT
wined3d_context_no3d_init(struct wined3d_context
*context_no3d
, struct wined3d_swapchain
*swapchain
)
124 TRACE("context_no3d %p, swapchain %p.\n", context_no3d
, swapchain
);
126 wined3d_context_init(context_no3d
, swapchain
);
131 static BOOL
fixed_get_input(BYTE usage
, BYTE usage_idx
, unsigned int *regnum
)
133 if ((usage
== WINED3D_DECL_USAGE_POSITION
|| usage
== WINED3D_DECL_USAGE_POSITIONT
) && !usage_idx
)
134 *regnum
= WINED3D_FFP_POSITION
;
135 else if (usage
== WINED3D_DECL_USAGE_BLEND_WEIGHT
&& !usage_idx
)
136 *regnum
= WINED3D_FFP_BLENDWEIGHT
;
137 else if (usage
== WINED3D_DECL_USAGE_BLEND_INDICES
&& !usage_idx
)
138 *regnum
= WINED3D_FFP_BLENDINDICES
;
139 else if (usage
== WINED3D_DECL_USAGE_NORMAL
&& !usage_idx
)
140 *regnum
= WINED3D_FFP_NORMAL
;
141 else if (usage
== WINED3D_DECL_USAGE_PSIZE
&& !usage_idx
)
142 *regnum
= WINED3D_FFP_PSIZE
;
143 else if (usage
== WINED3D_DECL_USAGE_COLOR
&& !usage_idx
)
144 *regnum
= WINED3D_FFP_DIFFUSE
;
145 else if (usage
== WINED3D_DECL_USAGE_COLOR
&& usage_idx
== 1)
146 *regnum
= WINED3D_FFP_SPECULAR
;
147 else if (usage
== WINED3D_DECL_USAGE_TEXCOORD
&& usage_idx
< WINED3DDP_MAXTEXCOORD
)
148 *regnum
= WINED3D_FFP_TEXCOORD0
+ usage_idx
;
151 WARN("Unsupported input stream [usage=%s, usage_idx=%u].\n", debug_d3ddeclusage(usage
), usage_idx
);
159 /* Context activation is done by the caller. */
160 void wined3d_stream_info_from_declaration(struct wined3d_stream_info
*stream_info
,
161 const struct wined3d_state
*state
, const struct wined3d_d3d_info
*d3d_info
)
163 /* We need to deal with frequency data! */
164 struct wined3d_vertex_declaration
*declaration
= state
->vertex_declaration
;
165 BOOL use_vshader
= use_vs(state
);
168 stream_info
->use_map
= 0;
169 stream_info
->swizzle_map
= 0;
170 stream_info
->position_transformed
= 0;
175 stream_info
->position_transformed
= declaration
->position_transformed
;
177 /* Translate the declaration into strided data. */
178 for (i
= 0; i
< declaration
->element_count
; ++i
)
180 const struct wined3d_vertex_declaration_element
*element
= &declaration
->elements
[i
];
181 const struct wined3d_stream_state
*stream
= &state
->streams
[element
->input_slot
];
185 TRACE("%p Element %p (%u of %u).\n", declaration
->elements
,
186 element
, i
+ 1, declaration
->element_count
);
191 TRACE("offset %u input_slot %u usage_idx %d.\n", element
->offset
, element
->input_slot
, element
->usage_idx
);
195 if (element
->output_slot
== WINED3D_OUTPUT_SLOT_UNUSED
)
199 else if (element
->output_slot
== WINED3D_OUTPUT_SLOT_SEMANTIC
)
201 /* TODO: Assuming vertexdeclarations are usually used with the
202 * same or a similar shader, it might be worth it to store the
203 * last used output slot and try that one first. */
204 stride_used
= vshader_get_input(state
->shader
[WINED3D_SHADER_TYPE_VERTEX
],
205 element
->usage
, element
->usage_idx
, &idx
);
209 idx
= element
->output_slot
;
215 stride_used
= fixed_get_input(element
->usage
, element
->usage_idx
, &idx
);
220 TRACE("Load %s array %u [usage %s, usage_idx %u, "
221 "input_slot %u, offset %u, stride %u, format %s, class %s, step_rate %u].\n",
222 use_vshader
? "shader": "fixed function", idx
,
223 debug_d3ddeclusage(element
->usage
), element
->usage_idx
, element
->input_slot
,
224 element
->offset
, stream
->stride
, debug_d3dformat(element
->format
->id
),
225 debug_d3dinput_classification(element
->input_slot_class
), element
->instance_data_step_rate
);
227 stream_info
->elements
[idx
].format
= element
->format
;
228 stream_info
->elements
[idx
].data
.buffer_object
= 0;
229 stream_info
->elements
[idx
].data
.addr
= (BYTE
*)NULL
+ stream
->offset
+ element
->offset
;
230 stream_info
->elements
[idx
].stride
= stream
->stride
;
231 stream_info
->elements
[idx
].stream_idx
= element
->input_slot
;
232 if (stream
->flags
& WINED3DSTREAMSOURCE_INSTANCEDATA
)
234 stream_info
->elements
[idx
].divisor
= 1;
235 stream_info
->elements
[idx
].instanced
= true;
237 else if (element
->input_slot_class
== WINED3D_INPUT_PER_INSTANCE_DATA
)
239 stream_info
->elements
[idx
].divisor
= element
->instance_data_step_rate
;
240 stream_info
->elements
[idx
].instanced
= true;
244 stream_info
->elements
[idx
].divisor
= 0;
245 stream_info
->elements
[idx
].instanced
= false;
248 if (!d3d_info
->vertex_bgra
&& element
->format
->id
== WINED3DFMT_B8G8R8A8_UNORM
)
250 stream_info
->swizzle_map
|= 1u << idx
;
252 stream_info
->use_map
|= 1u << idx
;
257 /* Context activation is done by the caller. */
258 void context_update_stream_info(struct wined3d_context
*context
, const struct wined3d_state
*state
)
260 struct wined3d_stream_info
*stream_info
= &context
->stream_info
;
261 const struct wined3d_d3d_info
*d3d_info
= context
->d3d_info
;
262 DWORD prev_all_vbo
= stream_info
->all_vbo
;
266 wined3d_stream_info_from_declaration(stream_info
, state
, d3d_info
);
268 stream_info
->all_vbo
= 1;
269 map
= stream_info
->use_map
;
272 struct wined3d_stream_info_element
*element
;
273 struct wined3d_bo_address data
;
274 struct wined3d_buffer
*buffer
;
276 i
= wined3d_bit_scan(&map
);
277 element
= &stream_info
->elements
[i
];
278 buffer
= state
->streams
[element
->stream_idx
].buffer
;
280 /* We can't use VBOs if the base vertex index is negative. OpenGL
281 * doesn't accept negative offsets (or rather offsets bigger than the
282 * VBO, because the pointer is unsigned), so use system memory
283 * sources. In most sane cases the pointer - offset will still be > 0,
284 * otherwise it will wrap around to some big value. Hope that with the
285 * indices the driver wraps it back internally. If not,
286 * draw_primitive_immediate_mode() is needed, including a vertex buffer
288 if (state
->load_base_vertex_index
< 0)
290 WARN_(d3d_perf
)("load_base_vertex_index is < 0 (%d), not using VBOs.\n",
291 state
->load_base_vertex_index
);
292 element
->data
.buffer_object
= 0;
293 element
->data
.addr
+= (ULONG_PTR
)wined3d_buffer_load_sysmem(buffer
, context
);
294 if ((UINT_PTR
)element
->data
.addr
< -state
->load_base_vertex_index
* element
->stride
)
295 FIXME("System memory vertex data load offset is negative!\n");
299 wined3d_buffer_load(buffer
, context
, state
);
300 wined3d_buffer_get_memory(buffer
, context
, &data
);
301 element
->data
.buffer_object
= data
.buffer_object
;
302 element
->data
.addr
+= (ULONG_PTR
)data
.addr
;
305 if (!element
->data
.buffer_object
)
306 stream_info
->all_vbo
= 0;
308 TRACE("Load array %u %s.\n", i
, debug_bo_address(&element
->data
));
311 if (prev_all_vbo
!= stream_info
->all_vbo
)
312 context_invalidate_state(context
, STATE_INDEXBUFFER
);