wined3d: Hold an internal reference on pixel and vertex shaders.
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blobd14ad303a6344f028e2f770c02fcbff8769dabda
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 for(i = 0; i < MAX_STREAMS; i++) {
518 if(object->streamSource[i]) {
519 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
522 if(object->pIndexData) {
523 IWineD3DIndexBuffer_AddRef(object->pIndexData);
525 if(object->vertexShader) {
526 IWineD3DVertexShader_AddRef(object->vertexShader);
528 if(object->pixelShader) {
529 IWineD3DPixelShader_AddRef(object->pixelShader);
532 } else if (Type == WINED3DSBT_PIXELSTATE) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.pixelShader = TRUE;
539 /* Pixel Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541 object->contained_ps_consts_f[i] = i;
542 object->changed.pixelShaderConstantsF[i] = TRUE;
544 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545 for (i = 0; i < MAX_CONST_B; ++i) {
546 object->contained_ps_consts_b[i] = i;
547 object->changed.pixelShaderConstantsB[i] = TRUE;
549 object->num_contained_ps_consts_b = MAX_CONST_B;
550 for (i = 0; i < MAX_CONST_I; ++i) {
551 object->contained_ps_consts_i[i] = i;
552 object->changed.pixelShaderConstantsI[i] = TRUE;
554 object->num_contained_ps_consts_i = MAX_CONST_I;
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558 object->contained_render_states[i] = SavedPixelStates_R[i];
560 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561 for (j = 0; j < MAX_TEXTURES; j++) {
562 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566 object->num_contained_tss_states++;
569 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574 object->num_contained_sampler_states++;
577 if(object->pixelShader) {
578 IWineD3DPixelShader_AddRef(object->pixelShader);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i = 0; i < MAX_STREAMS; i++) {
585 object->streamSource[i] = NULL;
587 object->pIndexData = NULL;
588 object->vertexShader = NULL;
590 } else if (Type == WINED3DSBT_VERTEXSTATE) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
595 object->changed.vertexShader = TRUE;
597 /* Vertex Shader Constants */
598 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599 object->changed.vertexShaderConstantsF[i] = TRUE;
600 object->contained_vs_consts_f[i] = i;
602 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603 for (i = 0; i < MAX_CONST_B; ++i) {
604 object->changed.vertexShaderConstantsB[i] = TRUE;
605 object->contained_vs_consts_b[i] = i;
607 object->num_contained_vs_consts_b = MAX_CONST_B;
608 for (i = 0; i < MAX_CONST_I; ++i) {
609 object->changed.vertexShaderConstantsI[i] = TRUE;
610 object->contained_vs_consts_i[i] = i;
612 object->num_contained_vs_consts_i = MAX_CONST_I;
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 object->contained_render_states[i] = SavedVertexStates_R[i];
617 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618 for (j = 0; j < MAX_TEXTURES; j++) {
619 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623 object->num_contained_tss_states++;
626 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631 object->num_contained_sampler_states++;
635 for(j = 0; j < LIGHTMAP_SIZE; j++) {
636 struct list *e;
637 LIST_FOR_EACH(e, &object->lightMap[j]) {
638 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639 light->changed = TRUE;
640 light->enabledChanged = TRUE;
644 for(i = 0; i < MAX_STREAMS; i++) {
645 if(object->streamSource[i]) {
646 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
649 if(object->vertexShader) {
650 IWineD3DVertexShader_AddRef(object->vertexShader);
652 object->pIndexData = NULL;
653 object->pixelShader = NULL;
654 } else {
655 FIXME("Unrecognized state block type %d\n", Type);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
659 return WINED3D_OK;
662 /* ************************************
663 MSDN:
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
666 Discard
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
671 ******************************** */
673 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
675 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size = 1;
677 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678 TRACE("(%p) Create surface\n",This);
680 /** FIXME: Check ranges on the inputs are valid
681 * MSDN
682 * MultisampleQuality
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
687 * must all match.
688 *******************************/
692 * TODO: Discard MSDN
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality < 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality);
704 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
707 if(MultisampleQuality > 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709 MultisampleQuality=0;
712 /** FIXME: Check that the format is supported
713 * by the device.
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
718 * space!
719 *********************************/
720 if (WINED3DFMT_UNKNOWN == Format) {
721 Size = 0;
722 } else if (Format == WINED3DFMT_DXT1) {
723 /* DXT1 is half byte per pixel */
724 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
726 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
729 } else {
730 /* The pitch is a multiple of 4 bytes */
731 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
732 Size *= Height;
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
740 object->currentDesc.Width = Width;
741 object->currentDesc.Height = Height;
742 object->currentDesc.MultiSampleType = MultiSample;
743 object->currentDesc.MultiSampleQuality = MultisampleQuality;
744 object->glDescription.level = Level;
746 /* Flags */
747 object->Flags = 0;
748 object->Flags |= Discard ? SFLAG_DISCARD : 0;
749 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
753 if (WINED3DFMT_UNKNOWN != Format) {
754 object->bytesPerPixel = tableEntry->bpp;
755 } else {
756 object->bytesPerPixel = 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
767 switch(Pool) {
768 case WINED3DPOOL_SCRATCH:
769 if(!Lockable)
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
772 Lockable = TRUE;
773 break;
774 case WINED3DPOOL_SYSTEMMEM:
775 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED:
778 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
781 break;
782 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
786 break;
787 default:
788 FIXME("(%p) Unknown pool %d\n", This, Pool);
789 break;
792 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This, Width, Height, Format, debug_d3dformat(Format),
800 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804 This->ddraw_primary = (IWineD3DSurface *) object;
806 /* Look at the implementation and set the correct Vtable */
807 switch(Impl) {
808 case SURFACE_OPENGL:
809 /* Check if a 3D adapter is available when creating gl surfaces */
810 if(!This->adapter) {
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813 HeapFree(GetProcessHeap(), 0, object);
814 return WINED3DERR_NOTAVAILABLE;
816 break;
818 case SURFACE_GDI:
819 object->lpVtbl = &IWineGDISurface_Vtbl;
820 break;
822 default:
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl);
825 IWineD3DSurface_Release((IWineD3DSurface *) object);
826 return WINED3DERR_INVALIDCALL;
829 list_init(&object->renderbuffers);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842 IWineD3DTextureImpl *object;
843 unsigned int i;
844 UINT tmpW;
845 UINT tmpH;
846 HRESULT hr;
847 unsigned int pow2Width;
848 unsigned int pow2Height;
851 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
852 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
853 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
855 /* TODO: It should only be possible to create textures for formats
856 that are reported as supported */
857 if (WINED3DFMT_UNKNOWN >= Format) {
858 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
859 return WINED3DERR_INVALIDCALL;
862 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
863 D3DINITIALIZEBASETEXTURE(object->baseTexture);
864 object->width = Width;
865 object->height = Height;
867 /** Non-power2 support **/
868 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
869 pow2Width = Width;
870 pow2Height = Height;
871 } else {
872 /* Find the nearest pow2 match */
873 pow2Width = pow2Height = 1;
874 while (pow2Width < Width) pow2Width <<= 1;
875 while (pow2Height < Height) pow2Height <<= 1;
878 /** FIXME: add support for real non-power-two if it's provided by the video card **/
879 /* Precalculated scaling for 'faked' non power of two texture coords */
880 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
881 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
882 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
884 /* Calculate levels for mip mapping */
885 if (Levels == 0) {
886 TRACE("calculating levels %d\n", object->baseTexture.levels);
887 object->baseTexture.levels++;
888 tmpW = Width;
889 tmpH = Height;
890 while (tmpW > 1 || tmpH > 1) {
891 tmpW = max(1, tmpW >> 1);
892 tmpH = max(1, tmpH >> 1);
893 object->baseTexture.levels++;
895 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
898 /* Generate all the surfaces */
899 tmpW = Width;
900 tmpH = Height;
901 for (i = 0; i < object->baseTexture.levels; i++)
903 /* use the callback to create the texture surface */
904 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
905 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
906 FIXME("Failed to create surface %p\n", object);
907 /* clean up */
908 object->surfaces[i] = NULL;
909 IWineD3DTexture_Release((IWineD3DTexture *)object);
911 *ppTexture = NULL;
912 return hr;
915 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
916 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
917 /* calculate the next mipmap level */
918 tmpW = max(1, tmpW >> 1);
919 tmpH = max(1, tmpH >> 1);
922 TRACE("(%p) : Created texture %p\n", This, object);
923 return WINED3D_OK;
926 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
927 UINT Width, UINT Height, UINT Depth,
928 UINT Levels, DWORD Usage,
929 WINED3DFORMAT Format, WINED3DPOOL Pool,
930 IWineD3DVolumeTexture **ppVolumeTexture,
931 HANDLE *pSharedHandle, IUnknown *parent,
932 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
935 IWineD3DVolumeTextureImpl *object;
936 unsigned int i;
937 UINT tmpW;
938 UINT tmpH;
939 UINT tmpD;
941 /* TODO: It should only be possible to create textures for formats
942 that are reported as supported */
943 if (WINED3DFMT_UNKNOWN >= Format) {
944 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
945 return WINED3DERR_INVALIDCALL;
948 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
949 D3DINITIALIZEBASETEXTURE(object->baseTexture);
951 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
952 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
954 object->width = Width;
955 object->height = Height;
956 object->depth = Depth;
958 /* Calculate levels for mip mapping */
959 if (Levels == 0) {
960 object->baseTexture.levels++;
961 tmpW = Width;
962 tmpH = Height;
963 tmpD = Depth;
964 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
965 tmpW = max(1, tmpW >> 1);
966 tmpH = max(1, tmpH >> 1);
967 tmpD = max(1, tmpD >> 1);
968 object->baseTexture.levels++;
970 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
973 /* Generate all the surfaces */
974 tmpW = Width;
975 tmpH = Height;
976 tmpD = Depth;
978 for (i = 0; i < object->baseTexture.levels; i++)
980 HRESULT hr;
981 /* Create the volume */
982 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
983 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
985 if(FAILED(hr)) {
986 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
987 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
988 *ppVolumeTexture = NULL;
989 return hr;
992 /* Set its container to this object */
993 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
995 /* calcualte the next mipmap level */
996 tmpW = max(1, tmpW >> 1);
997 tmpH = max(1, tmpH >> 1);
998 tmpD = max(1, tmpD >> 1);
1001 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1002 TRACE("(%p) : Created volume texture %p\n", This, object);
1003 return WINED3D_OK;
1006 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1007 UINT Width, UINT Height, UINT Depth,
1008 DWORD Usage,
1009 WINED3DFORMAT Format, WINED3DPOOL Pool,
1010 IWineD3DVolume** ppVolume,
1011 HANDLE* pSharedHandle, IUnknown *parent) {
1013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1014 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1015 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1017 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1019 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1020 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1022 object->currentDesc.Width = Width;
1023 object->currentDesc.Height = Height;
1024 object->currentDesc.Depth = Depth;
1025 object->bytesPerPixel = formatDesc->bpp;
1027 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1028 object->lockable = TRUE;
1029 object->locked = FALSE;
1030 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1031 object->dirty = TRUE;
1033 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1036 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1037 UINT Levels, DWORD Usage,
1038 WINED3DFORMAT Format, WINED3DPOOL Pool,
1039 IWineD3DCubeTexture **ppCubeTexture,
1040 HANDLE *pSharedHandle, IUnknown *parent,
1041 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1044 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1045 unsigned int i, j;
1046 UINT tmpW;
1047 HRESULT hr;
1048 unsigned int pow2EdgeLength = EdgeLength;
1050 /* TODO: It should only be possible to create textures for formats
1051 that are reported as supported */
1052 if (WINED3DFMT_UNKNOWN >= Format) {
1053 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1054 return WINED3DERR_INVALIDCALL;
1057 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1058 WARN("(%p) : Tried to create not supported cube texture\n", This);
1059 return WINED3DERR_INVALIDCALL;
1062 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1063 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1065 TRACE("(%p) Create Cube Texture\n", This);
1067 /** Non-power2 support **/
1069 /* Find the nearest pow2 match */
1070 pow2EdgeLength = 1;
1071 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1073 object->edgeLength = EdgeLength;
1074 /* TODO: support for native non-power 2 */
1075 /* Precalculated scaling for 'faked' non power of two texture coords */
1076 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1078 /* Calculate levels for mip mapping */
1079 if (Levels == 0) {
1080 object->baseTexture.levels++;
1081 tmpW = EdgeLength;
1082 while (tmpW > 1) {
1083 tmpW = max(1, tmpW >> 1);
1084 object->baseTexture.levels++;
1086 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1089 /* Generate all the surfaces */
1090 tmpW = EdgeLength;
1091 for (i = 0; i < object->baseTexture.levels; i++) {
1093 /* Create the 6 faces */
1094 for (j = 0; j < 6; j++) {
1096 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1097 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1099 if(hr!= WINED3D_OK) {
1100 /* clean up */
1101 int k;
1102 int l;
1103 for (l = 0; l < j; l++) {
1104 IWineD3DSurface_Release(object->surfaces[j][i]);
1106 for (k = 0; k < i; k++) {
1107 for (l = 0; l < 6; l++) {
1108 IWineD3DSurface_Release(object->surfaces[l][j]);
1112 FIXME("(%p) Failed to create surface\n",object);
1113 HeapFree(GetProcessHeap(),0,object);
1114 *ppCubeTexture = NULL;
1115 return hr;
1117 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1118 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1120 tmpW = max(1, tmpW >> 1);
1123 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1124 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1125 return WINED3D_OK;
1128 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1130 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1131 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1133 /* Just a check to see if we support this type of query */
1134 switch(Type) {
1135 case WINED3DQUERYTYPE_OCCLUSION:
1136 TRACE("(%p) occlusion query\n", This);
1137 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1138 hr = WINED3D_OK;
1139 else
1140 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1141 break;
1143 case WINED3DQUERYTYPE_EVENT:
1144 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1145 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1146 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1148 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1150 hr = WINED3D_OK;
1151 break;
1153 case WINED3DQUERYTYPE_VCACHE:
1154 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1155 case WINED3DQUERYTYPE_VERTEXSTATS:
1156 case WINED3DQUERYTYPE_TIMESTAMP:
1157 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1158 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1159 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1160 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1161 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1162 case WINED3DQUERYTYPE_PIXELTIMINGS:
1163 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1164 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1165 default:
1166 FIXME("(%p) Unhandled query type %d\n", This, Type);
1168 if(NULL == ppQuery || hr != WINED3D_OK) {
1169 return hr;
1172 D3DCREATEOBJECTINSTANCE(object, Query)
1173 object->type = Type;
1174 /* allocated the 'extended' data based on the type of query requested */
1175 switch(Type){
1176 case WINED3DQUERYTYPE_OCCLUSION:
1177 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1178 TRACE("(%p) Allocating data for an occlusion query\n", This);
1179 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1180 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1181 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1182 break;
1184 case WINED3DQUERYTYPE_EVENT:
1185 if(GL_SUPPORT(APPLE_FENCE)) {
1186 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1187 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1188 checkGLcall("glGenFencesAPPLE");
1189 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1190 } else if(GL_SUPPORT(NV_FENCE)) {
1191 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1192 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1193 checkGLcall("glGenFencesNV");
1194 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1196 break;
1198 case WINED3DQUERYTYPE_VCACHE:
1199 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1200 case WINED3DQUERYTYPE_VERTEXSTATS:
1201 case WINED3DQUERYTYPE_TIMESTAMP:
1202 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1203 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1204 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1205 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1206 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1207 case WINED3DQUERYTYPE_PIXELTIMINGS:
1208 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1209 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1210 default:
1211 object->extendedData = 0;
1212 FIXME("(%p) Unhandled query type %d\n",This , Type);
1214 TRACE("(%p) : Created Query %p\n", This, object);
1215 return WINED3D_OK;
1218 /*****************************************************************************
1219 * IWineD3DDeviceImpl_SetupFullscreenWindow
1221 * Helper function that modifies a HWND's Style and ExStyle for proper
1222 * fullscreen use.
1224 * Params:
1225 * iface: Pointer to the IWineD3DDevice interface
1226 * window: Window to setup
1228 *****************************************************************************/
1229 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1232 LONG style, exStyle;
1233 /* Don't do anything if an original style is stored.
1234 * That shouldn't happen
1236 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1237 if (This->style || This->exStyle) {
1238 ERR("(%p): Want to change the window parameters of HWND %p, but "
1239 "another style is stored for restoration afterwards\n", This, window);
1242 /* Get the parameters and save them */
1243 style = GetWindowLongW(window, GWL_STYLE);
1244 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1245 This->style = style;
1246 This->exStyle = exStyle;
1248 /* Filter out window decorations */
1249 style &= ~WS_CAPTION;
1250 style &= ~WS_THICKFRAME;
1251 exStyle &= ~WS_EX_WINDOWEDGE;
1252 exStyle &= ~WS_EX_CLIENTEDGE;
1254 /* Make sure the window is managed, otherwise we won't get keyboard input */
1255 style |= WS_POPUP | WS_SYSMENU;
1257 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1258 This->style, This->exStyle, style, exStyle);
1260 SetWindowLongW(window, GWL_STYLE, style);
1261 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1263 /* Inform the window about the update. */
1264 SetWindowPos(window, HWND_TOP, 0, 0,
1265 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1266 ShowWindow(window, SW_NORMAL);
1269 /*****************************************************************************
1270 * IWineD3DDeviceImpl_RestoreWindow
1272 * Helper function that restores a windows' properties when taking it out
1273 * of fullscreen mode
1275 * Params:
1276 * iface: Pointer to the IWineD3DDevice interface
1277 * window: Window to setup
1279 *****************************************************************************/
1280 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1283 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1284 * switch, do nothing
1286 if (!This->style && !This->exStyle) return;
1288 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1289 This, window, This->style, This->exStyle);
1291 SetWindowLongW(window, GWL_STYLE, This->style);
1292 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1294 /* Delete the old values */
1295 This->style = 0;
1296 This->exStyle = 0;
1298 /* Inform the window about the update */
1299 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1300 0, 0, 0, 0, /* Pos, Size, ignored */
1301 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1304 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1305 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1306 IUnknown* parent,
1307 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1308 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1311 HDC hDc;
1312 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1313 HRESULT hr = WINED3D_OK;
1314 IUnknown *bufferParent;
1316 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1318 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1319 * does a device hold a reference to a swap chain giving them a lifetime of the device
1320 * or does the swap chain notify the device of its destruction.
1321 *******************************/
1323 /* Check the params */
1324 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1325 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1326 return WINED3DERR_INVALIDCALL;
1327 } else if (pPresentationParameters->BackBufferCount > 1) {
1328 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1331 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1333 /*********************
1334 * Lookup the window Handle and the relating X window handle
1335 ********************/
1337 /* Setup hwnd we are using, plus which display this equates to */
1338 object->win_handle = pPresentationParameters->hDeviceWindow;
1339 if (!object->win_handle) {
1340 object->win_handle = This->createParms.hFocusWindow;
1343 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1344 hDc = GetDC(object->win_handle);
1345 TRACE("Using hDc %p\n", hDc);
1347 if (NULL == hDc) {
1348 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1349 return WINED3DERR_NOTAVAILABLE;
1352 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1353 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1354 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1355 ReleaseDC(object->win_handle, hDc);
1357 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1358 * then the corresponding dimension of the client area of the hDeviceWindow
1359 * (or the focus window, if hDeviceWindow is NULL) is taken.
1360 **********************/
1362 if (pPresentationParameters->Windowed &&
1363 ((pPresentationParameters->BackBufferWidth == 0) ||
1364 (pPresentationParameters->BackBufferHeight == 0))) {
1366 RECT Rect;
1367 GetClientRect(object->win_handle, &Rect);
1369 if (pPresentationParameters->BackBufferWidth == 0) {
1370 pPresentationParameters->BackBufferWidth = Rect.right;
1371 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1373 if (pPresentationParameters->BackBufferHeight == 0) {
1374 pPresentationParameters->BackBufferHeight = Rect.bottom;
1375 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1377 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1378 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1379 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1383 /* Put the correct figures in the presentation parameters */
1384 TRACE("Copying across presentation parameters\n");
1385 object->presentParms = *pPresentationParameters;
1387 TRACE("calling rendertarget CB\n");
1388 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1389 parent,
1390 object->presentParms.BackBufferWidth,
1391 object->presentParms.BackBufferHeight,
1392 object->presentParms.BackBufferFormat,
1393 object->presentParms.MultiSampleType,
1394 object->presentParms.MultiSampleQuality,
1395 TRUE /* Lockable */,
1396 &object->frontBuffer,
1397 NULL /* pShared (always null)*/);
1398 if (object->frontBuffer != NULL) {
1399 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1400 } else {
1401 ERR("Failed to create the front buffer\n");
1402 goto error;
1406 * Create an opengl context for the display visual
1407 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1408 * use different properties after that point in time. FIXME: How to handle when requested format
1409 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1410 * it chooses is identical to the one already being used!
1411 **********************************/
1412 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1414 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1415 if(!object->context)
1416 return E_OUTOFMEMORY;
1417 object->num_contexts = 1;
1419 ENTER_GL();
1420 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1421 LEAVE_GL();
1423 if (!object->context[0]) {
1424 ERR("Failed to create a new context\n");
1425 hr = WINED3DERR_NOTAVAILABLE;
1426 goto error;
1427 } else {
1428 TRACE("Context created (HWND=%p, glContext=%p)\n",
1429 object->win_handle, object->context[0]->glCtx);
1432 /*********************
1433 * Windowed / Fullscreen
1434 *******************/
1437 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1438 * so we should really check to see if there is a fullscreen swapchain already
1439 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1440 **************************************/
1442 if (!pPresentationParameters->Windowed) {
1444 DEVMODEW devmode;
1445 HDC hdc;
1446 int bpp = 0;
1447 RECT clip_rc;
1449 /* Get info on the current display setup */
1450 hdc = GetDC(0);
1451 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1452 ReleaseDC(0, hdc);
1454 /* Change the display settings */
1455 memset(&devmode, 0, sizeof(devmode));
1456 devmode.dmSize = sizeof(devmode);
1457 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1458 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1459 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1460 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1461 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1463 /* For GetDisplayMode */
1464 This->ddraw_width = devmode.dmPelsWidth;
1465 This->ddraw_height = devmode.dmPelsHeight;
1466 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1468 IWineD3DDevice_SetFullscreen(iface, TRUE);
1470 /* And finally clip mouse to our screen */
1471 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1472 ClipCursor(&clip_rc);
1475 /*********************
1476 * Create the back, front and stencil buffers
1477 *******************/
1478 if(object->presentParms.BackBufferCount > 0) {
1479 int i;
1481 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1482 if(!object->backBuffer) {
1483 ERR("Out of memory\n");
1484 hr = E_OUTOFMEMORY;
1485 goto error;
1488 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1489 TRACE("calling rendertarget CB\n");
1490 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1491 parent,
1492 object->presentParms.BackBufferWidth,
1493 object->presentParms.BackBufferHeight,
1494 object->presentParms.BackBufferFormat,
1495 object->presentParms.MultiSampleType,
1496 object->presentParms.MultiSampleQuality,
1497 TRUE /* Lockable */,
1498 &object->backBuffer[i],
1499 NULL /* pShared (always null)*/);
1500 if(hr == WINED3D_OK && object->backBuffer[i]) {
1501 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1502 } else {
1503 ERR("Cannot create new back buffer\n");
1504 goto error;
1506 ENTER_GL();
1507 glDrawBuffer(GL_BACK);
1508 checkGLcall("glDrawBuffer(GL_BACK)");
1509 LEAVE_GL();
1511 } else {
1512 object->backBuffer = NULL;
1514 /* Single buffering - draw to front buffer */
1515 ENTER_GL();
1516 glDrawBuffer(GL_FRONT);
1517 checkGLcall("glDrawBuffer(GL_FRONT)");
1518 LEAVE_GL();
1521 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1522 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1523 TRACE("Creating depth stencil buffer\n");
1524 if (This->depthStencilBuffer == NULL ) {
1525 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1526 parent,
1527 object->presentParms.BackBufferWidth,
1528 object->presentParms.BackBufferHeight,
1529 object->presentParms.AutoDepthStencilFormat,
1530 object->presentParms.MultiSampleType,
1531 object->presentParms.MultiSampleQuality,
1532 FALSE /* FIXME: Discard */,
1533 &This->depthStencilBuffer,
1534 NULL /* pShared (always null)*/ );
1535 if (This->depthStencilBuffer != NULL)
1536 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1539 /** TODO: A check on width, height and multisample types
1540 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1541 ****************************/
1542 object->wantsDepthStencilBuffer = TRUE;
1543 } else {
1544 object->wantsDepthStencilBuffer = FALSE;
1547 TRACE("Created swapchain %p\n", object);
1548 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1549 return WINED3D_OK;
1551 error:
1552 if (object->backBuffer) {
1553 int i;
1554 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1555 if(object->backBuffer[i]) {
1556 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1557 IUnknown_Release(bufferParent); /* once for the get parent */
1558 if (IUnknown_Release(bufferParent) > 0) {
1559 FIXME("(%p) Something's still holding the back buffer\n",This);
1563 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1564 object->backBuffer = NULL;
1566 if(object->context[0])
1567 DestroyContext(This, object->context[0]);
1568 if(object->frontBuffer) {
1569 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1570 IUnknown_Release(bufferParent); /* once for the get parent */
1571 if (IUnknown_Release(bufferParent) > 0) {
1572 FIXME("(%p) Something's still holding the front buffer\n",This);
1575 HeapFree(GetProcessHeap(), 0, object);
1576 return hr;
1579 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1580 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1582 TRACE("(%p)\n", This);
1584 return This->NumberOfSwapChains;
1587 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1589 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1591 if(iSwapChain < This->NumberOfSwapChains) {
1592 *pSwapChain = This->swapchains[iSwapChain];
1593 IWineD3DSwapChain_AddRef(*pSwapChain);
1594 TRACE("(%p) returning %p\n", This, *pSwapChain);
1595 return WINED3D_OK;
1596 } else {
1597 TRACE("Swapchain out of range\n");
1598 *pSwapChain = NULL;
1599 return WINED3DERR_INVALIDCALL;
1603 /*****
1604 * Vertex Declaration
1605 *****/
1606 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1607 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1609 IWineD3DVertexDeclarationImpl *object = NULL;
1610 HRESULT hr = WINED3D_OK;
1612 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1613 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1615 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1617 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1619 return hr;
1622 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1624 unsigned int idx, idx2;
1625 unsigned int offset;
1626 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1627 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1628 BOOL has_blend_idx = has_blend &&
1629 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1630 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1631 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1632 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1633 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1634 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1635 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1637 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1638 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1640 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1641 WINED3DVERTEXELEMENT *elements = NULL;
1643 unsigned int size;
1644 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1645 if (has_blend_idx) num_blends--;
1647 /* Compute declaration size */
1648 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1649 has_psize + has_diffuse + has_specular + num_textures + 1;
1651 /* convert the declaration */
1652 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1653 if (!elements)
1654 return 0;
1656 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1657 idx = 0;
1658 if (has_pos) {
1659 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1660 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1661 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1663 else {
1664 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1665 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1667 elements[idx].UsageIndex = 0;
1668 idx++;
1670 if (has_blend && (num_blends > 0)) {
1671 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1672 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1673 else
1674 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1675 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1676 elements[idx].UsageIndex = 0;
1677 idx++;
1679 if (has_blend_idx) {
1680 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1681 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1682 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1683 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1684 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1685 else
1686 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1687 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1688 elements[idx].UsageIndex = 0;
1689 idx++;
1691 if (has_normal) {
1692 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1693 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1694 elements[idx].UsageIndex = 0;
1695 idx++;
1697 if (has_psize) {
1698 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1699 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1700 elements[idx].UsageIndex = 0;
1701 idx++;
1703 if (has_diffuse) {
1704 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1705 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1706 elements[idx].UsageIndex = 0;
1707 idx++;
1709 if (has_specular) {
1710 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1711 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1712 elements[idx].UsageIndex = 1;
1713 idx++;
1715 for (idx2 = 0; idx2 < num_textures; idx2++) {
1716 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1717 switch (numcoords) {
1718 case WINED3DFVF_TEXTUREFORMAT1:
1719 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1720 break;
1721 case WINED3DFVF_TEXTUREFORMAT2:
1722 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1723 break;
1724 case WINED3DFVF_TEXTUREFORMAT3:
1725 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1726 break;
1727 case WINED3DFVF_TEXTUREFORMAT4:
1728 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1729 break;
1731 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1732 elements[idx].UsageIndex = idx2;
1733 idx++;
1736 /* Now compute offsets, and initialize the rest of the fields */
1737 for (idx = 0, offset = 0; idx < size-1; idx++) {
1738 elements[idx].Stream = 0;
1739 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1740 elements[idx].Offset = offset;
1741 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1744 *ppVertexElements = elements;
1745 return size;
1748 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1749 WINED3DVERTEXELEMENT* elements = NULL;
1750 size_t size;
1751 DWORD hr;
1753 size = ConvertFvfToDeclaration(Fvf, &elements);
1754 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1756 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1757 HeapFree(GetProcessHeap(), 0, elements);
1758 if (hr != S_OK) return hr;
1760 return WINED3D_OK;
1763 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1764 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1766 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1767 HRESULT hr = WINED3D_OK;
1768 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1769 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1771 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1773 if (vertex_declaration) {
1774 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1777 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1779 if (WINED3D_OK != hr) {
1780 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1781 IWineD3DVertexShader_Release(*ppVertexShader);
1782 return WINED3DERR_INVALIDCALL;
1785 return WINED3D_OK;
1788 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1790 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1791 HRESULT hr = WINED3D_OK;
1793 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1794 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1795 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1796 if (WINED3D_OK == hr) {
1797 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1798 } else {
1799 WARN("(%p) : Failed to create pixel shader\n", This);
1802 return hr;
1805 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1807 IWineD3DPaletteImpl *object;
1808 HRESULT hr;
1809 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1811 /* Create the new object */
1812 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1813 if(!object) {
1814 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1815 return E_OUTOFMEMORY;
1818 object->lpVtbl = &IWineD3DPalette_Vtbl;
1819 object->ref = 1;
1820 object->Flags = Flags;
1821 object->parent = Parent;
1822 object->wineD3DDevice = This;
1823 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1825 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1827 if(!object->hpal) {
1828 HeapFree( GetProcessHeap(), 0, object);
1829 return E_OUTOFMEMORY;
1832 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1833 if(FAILED(hr)) {
1834 IWineD3DPalette_Release((IWineD3DPalette *) object);
1835 return hr;
1838 *Palette = (IWineD3DPalette *) object;
1840 return WINED3D_OK;
1843 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1845 IWineD3DSwapChainImpl *swapchain;
1846 HRESULT hr;
1847 DWORD state;
1849 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1850 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1852 /* TODO: Test if OpenGL is compiled in and loaded */
1854 TRACE("(%p) : Creating stateblock\n", This);
1855 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1856 hr = IWineD3DDevice_CreateStateBlock(iface,
1857 WINED3DSBT_INIT,
1858 (IWineD3DStateBlock **)&This->stateBlock,
1859 NULL);
1860 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1861 WARN("Failed to create stateblock\n");
1862 return hr;
1864 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1865 This->updateStateBlock = This->stateBlock;
1866 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1868 hr = allocate_shader_constants(This->updateStateBlock);
1869 if (WINED3D_OK != hr)
1870 return hr;
1872 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1873 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1874 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1876 /* Initialize the texture unit mapping to a 1:1 mapping */
1877 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1878 if (state < GL_LIMITS(fragment_samplers)) {
1879 This->texUnitMap[state] = state;
1880 This->rev_tex_unit_map[state] = state;
1881 } else {
1882 This->texUnitMap[state] = -1;
1883 This->rev_tex_unit_map[state] = -1;
1887 /* Setup the implicit swapchain */
1888 TRACE("Creating implicit swapchain\n");
1889 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1890 if (FAILED(hr) || !swapchain) {
1891 WARN("Failed to create implicit swapchain\n");
1892 return hr;
1895 This->NumberOfSwapChains = 1;
1896 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1897 if(!This->swapchains) {
1898 ERR("Out of memory!\n");
1899 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1900 return E_OUTOFMEMORY;
1902 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1904 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1906 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1907 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1908 This->render_targets[0] = swapchain->backBuffer[0];
1909 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1911 else {
1912 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1913 This->render_targets[0] = swapchain->frontBuffer;
1914 This->lastActiveRenderTarget = swapchain->frontBuffer;
1916 IWineD3DSurface_AddRef(This->render_targets[0]);
1917 This->activeContext = swapchain->context[0];
1918 This->lastThread = GetCurrentThreadId();
1920 /* Depth Stencil support */
1921 This->stencilBufferTarget = This->depthStencilBuffer;
1922 if (NULL != This->stencilBufferTarget) {
1923 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1926 /* Set up some starting GL setup */
1927 ENTER_GL();
1929 /* Setup all the devices defaults */
1930 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1931 #if 0
1932 IWineD3DImpl_CheckGraphicsMemory();
1933 #endif
1935 { /* Set a default viewport */
1936 WINED3DVIEWPORT vp;
1937 vp.X = 0;
1938 vp.Y = 0;
1939 vp.Width = pPresentationParameters->BackBufferWidth;
1940 vp.Height = pPresentationParameters->BackBufferHeight;
1941 vp.MinZ = 0.0f;
1942 vp.MaxZ = 1.0f;
1943 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1946 /* Initialize the current view state */
1947 This->view_ident = 1;
1948 This->contexts[0]->last_was_rhw = 0;
1949 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1950 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1952 switch(wined3d_settings.offscreen_rendering_mode) {
1953 case ORM_FBO:
1954 case ORM_PBUFFER:
1955 This->offscreenBuffer = GL_BACK;
1956 break;
1958 case ORM_BACKBUFFER:
1960 if(GL_LIMITS(aux_buffers) > 0) {
1961 TRACE("Using auxilliary buffer for offscreen rendering\n");
1962 This->offscreenBuffer = GL_AUX0;
1963 } else {
1964 TRACE("Using back buffer for offscreen rendering\n");
1965 This->offscreenBuffer = GL_BACK;
1970 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1971 LEAVE_GL();
1973 /* Clear the screen */
1974 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1975 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1976 0x00, 1.0, 0);
1978 This->d3d_initialized = TRUE;
1979 return WINED3D_OK;
1982 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1984 int sampler;
1985 UINT i;
1986 TRACE("(%p)\n", This);
1988 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1990 /* I don't think that the interface guarants that the device is destroyed from the same thread
1991 * it was created. Thus make sure a context is active for the glDelete* calls
1993 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1995 TRACE("Deleting high order patches\n");
1996 for(i = 0; i < PATCHMAP_SIZE; i++) {
1997 struct list *e1, *e2;
1998 struct WineD3DRectPatch *patch;
1999 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2000 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2001 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2005 /* Delete the pbuffer context if there is any */
2006 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2008 /* Delete the mouse cursor texture */
2009 if(This->cursorTexture) {
2010 ENTER_GL();
2011 glDeleteTextures(1, &This->cursorTexture);
2012 LEAVE_GL();
2013 This->cursorTexture = 0;
2016 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2017 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2019 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2020 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2023 /* Release the update stateblock */
2024 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2025 if(This->updateStateBlock != This->stateBlock)
2026 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2028 This->updateStateBlock = NULL;
2030 { /* because were not doing proper internal refcounts releasing the primary state block
2031 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2032 to set this->stateBlock = NULL; first */
2033 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2034 This->stateBlock = NULL;
2036 /* Release the stateblock */
2037 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2038 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2042 /* Release the buffers (with sanity checks)*/
2043 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2044 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2045 if(This->depthStencilBuffer != This->stencilBufferTarget)
2046 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2048 This->stencilBufferTarget = NULL;
2050 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2051 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2052 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2054 TRACE("Setting rendertarget to NULL\n");
2055 This->render_targets[0] = NULL;
2057 if (This->depthStencilBuffer) {
2058 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2059 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2061 This->depthStencilBuffer = NULL;
2064 for(i=0; i < This->NumberOfSwapChains; i++) {
2065 TRACE("Releasing the implicit swapchain %d\n", i);
2066 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2067 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2071 HeapFree(GetProcessHeap(), 0, This->swapchains);
2072 This->swapchains = NULL;
2073 This->NumberOfSwapChains = 0;
2075 HeapFree(GetProcessHeap(), 0, This->render_targets);
2076 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2077 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2078 This->render_targets = NULL;
2079 This->fbo_color_attachments = NULL;
2080 This->draw_buffers = NULL;
2083 This->d3d_initialized = FALSE;
2084 return WINED3D_OK;
2087 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2089 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2091 /* Setup the window for fullscreen mode */
2092 if(fullscreen && !This->ddraw_fullscreen) {
2093 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2094 } else if(!fullscreen && This->ddraw_fullscreen) {
2095 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2098 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2099 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2100 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2101 * separately.
2103 This->ddraw_fullscreen = fullscreen;
2106 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2107 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2108 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2110 * There is no way to deactivate thread safety once it is enabled
2112 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2115 /*For now just store the flag(needed in case of ddraw) */
2116 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2118 return;
2121 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2122 DEVMODEW devmode;
2123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2124 LONG ret;
2125 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2126 RECT clip_rc;
2128 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2130 /* Resize the screen even without a window:
2131 * The app could have unset it with SetCooperativeLevel, but not called
2132 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2133 * but we don't have any hwnd
2136 memset(&devmode, 0, sizeof(devmode));
2137 devmode.dmSize = sizeof(devmode);
2138 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2139 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2140 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2141 devmode.dmPelsWidth = pMode->Width;
2142 devmode.dmPelsHeight = pMode->Height;
2144 devmode.dmDisplayFrequency = pMode->RefreshRate;
2145 if (pMode->RefreshRate != 0) {
2146 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2149 /* Only change the mode if necessary */
2150 if( (This->ddraw_width == pMode->Width) &&
2151 (This->ddraw_height == pMode->Height) &&
2152 (This->ddraw_format == pMode->Format) &&
2153 (pMode->RefreshRate == 0) ) {
2154 return WINED3D_OK;
2157 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2158 if (ret != DISP_CHANGE_SUCCESSFUL) {
2159 if(devmode.dmDisplayFrequency != 0) {
2160 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2161 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2162 devmode.dmDisplayFrequency = 0;
2163 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2165 if(ret != DISP_CHANGE_SUCCESSFUL) {
2166 return WINED3DERR_NOTAVAILABLE;
2170 /* Store the new values */
2171 This->ddraw_width = pMode->Width;
2172 This->ddraw_height = pMode->Height;
2173 This->ddraw_format = pMode->Format;
2175 /* Only do this with a window of course */
2176 if(This->ddraw_window)
2177 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2179 /* And finally clip mouse to our screen */
2180 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2181 ClipCursor(&clip_rc);
2183 return WINED3D_OK;
2186 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2188 *ppD3D= This->wineD3D;
2189 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2190 IWineD3D_AddRef(*ppD3D);
2191 return WINED3D_OK;
2194 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2195 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2196 * into the video ram as possible and seeing how many fit
2197 * you can also get the correct initial value from nvidia and ATI's driver via X
2198 * texture memory is video memory + AGP memory
2199 *******************/
2200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2201 static BOOL showfixmes = TRUE;
2202 if (showfixmes) {
2203 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2204 (wined3d_settings.emulated_textureram/(1024*1024)),
2205 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2206 showfixmes = FALSE;
2208 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2209 (wined3d_settings.emulated_textureram/(1024*1024)),
2210 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2211 /* return simulated texture memory left */
2212 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2217 /*****
2218 * Get / Set FVF
2219 *****/
2220 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2223 /* Update the current state block */
2224 This->updateStateBlock->changed.fvf = TRUE;
2226 if(This->updateStateBlock->fvf == fvf) {
2227 TRACE("Application is setting the old fvf over, nothing to do\n");
2228 return WINED3D_OK;
2231 This->updateStateBlock->fvf = fvf;
2232 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2233 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2234 return WINED3D_OK;
2238 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2240 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2241 *pfvf = This->stateBlock->fvf;
2242 return WINED3D_OK;
2245 /*****
2246 * Get / Set Stream Source
2247 *****/
2248 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2250 IWineD3DVertexBuffer *oldSrc;
2252 if (StreamNumber >= MAX_STREAMS) {
2253 WARN("Stream out of range %d\n", StreamNumber);
2254 return WINED3DERR_INVALIDCALL;
2257 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2258 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2260 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2262 if(oldSrc == pStreamData &&
2263 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2264 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2265 TRACE("Application is setting the old values over, nothing to do\n");
2266 return WINED3D_OK;
2269 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2270 if (pStreamData) {
2271 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2272 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2275 /* Handle recording of state blocks */
2276 if (This->isRecordingState) {
2277 TRACE("Recording... not performing anything\n");
2278 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2279 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2280 return WINED3D_OK;
2283 /* Need to do a getParent and pass the reffs up */
2284 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2285 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2286 so for now, just count internally */
2287 if (pStreamData != NULL) {
2288 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2289 InterlockedIncrement(&vbImpl->bindCount);
2290 IWineD3DVertexBuffer_AddRef(pStreamData);
2292 if (oldSrc != NULL) {
2293 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2294 IWineD3DVertexBuffer_Release(oldSrc);
2297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2299 return WINED3D_OK;
2302 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2305 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2306 This->stateBlock->streamSource[StreamNumber],
2307 This->stateBlock->streamOffset[StreamNumber],
2308 This->stateBlock->streamStride[StreamNumber]);
2310 if (StreamNumber >= MAX_STREAMS) {
2311 WARN("Stream out of range %d\n", StreamNumber);
2312 return WINED3DERR_INVALIDCALL;
2314 *pStream = This->stateBlock->streamSource[StreamNumber];
2315 *pStride = This->stateBlock->streamStride[StreamNumber];
2316 if (pOffset) {
2317 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2320 if (*pStream != NULL) {
2321 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2323 return WINED3D_OK;
2326 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2328 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2329 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2331 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2332 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2334 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2335 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2337 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2338 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2342 return WINED3D_OK;
2345 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2348 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2349 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2351 TRACE("(%p) : returning %d\n", This, *Divider);
2353 return WINED3D_OK;
2356 /*****
2357 * Get / Set & Multiply Transform
2358 *****/
2359 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2362 /* Most of this routine, comments included copied from ddraw tree initially: */
2363 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2365 /* Handle recording of state blocks */
2366 if (This->isRecordingState) {
2367 TRACE("Recording... not performing anything\n");
2368 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2369 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2370 return WINED3D_OK;
2374 * If the new matrix is the same as the current one,
2375 * we cut off any further processing. this seems to be a reasonable
2376 * optimization because as was noticed, some apps (warcraft3 for example)
2377 * tend towards setting the same matrix repeatedly for some reason.
2379 * From here on we assume that the new matrix is different, wherever it matters.
2381 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2382 TRACE("The app is setting the same matrix over again\n");
2383 return WINED3D_OK;
2384 } else {
2385 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2389 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2390 where ViewMat = Camera space, WorldMat = world space.
2392 In OpenGL, camera and world space is combined into GL_MODELVIEW
2393 matrix. The Projection matrix stay projection matrix.
2396 /* Capture the times we can just ignore the change for now */
2397 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2398 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2399 /* Handled by the state manager */
2402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2403 return WINED3D_OK;
2406 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2408 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2409 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2410 return WINED3D_OK;
2413 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2414 WINED3DMATRIX *mat = NULL;
2415 WINED3DMATRIX temp;
2417 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2418 * below means it will be recorded in a state block change, but it
2419 * works regardless where it is recorded.
2420 * If this is found to be wrong, change to StateBlock.
2422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2423 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2425 if (State < HIGHEST_TRANSFORMSTATE)
2427 mat = &This->updateStateBlock->transforms[State];
2428 } else {
2429 FIXME("Unhandled transform state!!\n");
2432 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2434 /* Apply change via set transform - will reapply to eg. lights this way */
2435 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2438 /*****
2439 * Get / Set Light
2440 *****/
2441 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2442 you can reference any indexes you want as long as that number max are enabled at any
2443 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2444 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2445 but when recording, just build a chain pretty much of commands to be replayed. */
2447 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2448 float rho;
2449 PLIGHTINFOEL *object = NULL;
2450 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2451 struct list *e;
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2454 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2456 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2457 * the gl driver.
2459 if(!pLight) {
2460 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2461 return WINED3DERR_INVALIDCALL;
2464 switch(pLight->Type) {
2465 case WINED3DLIGHT_POINT:
2466 case WINED3DLIGHT_SPOT:
2467 case WINED3DLIGHT_PARALLELPOINT:
2468 case WINED3DLIGHT_GLSPOT:
2469 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2470 * most wanted
2472 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2473 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2474 return WINED3DERR_INVALIDCALL;
2476 break;
2478 case WINED3DLIGHT_DIRECTIONAL:
2479 /* Ignores attenuation */
2480 break;
2482 default:
2483 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2484 return WINED3DERR_INVALIDCALL;
2487 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2488 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2489 if(object->OriginalIndex == Index) break;
2490 object = NULL;
2493 if(!object) {
2494 TRACE("Adding new light\n");
2495 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2496 if(!object) {
2497 ERR("Out of memory error when allocating a light\n");
2498 return E_OUTOFMEMORY;
2500 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2501 object->glIndex = -1;
2502 object->OriginalIndex = Index;
2503 object->changed = TRUE;
2506 /* Initialize the object */
2507 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2508 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2509 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2510 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2511 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2512 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2513 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2515 /* Save away the information */
2516 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2518 switch (pLight->Type) {
2519 case WINED3DLIGHT_POINT:
2520 /* Position */
2521 object->lightPosn[0] = pLight->Position.x;
2522 object->lightPosn[1] = pLight->Position.y;
2523 object->lightPosn[2] = pLight->Position.z;
2524 object->lightPosn[3] = 1.0f;
2525 object->cutoff = 180.0f;
2526 /* FIXME: Range */
2527 break;
2529 case WINED3DLIGHT_DIRECTIONAL:
2530 /* Direction */
2531 object->lightPosn[0] = -pLight->Direction.x;
2532 object->lightPosn[1] = -pLight->Direction.y;
2533 object->lightPosn[2] = -pLight->Direction.z;
2534 object->lightPosn[3] = 0.0;
2535 object->exponent = 0.0f;
2536 object->cutoff = 180.0f;
2537 break;
2539 case WINED3DLIGHT_SPOT:
2540 /* Position */
2541 object->lightPosn[0] = pLight->Position.x;
2542 object->lightPosn[1] = pLight->Position.y;
2543 object->lightPosn[2] = pLight->Position.z;
2544 object->lightPosn[3] = 1.0;
2546 /* Direction */
2547 object->lightDirn[0] = pLight->Direction.x;
2548 object->lightDirn[1] = pLight->Direction.y;
2549 object->lightDirn[2] = pLight->Direction.z;
2550 object->lightDirn[3] = 1.0;
2553 * opengl-ish and d3d-ish spot lights use too different models for the
2554 * light "intensity" as a function of the angle towards the main light direction,
2555 * so we only can approximate very roughly.
2556 * however spot lights are rather rarely used in games (if ever used at all).
2557 * furthermore if still used, probably nobody pays attention to such details.
2559 if (pLight->Falloff == 0) {
2560 rho = 6.28f;
2561 } else {
2562 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2564 if (rho < 0.0001) rho = 0.0001f;
2565 object->exponent = -0.3/log(cos(rho/2));
2566 if (object->exponent > 128.0) {
2567 object->exponent = 128.0;
2569 object->cutoff = pLight->Phi*90/M_PI;
2571 /* FIXME: Range */
2572 break;
2574 default:
2575 FIXME("Unrecognized light type %d\n", pLight->Type);
2578 /* Update the live definitions if the light is currently assigned a glIndex */
2579 if (object->glIndex != -1 && !This->isRecordingState) {
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2582 return WINED3D_OK;
2585 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2586 PLIGHTINFOEL *lightInfo = NULL;
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2589 struct list *e;
2590 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2592 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2593 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2594 if(lightInfo->OriginalIndex == Index) break;
2595 lightInfo = NULL;
2598 if (lightInfo == NULL) {
2599 TRACE("Light information requested but light not defined\n");
2600 return WINED3DERR_INVALIDCALL;
2603 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2604 return WINED3D_OK;
2607 /*****
2608 * Get / Set Light Enable
2609 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2610 *****/
2611 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2612 PLIGHTINFOEL *lightInfo = NULL;
2613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2614 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2615 struct list *e;
2616 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2618 /* Tests show true = 128...not clear why */
2619 Enable = Enable? 128: 0;
2621 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2622 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2623 if(lightInfo->OriginalIndex == Index) break;
2624 lightInfo = NULL;
2626 TRACE("Found light: %p\n", lightInfo);
2628 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2629 if (lightInfo == NULL) {
2631 TRACE("Light enabled requested but light not defined, so defining one!\n");
2632 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2634 /* Search for it again! Should be fairly quick as near head of list */
2635 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2636 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2637 if(lightInfo->OriginalIndex == Index) break;
2638 lightInfo = NULL;
2640 if (lightInfo == NULL) {
2641 FIXME("Adding default lights has failed dismally\n");
2642 return WINED3DERR_INVALIDCALL;
2646 lightInfo->enabledChanged = TRUE;
2647 if(!Enable) {
2648 if(lightInfo->glIndex != -1) {
2649 if(!This->isRecordingState) {
2650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2653 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2654 lightInfo->glIndex = -1;
2655 } else {
2656 TRACE("Light already disabled, nothing to do\n");
2658 } else {
2659 if (lightInfo->glIndex != -1) {
2660 /* nop */
2661 TRACE("Nothing to do as light was enabled\n");
2662 } else {
2663 int i;
2664 /* Find a free gl light */
2665 for(i = 0; i < This->maxConcurrentLights; i++) {
2666 if(This->stateBlock->activeLights[i] == NULL) {
2667 This->stateBlock->activeLights[i] = lightInfo;
2668 lightInfo->glIndex = i;
2669 break;
2672 if(lightInfo->glIndex == -1) {
2673 ERR("Too many concurrently active lights\n");
2674 return WINED3DERR_INVALIDCALL;
2677 /* i == lightInfo->glIndex */
2678 if(!This->isRecordingState) {
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2684 return WINED3D_OK;
2687 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2689 PLIGHTINFOEL *lightInfo = NULL;
2690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 struct list *e;
2692 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2693 TRACE("(%p) : for idx(%d)\n", This, Index);
2695 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2696 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2697 if(lightInfo->OriginalIndex == Index) break;
2698 lightInfo = NULL;
2701 if (lightInfo == NULL) {
2702 TRACE("Light enabled state requested but light not defined\n");
2703 return WINED3DERR_INVALIDCALL;
2705 /* true is 128 according to SetLightEnable */
2706 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2707 return WINED3D_OK;
2710 /*****
2711 * Get / Set Clip Planes
2712 *****/
2713 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2715 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2717 /* Validate Index */
2718 if (Index >= GL_LIMITS(clipplanes)) {
2719 TRACE("Application has requested clipplane this device doesn't support\n");
2720 return WINED3DERR_INVALIDCALL;
2723 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2725 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2726 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2727 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2728 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2729 TRACE("Application is setting old values over, nothing to do\n");
2730 return WINED3D_OK;
2733 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2734 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2735 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2736 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2738 /* Handle recording of state blocks */
2739 if (This->isRecordingState) {
2740 TRACE("Recording... not performing anything\n");
2741 return WINED3D_OK;
2744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2746 return WINED3D_OK;
2749 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2751 TRACE("(%p) : for idx %d\n", This, Index);
2753 /* Validate Index */
2754 if (Index >= GL_LIMITS(clipplanes)) {
2755 TRACE("Application has requested clipplane this device doesn't support\n");
2756 return WINED3DERR_INVALIDCALL;
2759 pPlane[0] = This->stateBlock->clipplane[Index][0];
2760 pPlane[1] = This->stateBlock->clipplane[Index][1];
2761 pPlane[2] = This->stateBlock->clipplane[Index][2];
2762 pPlane[3] = This->stateBlock->clipplane[Index][3];
2763 return WINED3D_OK;
2766 /*****
2767 * Get / Set Clip Plane Status
2768 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2769 *****/
2770 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 FIXME("(%p) : stub\n", This);
2773 if (NULL == pClipStatus) {
2774 return WINED3DERR_INVALIDCALL;
2776 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2777 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2778 return WINED3D_OK;
2781 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2783 FIXME("(%p) : stub\n", This);
2784 if (NULL == pClipStatus) {
2785 return WINED3DERR_INVALIDCALL;
2787 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2788 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2789 return WINED3D_OK;
2792 /*****
2793 * Get / Set Material
2794 *****/
2795 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2798 This->updateStateBlock->changed.material = TRUE;
2799 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2801 /* Handle recording of state blocks */
2802 if (This->isRecordingState) {
2803 TRACE("Recording... not performing anything\n");
2804 return WINED3D_OK;
2807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2808 return WINED3D_OK;
2811 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2814 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2815 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2816 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2817 pMaterial->Ambient.b, pMaterial->Ambient.a);
2818 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2819 pMaterial->Specular.b, pMaterial->Specular.a);
2820 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2821 pMaterial->Emissive.b, pMaterial->Emissive.a);
2822 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2824 return WINED3D_OK;
2827 /*****
2828 * Get / Set Indices
2829 *****/
2830 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2832 IWineD3DIndexBuffer *oldIdxs;
2834 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2835 oldIdxs = This->updateStateBlock->pIndexData;
2837 This->updateStateBlock->changed.indices = TRUE;
2838 This->updateStateBlock->pIndexData = pIndexData;
2840 /* Handle recording of state blocks */
2841 if (This->isRecordingState) {
2842 TRACE("Recording... not performing anything\n");
2843 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2844 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2845 return WINED3D_OK;
2848 if(oldIdxs != pIndexData) {
2849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2850 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2851 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2853 return WINED3D_OK;
2856 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 *ppIndexData = This->stateBlock->pIndexData;
2861 /* up ref count on ppindexdata */
2862 if (*ppIndexData) {
2863 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2864 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2865 }else{
2866 TRACE("(%p) No index data set\n", This);
2868 TRACE("Returning %p\n", *ppIndexData);
2870 return WINED3D_OK;
2873 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2874 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2876 TRACE("(%p)->(%d)\n", This, BaseIndex);
2878 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2879 TRACE("Application is setting the old value over, nothing to do\n");
2880 return WINED3D_OK;
2883 This->updateStateBlock->baseVertexIndex = BaseIndex;
2885 if (This->isRecordingState) {
2886 TRACE("Recording... not performing anything\n");
2887 return WINED3D_OK;
2889 /* The base vertex index affects the stream sources */
2890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2891 return WINED3D_OK;
2894 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 TRACE("(%p) : base_index %p\n", This, base_index);
2898 *base_index = This->stateBlock->baseVertexIndex;
2900 TRACE("Returning %u\n", *base_index);
2902 return WINED3D_OK;
2905 /*****
2906 * Get / Set Viewports
2907 *****/
2908 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2911 TRACE("(%p)\n", This);
2912 This->updateStateBlock->changed.viewport = TRUE;
2913 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2915 /* Handle recording of state blocks */
2916 if (This->isRecordingState) {
2917 TRACE("Recording... not performing anything\n");
2918 return WINED3D_OK;
2921 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2922 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2925 return WINED3D_OK;
2929 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2931 TRACE("(%p)\n", This);
2932 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2933 return WINED3D_OK;
2936 /*****
2937 * Get / Set Render States
2938 * TODO: Verify against dx9 definitions
2939 *****/
2940 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 DWORD oldValue = This->stateBlock->renderState[State];
2945 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2947 This->updateStateBlock->changed.renderState[State] = TRUE;
2948 This->updateStateBlock->renderState[State] = Value;
2950 /* Handle recording of state blocks */
2951 if (This->isRecordingState) {
2952 TRACE("Recording... not performing anything\n");
2953 return WINED3D_OK;
2956 /* Compared here and not before the assignment to allow proper stateblock recording */
2957 if(Value == oldValue) {
2958 TRACE("Application is setting the old value over, nothing to do\n");
2959 } else {
2960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2963 return WINED3D_OK;
2966 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2968 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2969 *pValue = This->stateBlock->renderState[State];
2970 return WINED3D_OK;
2973 /*****
2974 * Get / Set Sampler States
2975 * TODO: Verify against dx9 definitions
2976 *****/
2978 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 DWORD oldValue;
2982 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2983 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2985 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2986 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2990 * SetSampler is designed to allow for more than the standard up to 8 textures
2991 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2992 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2994 * http://developer.nvidia.com/object/General_FAQ.html#t6
2996 * There are two new settings for GForce
2997 * the sampler one:
2998 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2999 * and the texture one:
3000 * GL_MAX_TEXTURE_COORDS_ARB.
3001 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3002 ******************/
3004 oldValue = This->stateBlock->samplerState[Sampler][Type];
3005 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3006 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3008 /* Handle recording of state blocks */
3009 if (This->isRecordingState) {
3010 TRACE("Recording... not performing anything\n");
3011 return WINED3D_OK;
3014 if(oldValue == Value) {
3015 TRACE("Application is setting the old value over, nothing to do\n");
3016 return WINED3D_OK;
3019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3021 return WINED3D_OK;
3024 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3027 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3028 This, Sampler, debug_d3dsamplerstate(Type), Type);
3030 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3031 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3034 *Value = This->stateBlock->samplerState[Sampler][Type];
3035 TRACE("(%p) : Returning %#x\n", This, *Value);
3037 return WINED3D_OK;
3040 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 This->updateStateBlock->changed.scissorRect = TRUE;
3044 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3045 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3046 return WINED3D_OK;
3048 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3050 if(This->isRecordingState) {
3051 TRACE("Recording... not performing anything\n");
3052 return WINED3D_OK;
3055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3057 return WINED3D_OK;
3060 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3064 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3065 return WINED3D_OK;
3068 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3070 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3072 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3074 This->updateStateBlock->vertexDecl = pDecl;
3075 This->updateStateBlock->changed.vertexDecl = TRUE;
3077 if (This->isRecordingState) {
3078 TRACE("Recording... not performing anything\n");
3079 return WINED3D_OK;
3080 } else if(pDecl == oldDecl) {
3081 /* Checked after the assignment to allow proper stateblock recording */
3082 TRACE("Application is setting the old declaration over, nothing to do\n");
3083 return WINED3D_OK;
3086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3087 return WINED3D_OK;
3090 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3095 *ppDecl = This->stateBlock->vertexDecl;
3096 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3097 return WINED3D_OK;
3100 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3102 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3104 This->updateStateBlock->vertexShader = pShader;
3105 This->updateStateBlock->changed.vertexShader = TRUE;
3107 if (This->isRecordingState) {
3108 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3109 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3110 TRACE("Recording... not performing anything\n");
3111 return WINED3D_OK;
3112 } else if(oldShader == pShader) {
3113 /* Checked here to allow proper stateblock recording */
3114 TRACE("App is setting the old shader over, nothing to do\n");
3115 return WINED3D_OK;
3118 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3119 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3120 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3124 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 if (NULL == ppShader) {
3131 return WINED3DERR_INVALIDCALL;
3133 *ppShader = This->stateBlock->vertexShader;
3134 if( NULL != *ppShader)
3135 IWineD3DVertexShader_AddRef(*ppShader);
3137 TRACE("(%p) : returning %p\n", This, *ppShader);
3138 return WINED3D_OK;
3141 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3142 IWineD3DDevice *iface,
3143 UINT start,
3144 CONST BOOL *srcData,
3145 UINT count) {
3147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 int i, cnt = min(count, MAX_CONST_B - start);
3150 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3151 iface, srcData, start, count);
3153 if (srcData == NULL || cnt < 0)
3154 return WINED3DERR_INVALIDCALL;
3156 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3157 for (i = 0; i < cnt; i++)
3158 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3160 for (i = start; i < cnt + start; ++i) {
3161 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3164 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3166 return WINED3D_OK;
3169 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3170 IWineD3DDevice *iface,
3171 UINT start,
3172 BOOL *dstData,
3173 UINT count) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3176 int cnt = min(count, MAX_CONST_B - start);
3178 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3179 iface, dstData, start, count);
3181 if (dstData == NULL || cnt < 0)
3182 return WINED3DERR_INVALIDCALL;
3184 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3185 return WINED3D_OK;
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3189 IWineD3DDevice *iface,
3190 UINT start,
3191 CONST int *srcData,
3192 UINT count) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3195 int i, cnt = min(count, MAX_CONST_I - start);
3197 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3198 iface, srcData, start, count);
3200 if (srcData == NULL || cnt < 0)
3201 return WINED3DERR_INVALIDCALL;
3203 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3204 for (i = 0; i < cnt; i++)
3205 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3206 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3208 for (i = start; i < cnt + start; ++i) {
3209 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3214 return WINED3D_OK;
3217 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3218 IWineD3DDevice *iface,
3219 UINT start,
3220 int *dstData,
3221 UINT count) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 int cnt = min(count, MAX_CONST_I - start);
3226 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3227 iface, dstData, start, count);
3229 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3230 return WINED3DERR_INVALIDCALL;
3232 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3233 return WINED3D_OK;
3236 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3237 IWineD3DDevice *iface,
3238 UINT start,
3239 CONST float *srcData,
3240 UINT count) {
3242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3243 int i;
3245 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3246 iface, srcData, start, count);
3248 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3249 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3250 return WINED3DERR_INVALIDCALL;
3252 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3253 if(TRACE_ON(d3d)) {
3254 for (i = 0; i < count; i++)
3255 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3256 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3259 for (i = start; i < count + start; ++i) {
3260 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3261 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3262 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3263 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3264 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3266 ptr->idx[ptr->count++] = i;
3267 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3273 return WINED3D_OK;
3276 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3277 IWineD3DDevice *iface,
3278 UINT start,
3279 float *dstData,
3280 UINT count) {
3282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3285 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3286 iface, dstData, start, count);
3288 if (dstData == NULL || cnt < 0)
3289 return WINED3DERR_INVALIDCALL;
3291 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3292 return WINED3D_OK;
3295 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3296 DWORD i;
3297 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3302 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3303 int i = This->rev_tex_unit_map[unit];
3304 int j = This->texUnitMap[stage];
3306 This->texUnitMap[stage] = unit;
3307 if (i != -1 && i != stage) {
3308 This->texUnitMap[i] = -1;
3311 This->rev_tex_unit_map[unit] = stage;
3312 if (j != -1 && j != unit) {
3313 This->rev_tex_unit_map[j] = -1;
3317 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3318 int i;
3320 for (i = 0; i < MAX_TEXTURES; ++i) {
3321 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3322 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3323 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3324 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3325 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3326 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3327 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3328 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3330 if (color_op == WINED3DTOP_DISABLE) {
3331 /* Not used, and disable higher stages */
3332 while (i < MAX_TEXTURES) {
3333 This->fixed_function_usage_map[i] = FALSE;
3334 ++i;
3336 break;
3339 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3340 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3341 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3342 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3343 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3344 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3345 This->fixed_function_usage_map[i] = TRUE;
3346 } else {
3347 This->fixed_function_usage_map[i] = FALSE;
3350 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3351 This->fixed_function_usage_map[i+1] = TRUE;
3356 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3357 int i, tex;
3359 device_update_fixed_function_usage_map(This);
3361 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3362 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3363 if (!This->fixed_function_usage_map[i]) continue;
3365 if (This->texUnitMap[i] != i) {
3366 device_map_stage(This, i, i);
3367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3368 markTextureStagesDirty(This, i);
3371 return;
3374 /* Now work out the mapping */
3375 tex = 0;
3376 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3377 if (!This->fixed_function_usage_map[i]) continue;
3379 if (This->texUnitMap[i] != tex) {
3380 device_map_stage(This, i, tex);
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3382 markTextureStagesDirty(This, i);
3385 ++tex;
3389 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3390 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3391 int i;
3393 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3394 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3395 device_map_stage(This, i, i);
3396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3397 if (i < MAX_TEXTURES) {
3398 markTextureStagesDirty(This, i);
3404 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3405 int current_mapping = This->rev_tex_unit_map[unit];
3407 if (current_mapping == -1) {
3408 /* Not currently used */
3409 return TRUE;
3412 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3413 /* Used by a fragment sampler */
3415 if (!pshader_sampler_tokens) {
3416 /* No pixel shader, check fixed function */
3417 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3420 /* Pixel shader, check the shader's sampler map */
3421 return !pshader_sampler_tokens[current_mapping];
3424 /* Used by a vertex sampler */
3425 return !vshader_sampler_tokens[current_mapping];
3428 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3429 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3430 DWORD *pshader_sampler_tokens = NULL;
3431 int start = GL_LIMITS(combined_samplers) - 1;
3432 int i;
3434 if (ps) {
3435 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3437 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3438 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3439 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3442 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3443 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3444 if (vshader_sampler_tokens[i]) {
3445 if (This->texUnitMap[vsampler_idx] != -1) {
3446 /* Already mapped somewhere */
3447 continue;
3450 while (start >= 0) {
3451 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3452 device_map_stage(This, vsampler_idx, start);
3453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3455 --start;
3456 break;
3459 --start;
3465 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3466 BOOL vs = use_vs(This);
3467 BOOL ps = use_ps(This);
3469 * Rules are:
3470 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3471 * that would be really messy and require shader recompilation
3472 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3473 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3475 if (ps) {
3476 device_map_psamplers(This);
3477 } else {
3478 device_map_fixed_function_samplers(This);
3481 if (vs) {
3482 device_map_vsamplers(This, ps);
3486 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3489 This->updateStateBlock->pixelShader = pShader;
3490 This->updateStateBlock->changed.pixelShader = TRUE;
3492 /* Handle recording of state blocks */
3493 if (This->isRecordingState) {
3494 TRACE("Recording... not performing anything\n");
3497 if (This->isRecordingState) {
3498 TRACE("Recording... not performing anything\n");
3499 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3500 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3501 return WINED3D_OK;
3504 if(pShader == oldShader) {
3505 TRACE("App is setting the old pixel shader over, nothing to do\n");
3506 return WINED3D_OK;
3509 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3510 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3512 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3515 return WINED3D_OK;
3518 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3521 if (NULL == ppShader) {
3522 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3523 return WINED3DERR_INVALIDCALL;
3526 *ppShader = This->stateBlock->pixelShader;
3527 if (NULL != *ppShader) {
3528 IWineD3DPixelShader_AddRef(*ppShader);
3530 TRACE("(%p) : returning %p\n", This, *ppShader);
3531 return WINED3D_OK;
3534 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3535 IWineD3DDevice *iface,
3536 UINT start,
3537 CONST BOOL *srcData,
3538 UINT count) {
3540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3541 int i, cnt = min(count, MAX_CONST_B - start);
3543 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3544 iface, srcData, start, count);
3546 if (srcData == NULL || cnt < 0)
3547 return WINED3DERR_INVALIDCALL;
3549 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3550 for (i = 0; i < cnt; i++)
3551 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3553 for (i = start; i < cnt + start; ++i) {
3554 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3559 return WINED3D_OK;
3562 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3563 IWineD3DDevice *iface,
3564 UINT start,
3565 BOOL *dstData,
3566 UINT count) {
3568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3569 int cnt = min(count, MAX_CONST_B - start);
3571 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3572 iface, dstData, start, count);
3574 if (dstData == NULL || cnt < 0)
3575 return WINED3DERR_INVALIDCALL;
3577 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3578 return WINED3D_OK;
3581 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3582 IWineD3DDevice *iface,
3583 UINT start,
3584 CONST int *srcData,
3585 UINT count) {
3587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3588 int i, cnt = min(count, MAX_CONST_I - start);
3590 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3591 iface, srcData, start, count);
3593 if (srcData == NULL || cnt < 0)
3594 return WINED3DERR_INVALIDCALL;
3596 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3597 for (i = 0; i < cnt; i++)
3598 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3599 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3601 for (i = start; i < cnt + start; ++i) {
3602 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3607 return WINED3D_OK;
3610 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3611 IWineD3DDevice *iface,
3612 UINT start,
3613 int *dstData,
3614 UINT count) {
3616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3617 int cnt = min(count, MAX_CONST_I - start);
3619 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3620 iface, dstData, start, count);
3622 if (dstData == NULL || cnt < 0)
3623 return WINED3DERR_INVALIDCALL;
3625 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3626 return WINED3D_OK;
3629 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3630 IWineD3DDevice *iface,
3631 UINT start,
3632 CONST float *srcData,
3633 UINT count) {
3635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3636 int i;
3638 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3639 iface, srcData, start, count);
3641 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3642 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3643 return WINED3DERR_INVALIDCALL;
3645 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3646 if(TRACE_ON(d3d)) {
3647 for (i = 0; i < count; i++)
3648 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3649 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3652 for (i = start; i < count + start; ++i) {
3653 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3654 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3655 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3656 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3657 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3659 ptr->idx[ptr->count++] = i;
3660 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3666 return WINED3D_OK;
3669 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3670 IWineD3DDevice *iface,
3671 UINT start,
3672 float *dstData,
3673 UINT count) {
3675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3676 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3678 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3679 iface, dstData, start, count);
3681 if (dstData == NULL || cnt < 0)
3682 return WINED3DERR_INVALIDCALL;
3684 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3685 return WINED3D_OK;
3688 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3689 static HRESULT
3690 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3691 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3692 unsigned int i;
3693 DWORD DestFVF = dest->fvf;
3694 WINED3DVIEWPORT vp;
3695 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3696 BOOL doClip;
3697 int numTextures;
3699 if (lpStrideData->u.s.normal.lpData) {
3700 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3703 if (lpStrideData->u.s.position.lpData == NULL) {
3704 ERR("Source has no position mask\n");
3705 return WINED3DERR_INVALIDCALL;
3708 /* We might access VBOs from this code, so hold the lock */
3709 ENTER_GL();
3711 if (dest->resource.allocatedMemory == NULL) {
3712 /* This may happen if we do direct locking into a vbo. Unlikely,
3713 * but theoretically possible(ddraw processvertices test)
3715 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3716 if(!dest->resource.allocatedMemory) {
3717 LEAVE_GL();
3718 ERR("Out of memory\n");
3719 return E_OUTOFMEMORY;
3721 if(dest->vbo) {
3722 void *src;
3723 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3724 checkGLcall("glBindBufferARB");
3725 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3726 if(src) {
3727 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3729 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3730 checkGLcall("glUnmapBufferARB");
3734 /* Get a pointer into the destination vbo(create one if none exists) and
3735 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3737 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3738 CreateVBO(dest);
3741 if(dest->vbo) {
3742 unsigned char extrabytes = 0;
3743 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3744 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3745 * this may write 4 extra bytes beyond the area that should be written
3747 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3748 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3749 if(!dest_conv_addr) {
3750 ERR("Out of memory\n");
3751 /* Continue without storing converted vertices */
3753 dest_conv = dest_conv_addr;
3756 /* Should I clip?
3757 * a) WINED3DRS_CLIPPING is enabled
3758 * b) WINED3DVOP_CLIP is passed
3760 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3761 static BOOL warned = FALSE;
3763 * The clipping code is not quite correct. Some things need
3764 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3765 * so disable clipping for now.
3766 * (The graphics in Half-Life are broken, and my processvertices
3767 * test crashes with IDirect3DDevice3)
3768 doClip = TRUE;
3770 doClip = FALSE;
3771 if(!warned) {
3772 warned = TRUE;
3773 FIXME("Clipping is broken and disabled for now\n");
3775 } else doClip = FALSE;
3776 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3778 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3779 WINED3DTS_VIEW,
3780 &view_mat);
3781 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3782 WINED3DTS_PROJECTION,
3783 &proj_mat);
3784 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3785 WINED3DTS_WORLDMATRIX(0),
3786 &world_mat);
3788 TRACE("View mat:\n");
3789 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
3790 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
3791 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
3792 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
3794 TRACE("Proj mat:\n");
3795 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
3796 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
3797 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
3798 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
3800 TRACE("World mat:\n");
3801 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
3802 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
3803 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
3804 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
3806 /* Get the viewport */
3807 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3808 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3809 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3811 multiply_matrix(&mat,&view_mat,&world_mat);
3812 multiply_matrix(&mat,&proj_mat,&mat);
3814 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3816 for (i = 0; i < dwCount; i+= 1) {
3817 unsigned int tex_index;
3819 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3820 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3821 /* The position first */
3822 float *p =
3823 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3824 float x, y, z, rhw;
3825 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3827 /* Multiplication with world, view and projection matrix */
3828 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
3829 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
3830 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
3831 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
3833 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3835 /* WARNING: The following things are taken from d3d7 and were not yet checked
3836 * against d3d8 or d3d9!
3839 /* Clipping conditions: From
3840 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3842 * A vertex is clipped if it does not match the following requirements
3843 * -rhw < x <= rhw
3844 * -rhw < y <= rhw
3845 * 0 < z <= rhw
3846 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3848 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3849 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3853 if( !doClip ||
3854 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3855 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3856 ( rhw > eps ) ) ) {
3858 /* "Normal" viewport transformation (not clipped)
3859 * 1) The values are divided by rhw
3860 * 2) The y axis is negative, so multiply it with -1
3861 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3862 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3863 * 4) Multiply x with Width/2 and add Width/2
3864 * 5) The same for the height
3865 * 6) Add the viewpoint X and Y to the 2D coordinates and
3866 * The minimum Z value to z
3867 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3869 * Well, basically it's simply a linear transformation into viewport
3870 * coordinates
3873 x /= rhw;
3874 y /= rhw;
3875 z /= rhw;
3877 y *= -1;
3879 x *= vp.Width / 2;
3880 y *= vp.Height / 2;
3881 z *= vp.MaxZ - vp.MinZ;
3883 x += vp.Width / 2 + vp.X;
3884 y += vp.Height / 2 + vp.Y;
3885 z += vp.MinZ;
3887 rhw = 1 / rhw;
3888 } else {
3889 /* That vertex got clipped
3890 * Contrary to OpenGL it is not dropped completely, it just
3891 * undergoes a different calculation.
3893 TRACE("Vertex got clipped\n");
3894 x += rhw;
3895 y += rhw;
3897 x /= 2;
3898 y /= 2;
3900 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3901 * outside of the main vertex buffer memory. That needs some more
3902 * investigation...
3906 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3909 ( (float *) dest_ptr)[0] = x;
3910 ( (float *) dest_ptr)[1] = y;
3911 ( (float *) dest_ptr)[2] = z;
3912 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3914 dest_ptr += 3 * sizeof(float);
3916 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3917 dest_ptr += sizeof(float);
3920 if(dest_conv) {
3921 float w = 1 / rhw;
3922 ( (float *) dest_conv)[0] = x * w;
3923 ( (float *) dest_conv)[1] = y * w;
3924 ( (float *) dest_conv)[2] = z * w;
3925 ( (float *) dest_conv)[3] = w;
3927 dest_conv += 3 * sizeof(float);
3929 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3930 dest_conv += sizeof(float);
3934 if (DestFVF & WINED3DFVF_PSIZE) {
3935 dest_ptr += sizeof(DWORD);
3936 if(dest_conv) dest_conv += sizeof(DWORD);
3938 if (DestFVF & WINED3DFVF_NORMAL) {
3939 float *normal =
3940 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3941 /* AFAIK this should go into the lighting information */
3942 FIXME("Didn't expect the destination to have a normal\n");
3943 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3944 if(dest_conv) {
3945 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3949 if (DestFVF & WINED3DFVF_DIFFUSE) {
3950 DWORD *color_d =
3951 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3952 if(!color_d) {
3953 static BOOL warned = FALSE;
3955 if(!warned) {
3956 ERR("No diffuse color in source, but destination has one\n");
3957 warned = TRUE;
3960 *( (DWORD *) dest_ptr) = 0xffffffff;
3961 dest_ptr += sizeof(DWORD);
3963 if(dest_conv) {
3964 *( (DWORD *) dest_conv) = 0xffffffff;
3965 dest_conv += sizeof(DWORD);
3968 else {
3969 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3970 if(dest_conv) {
3971 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3972 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3973 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3974 dest_conv += sizeof(DWORD);
3979 if (DestFVF & WINED3DFVF_SPECULAR) {
3980 /* What's the color value in the feedback buffer? */
3981 DWORD *color_s =
3982 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3983 if(!color_s) {
3984 static BOOL warned = FALSE;
3986 if(!warned) {
3987 ERR("No specular color in source, but destination has one\n");
3988 warned = TRUE;
3991 *( (DWORD *) dest_ptr) = 0xFF000000;
3992 dest_ptr += sizeof(DWORD);
3994 if(dest_conv) {
3995 *( (DWORD *) dest_conv) = 0xFF000000;
3996 dest_conv += sizeof(DWORD);
3999 else {
4000 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4001 if(dest_conv) {
4002 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4003 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4004 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4005 dest_conv += sizeof(DWORD);
4010 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4011 float *tex_coord =
4012 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4013 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4014 if(!tex_coord) {
4015 ERR("No source texture, but destination requests one\n");
4016 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4017 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4019 else {
4020 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4021 if(dest_conv) {
4022 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4028 if(dest_conv) {
4029 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4030 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4031 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4032 dwCount * get_flexible_vertex_size(DestFVF),
4033 dest_conv_addr));
4034 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4035 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4038 LEAVE_GL();
4040 return WINED3D_OK;
4042 #undef copy_and_next
4044 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4046 WineDirect3DVertexStridedData strided;
4047 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4048 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4050 if(pVertexDecl) {
4051 ERR("Output vertex declaration not implemented yet\n");
4054 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4055 * and this call is quite performance critical, so don't call needlessly
4057 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4058 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4061 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4062 * control the streamIsUP flag, thus restore it afterwards.
4064 This->stateBlock->streamIsUP = FALSE;
4065 memset(&strided, 0, sizeof(strided));
4066 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4067 This->stateBlock->streamIsUP = streamWasUP;
4069 if(vbo || SrcStartIndex) {
4070 unsigned int i;
4071 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4072 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4074 * Also get the start index in, but only loop over all elements if there's something to add at all.
4076 #define FIXSRC(type) \
4077 if(strided.u.s.type.VBO) { \
4078 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4079 strided.u.s.type.VBO = 0; \
4080 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4081 ENTER_GL(); \
4082 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4083 vb->vbo = 0; \
4084 LEAVE_GL(); \
4086 if(strided.u.s.type.lpData) { \
4087 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4089 FIXSRC(position);
4090 FIXSRC(blendWeights);
4091 FIXSRC(blendMatrixIndices);
4092 FIXSRC(normal);
4093 FIXSRC(pSize);
4094 FIXSRC(diffuse);
4095 FIXSRC(specular);
4096 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4097 FIXSRC(texCoords[i]);
4099 FIXSRC(position2);
4100 FIXSRC(normal2);
4101 FIXSRC(tangent);
4102 FIXSRC(binormal);
4103 FIXSRC(tessFactor);
4104 FIXSRC(fog);
4105 FIXSRC(depth);
4106 FIXSRC(sample);
4107 #undef FIXSRC
4110 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4113 /*****
4114 * Get / Set Texture Stage States
4115 * TODO: Verify against dx9 definitions
4116 *****/
4117 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4119 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4121 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4123 if (Stage >= MAX_TEXTURES) {
4124 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4125 return WINED3D_OK;
4128 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4129 This->updateStateBlock->textureState[Stage][Type] = Value;
4131 if (This->isRecordingState) {
4132 TRACE("Recording... not performing anything\n");
4133 return WINED3D_OK;
4136 /* Checked after the assignments to allow proper stateblock recording */
4137 if(oldValue == Value) {
4138 TRACE("App is setting the old value over, nothing to do\n");
4139 return WINED3D_OK;
4142 if(Stage > This->stateBlock->lowest_disabled_stage &&
4143 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4144 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4145 * Changes in other states are important on disabled stages too
4147 return WINED3D_OK;
4150 if(Type == WINED3DTSS_COLOROP) {
4151 int i;
4153 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4154 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4155 * they have to be disabled
4157 * The current stage is dirtified below.
4159 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4160 TRACE("Additionally dirtifying stage %d\n", i);
4161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4163 This->stateBlock->lowest_disabled_stage = Stage;
4164 TRACE("New lowest disabled: %d\n", Stage);
4165 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4166 /* Previously disabled stage enabled. Stages above it may need enabling
4167 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4168 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4170 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4173 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4174 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4175 break;
4177 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4180 This->stateBlock->lowest_disabled_stage = i;
4181 TRACE("New lowest disabled: %d\n", i);
4183 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4184 /* TODO: Built a stage -> texture unit mapping for register combiners */
4188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4190 return WINED3D_OK;
4193 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4195 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4196 *pValue = This->updateStateBlock->textureState[Stage][Type];
4197 return WINED3D_OK;
4200 /*****
4201 * Get / Set Texture
4202 *****/
4203 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4205 IWineD3DBaseTexture *oldTexture;
4207 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4209 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4210 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4213 oldTexture = This->updateStateBlock->textures[Stage];
4215 if(pTexture != NULL) {
4216 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4218 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4219 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4220 return WINED3DERR_INVALIDCALL;
4222 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4225 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4226 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4228 This->updateStateBlock->changed.textures[Stage] = TRUE;
4229 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4230 This->updateStateBlock->textures[Stage] = pTexture;
4232 /* Handle recording of state blocks */
4233 if (This->isRecordingState) {
4234 TRACE("Recording... not performing anything\n");
4235 return WINED3D_OK;
4238 if(oldTexture == pTexture) {
4239 TRACE("App is setting the same texture again, nothing to do\n");
4240 return WINED3D_OK;
4243 /** NOTE: MSDN says that setTexture increases the reference count,
4244 * and the the application must set the texture back to null (or have a leaky application),
4245 * This means we should pass the refcount up to the parent
4246 *******************************/
4247 if (NULL != This->updateStateBlock->textures[Stage]) {
4248 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4249 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4251 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4252 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4253 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4254 * so the COLOROP and ALPHAOP have to be dirtified.
4256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4259 if(bindCount == 1) {
4260 new->baseTexture.sampler = Stage;
4262 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4266 if (NULL != oldTexture) {
4267 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4268 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4270 IWineD3DBaseTexture_Release(oldTexture);
4271 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4276 if(bindCount && old->baseTexture.sampler == Stage) {
4277 int i;
4278 /* Have to do a search for the other sampler(s) where the texture is bound to
4279 * Shouldn't happen as long as apps bind a texture only to one stage
4281 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4282 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4283 if(This->updateStateBlock->textures[i] == oldTexture) {
4284 old->baseTexture.sampler = i;
4285 break;
4291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4293 return WINED3D_OK;
4296 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4299 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4301 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4302 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4305 *ppTexture=This->stateBlock->textures[Stage];
4306 if (*ppTexture)
4307 IWineD3DBaseTexture_AddRef(*ppTexture);
4309 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4311 return WINED3D_OK;
4314 /*****
4315 * Get Back Buffer
4316 *****/
4317 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4318 IWineD3DSurface **ppBackBuffer) {
4319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4320 IWineD3DSwapChain *swapChain;
4321 HRESULT hr;
4323 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4325 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4326 if (hr == WINED3D_OK) {
4327 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4328 IWineD3DSwapChain_Release(swapChain);
4329 } else {
4330 *ppBackBuffer = NULL;
4332 return hr;
4335 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4337 WARN("(%p) : stub, calling idirect3d for now\n", This);
4338 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4341 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4343 IWineD3DSwapChain *swapChain;
4344 HRESULT hr;
4346 if(iSwapChain > 0) {
4347 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4348 if (hr == WINED3D_OK) {
4349 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4350 IWineD3DSwapChain_Release(swapChain);
4351 } else {
4352 FIXME("(%p) Error getting display mode\n", This);
4354 } else {
4355 /* Don't read the real display mode,
4356 but return the stored mode instead. X11 can't change the color
4357 depth, and some apps are pretty angry if they SetDisplayMode from
4358 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4360 Also don't relay to the swapchain because with ddraw it's possible
4361 that there isn't a swapchain at all */
4362 pMode->Width = This->ddraw_width;
4363 pMode->Height = This->ddraw_height;
4364 pMode->Format = This->ddraw_format;
4365 pMode->RefreshRate = 0;
4366 hr = WINED3D_OK;
4369 return hr;
4372 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4374 TRACE("(%p)->(%p)\n", This, hWnd);
4376 if(This->ddraw_fullscreen) {
4377 if(This->ddraw_window && This->ddraw_window != hWnd) {
4378 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4380 if(hWnd && This->ddraw_window != hWnd) {
4381 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4385 This->ddraw_window = hWnd;
4386 return WINED3D_OK;
4389 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4391 TRACE("(%p)->(%p)\n", This, hWnd);
4393 *hWnd = This->ddraw_window;
4394 return WINED3D_OK;
4397 /*****
4398 * Stateblock related functions
4399 *****/
4401 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4403 IWineD3DStateBlockImpl *object;
4404 HRESULT temp_result;
4405 int i;
4407 TRACE("(%p)\n", This);
4409 if (This->isRecordingState) {
4410 return WINED3DERR_INVALIDCALL;
4413 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4414 if (NULL == object ) {
4415 FIXME("(%p)Error allocating memory for stateblock\n", This);
4416 return E_OUTOFMEMORY;
4418 TRACE("(%p) created object %p\n", This, object);
4419 object->wineD3DDevice= This;
4420 /** FIXME: object->parent = parent; **/
4421 object->parent = NULL;
4422 object->blockType = WINED3DSBT_RECORDED;
4423 object->ref = 1;
4424 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4427 list_init(&object->lightMap[i]);
4430 temp_result = allocate_shader_constants(object);
4431 if (WINED3D_OK != temp_result)
4432 return temp_result;
4434 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4435 This->updateStateBlock = object;
4436 This->isRecordingState = TRUE;
4438 TRACE("(%p) recording stateblock %p\n",This , object);
4439 return WINED3D_OK;
4442 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4444 unsigned int i, j;
4445 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4447 if (!This->isRecordingState) {
4448 FIXME("(%p) not recording! returning error\n", This);
4449 *ppStateBlock = NULL;
4450 return WINED3DERR_INVALIDCALL;
4453 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4454 if(object->changed.renderState[i]) {
4455 object->contained_render_states[object->num_contained_render_states] = i;
4456 object->num_contained_render_states++;
4459 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4460 if(object->changed.transform[i]) {
4461 object->contained_transform_states[object->num_contained_transform_states] = i;
4462 object->num_contained_transform_states++;
4465 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4466 if(object->changed.vertexShaderConstantsF[i]) {
4467 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4468 object->num_contained_vs_consts_f++;
4471 for(i = 0; i < MAX_CONST_I; i++) {
4472 if(object->changed.vertexShaderConstantsI[i]) {
4473 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4474 object->num_contained_vs_consts_i++;
4477 for(i = 0; i < MAX_CONST_B; i++) {
4478 if(object->changed.vertexShaderConstantsB[i]) {
4479 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4480 object->num_contained_vs_consts_b++;
4483 for(i = 0; i < MAX_CONST_I; i++) {
4484 if(object->changed.pixelShaderConstantsI[i]) {
4485 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4486 object->num_contained_ps_consts_i++;
4489 for(i = 0; i < MAX_CONST_B; i++) {
4490 if(object->changed.pixelShaderConstantsB[i]) {
4491 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4492 object->num_contained_ps_consts_b++;
4495 for(i = 0; i < MAX_TEXTURES; i++) {
4496 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4497 if(object->changed.textureState[i][j]) {
4498 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4499 object->contained_tss_states[object->num_contained_tss_states].state = j;
4500 object->num_contained_tss_states++;
4504 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4505 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4506 if(object->changed.samplerState[i][j]) {
4507 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4508 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4509 object->num_contained_sampler_states++;
4514 *ppStateBlock = (IWineD3DStateBlock*) object;
4515 This->isRecordingState = FALSE;
4516 This->updateStateBlock = This->stateBlock;
4517 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4518 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4519 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4520 return WINED3D_OK;
4523 /*****
4524 * Scene related functions
4525 *****/
4526 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4527 /* At the moment we have no need for any functionality at the beginning
4528 of a scene */
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 TRACE("(%p)\n", This);
4532 if(This->inScene) {
4533 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4534 return WINED3DERR_INVALIDCALL;
4536 This->inScene = TRUE;
4537 return WINED3D_OK;
4540 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 TRACE("(%p)\n", This);
4544 if(!This->inScene) {
4545 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4546 return WINED3DERR_INVALIDCALL;
4549 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4550 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4552 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4553 ENTER_GL();
4554 glFlush();
4555 checkGLcall("glFlush");
4556 LEAVE_GL();
4558 This->inScene = FALSE;
4559 return WINED3D_OK;
4562 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4563 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4564 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 IWineD3DSwapChain *swapChain = NULL;
4567 int i;
4568 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4570 TRACE("(%p) Presenting the frame\n", This);
4572 for(i = 0 ; i < swapchains ; i ++) {
4574 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4575 TRACE("presentinng chain %d, %p\n", i, swapChain);
4576 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4577 IWineD3DSwapChain_Release(swapChain);
4580 return WINED3D_OK;
4583 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4584 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4588 GLbitfield glMask = 0;
4589 unsigned int i;
4590 CONST WINED3DRECT* curRect;
4592 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4593 Count, pRects, Flags, Color, Z, Stencil);
4595 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4596 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4597 /* TODO: What about depth stencil buffers without stencil bits? */
4598 return WINED3DERR_INVALIDCALL;
4601 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4602 * and not the last active one.
4604 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4605 ENTER_GL();
4607 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4608 apply_fbo_state(iface);
4611 if (Count > 0 && pRects) {
4612 curRect = pRects;
4613 } else {
4614 curRect = NULL;
4617 /* Only set the values up once, as they are not changing */
4618 if (Flags & WINED3DCLEAR_STENCIL) {
4619 glClearStencil(Stencil);
4620 checkGLcall("glClearStencil");
4621 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4622 glStencilMask(0xFFFFFFFF);
4625 if (Flags & WINED3DCLEAR_ZBUFFER) {
4626 glDepthMask(GL_TRUE);
4627 glClearDepth(Z);
4628 checkGLcall("glClearDepth");
4629 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4633 if (Flags & WINED3DCLEAR_TARGET) {
4634 TRACE("Clearing screen with glClear to color %x\n", Color);
4635 glClearColor(D3DCOLOR_R(Color),
4636 D3DCOLOR_G(Color),
4637 D3DCOLOR_B(Color),
4638 D3DCOLOR_A(Color));
4639 checkGLcall("glClearColor");
4641 /* Clear ALL colors! */
4642 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4643 glMask = glMask | GL_COLOR_BUFFER_BIT;
4646 if (!curRect) {
4647 /* In drawable flag is set below */
4649 if (This->render_offscreen) {
4650 glScissor(This->stateBlock->viewport.X,
4651 This->stateBlock->viewport.Y,
4652 This->stateBlock->viewport.Width,
4653 This->stateBlock->viewport.Height);
4654 } else {
4655 glScissor(This->stateBlock->viewport.X,
4656 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4657 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4658 This->stateBlock->viewport.Width,
4659 This->stateBlock->viewport.Height);
4661 checkGLcall("glScissor");
4662 glClear(glMask);
4663 checkGLcall("glClear");
4664 } else {
4665 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4666 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4668 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4669 curRect[0].x2 < target->currentDesc.Width ||
4670 curRect[0].y2 < target->currentDesc.Height) {
4671 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4672 blt_to_drawable(This, target);
4676 /* Now process each rect in turn */
4677 for (i = 0; i < Count; i++) {
4678 /* Note gl uses lower left, width/height */
4679 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4680 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4681 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4682 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4684 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4685 * The rectangle is not cleared, no error is returned, but further rectanlges are
4686 * still cleared if they are valid
4688 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4689 TRACE("Rectangle with negative dimensions, ignoring\n");
4690 continue;
4693 if(This->render_offscreen) {
4694 glScissor(curRect[i].x1, curRect[i].y1,
4695 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4696 } else {
4697 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4698 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4700 checkGLcall("glScissor");
4702 glClear(glMask);
4703 checkGLcall("glClear");
4707 /* Restore the old values (why..?) */
4708 if (Flags & WINED3DCLEAR_STENCIL) {
4709 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4711 if (Flags & WINED3DCLEAR_TARGET) {
4712 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4713 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4714 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4715 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4716 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4719 LEAVE_GL();
4721 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4722 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4724 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4725 target->Flags |= SFLAG_INTEXTURE;
4726 target->Flags &= ~SFLAG_INSYSMEM;
4727 } else {
4728 target->Flags |= SFLAG_INDRAWABLE;
4729 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4731 return WINED3D_OK;
4734 /*****
4735 * Drawing functions
4736 *****/
4737 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4738 UINT PrimitiveCount) {
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4742 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4743 debug_d3dprimitivetype(PrimitiveType),
4744 StartVertex, PrimitiveCount);
4746 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4747 if(This->stateBlock->streamIsUP) {
4748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4749 This->stateBlock->streamIsUP = FALSE;
4752 if(This->stateBlock->loadBaseVertexIndex != 0) {
4753 This->stateBlock->loadBaseVertexIndex = 0;
4754 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4756 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4757 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4758 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4759 return WINED3D_OK;
4762 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4763 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4764 WINED3DPRIMITIVETYPE PrimitiveType,
4765 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 UINT idxStride = 2;
4769 IWineD3DIndexBuffer *pIB;
4770 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4771 GLuint vbo;
4773 pIB = This->stateBlock->pIndexData;
4774 if (!pIB) {
4775 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4776 * without an index buffer set. (The first time at least...)
4777 * D3D8 simply dies, but I doubt it can do much harm to return
4778 * D3DERR_INVALIDCALL there as well. */
4779 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4780 return WINED3DERR_INVALIDCALL;
4783 if(This->stateBlock->streamIsUP) {
4784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4785 This->stateBlock->streamIsUP = FALSE;
4787 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4789 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4790 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4791 minIndex, NumVertices, startIndex, primCount);
4793 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4794 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4795 idxStride = 2;
4796 } else {
4797 idxStride = 4;
4800 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4801 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4805 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4806 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4808 return WINED3D_OK;
4811 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4812 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4813 UINT VertexStreamZeroStride) {
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4815 IWineD3DVertexBuffer *vb;
4817 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4818 debug_d3dprimitivetype(PrimitiveType),
4819 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4821 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4822 vb = This->stateBlock->streamSource[0];
4823 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4824 if(vb) IWineD3DVertexBuffer_Release(vb);
4825 This->stateBlock->streamOffset[0] = 0;
4826 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4827 This->stateBlock->streamIsUP = TRUE;
4828 This->stateBlock->loadBaseVertexIndex = 0;
4830 /* TODO: Only mark dirty if drawing from a different UP address */
4831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4833 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4834 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4836 /* MSDN specifies stream zero settings must be set to NULL */
4837 This->stateBlock->streamStride[0] = 0;
4838 This->stateBlock->streamSource[0] = NULL;
4840 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4841 * the new stream sources or use UP drawing again
4843 return WINED3D_OK;
4846 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4847 UINT MinVertexIndex, UINT NumVertices,
4848 UINT PrimitiveCount, CONST void* pIndexData,
4849 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4850 UINT VertexStreamZeroStride) {
4851 int idxStride;
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 IWineD3DVertexBuffer *vb;
4854 IWineD3DIndexBuffer *ib;
4856 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4857 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4858 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4859 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4861 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4862 idxStride = 2;
4863 } else {
4864 idxStride = 4;
4867 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4868 vb = This->stateBlock->streamSource[0];
4869 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4870 if(vb) IWineD3DVertexBuffer_Release(vb);
4871 This->stateBlock->streamIsUP = TRUE;
4872 This->stateBlock->streamOffset[0] = 0;
4873 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4875 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4876 This->stateBlock->baseVertexIndex = 0;
4877 This->stateBlock->loadBaseVertexIndex = 0;
4878 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4882 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4884 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4885 This->stateBlock->streamSource[0] = NULL;
4886 This->stateBlock->streamStride[0] = 0;
4887 ib = This->stateBlock->pIndexData;
4888 if(ib) {
4889 IWineD3DIndexBuffer_Release(ib);
4890 This->stateBlock->pIndexData = NULL;
4892 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4893 * SetStreamSource to specify a vertex buffer
4896 return WINED3D_OK;
4899 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4902 /* Mark the state dirty until we have nicer tracking
4903 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4904 * that value.
4906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4908 This->stateBlock->baseVertexIndex = 0;
4909 This->up_strided = DrawPrimStrideData;
4910 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4911 This->up_strided = NULL;
4912 return WINED3D_OK;
4915 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4917 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4919 /* Mark the state dirty until we have nicer tracking
4920 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4921 * that value.
4923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4925 This->stateBlock->streamIsUP = TRUE;
4926 This->stateBlock->baseVertexIndex = 0;
4927 This->up_strided = DrawPrimStrideData;
4928 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4929 This->up_strided = NULL;
4930 return WINED3D_OK;
4934 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4935 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4937 HRESULT hr = WINED3D_OK;
4938 WINED3DRESOURCETYPE sourceType;
4939 WINED3DRESOURCETYPE destinationType;
4940 int i ,levels;
4942 /* TODO: think about moving the code into IWineD3DBaseTexture */
4944 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4946 /* verify that the source and destination textures aren't NULL */
4947 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4948 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4949 This, pSourceTexture, pDestinationTexture);
4950 hr = WINED3DERR_INVALIDCALL;
4953 if (pSourceTexture == pDestinationTexture) {
4954 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4955 This, pSourceTexture, pDestinationTexture);
4956 hr = WINED3DERR_INVALIDCALL;
4958 /* Verify that the source and destination textures are the same type */
4959 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4960 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4962 if (sourceType != destinationType) {
4963 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4964 This);
4965 hr = WINED3DERR_INVALIDCALL;
4968 /* check that both textures have the identical numbers of levels */
4969 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4970 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4971 hr = WINED3DERR_INVALIDCALL;
4974 if (WINED3D_OK == hr) {
4976 /* Make sure that the destination texture is loaded */
4977 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4979 /* Update every surface level of the texture */
4980 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4982 switch (sourceType) {
4983 case WINED3DRTYPE_TEXTURE:
4985 IWineD3DSurface *srcSurface;
4986 IWineD3DSurface *destSurface;
4988 for (i = 0 ; i < levels ; ++i) {
4989 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4990 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4991 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4992 IWineD3DSurface_Release(srcSurface);
4993 IWineD3DSurface_Release(destSurface);
4994 if (WINED3D_OK != hr) {
4995 WARN("(%p) : Call to update surface failed\n", This);
4996 return hr;
5000 break;
5001 case WINED3DRTYPE_CUBETEXTURE:
5003 IWineD3DSurface *srcSurface;
5004 IWineD3DSurface *destSurface;
5005 WINED3DCUBEMAP_FACES faceType;
5007 for (i = 0 ; i < levels ; ++i) {
5008 /* Update each cube face */
5009 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5010 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5011 if (WINED3D_OK != hr) {
5012 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5013 } else {
5014 TRACE("Got srcSurface %p\n", srcSurface);
5016 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5017 if (WINED3D_OK != hr) {
5018 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5019 } else {
5020 TRACE("Got desrSurface %p\n", destSurface);
5022 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5023 IWineD3DSurface_Release(srcSurface);
5024 IWineD3DSurface_Release(destSurface);
5025 if (WINED3D_OK != hr) {
5026 WARN("(%p) : Call to update surface failed\n", This);
5027 return hr;
5032 break;
5033 #if 0 /* TODO: Add support for volume textures */
5034 case WINED3DRTYPE_VOLUMETEXTURE:
5036 IWineD3DVolume srcVolume = NULL;
5037 IWineD3DSurface destVolume = NULL;
5039 for (i = 0 ; i < levels ; ++i) {
5040 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5041 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5042 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5043 IWineD3DVolume_Release(srcSurface);
5044 IWineD3DVolume_Release(destSurface);
5045 if (WINED3D_OK != hr) {
5046 WARN("(%p) : Call to update volume failed\n", This);
5047 return hr;
5051 break;
5052 #endif
5053 default:
5054 FIXME("(%p) : Unsupported source and destination type\n", This);
5055 hr = WINED3DERR_INVALIDCALL;
5059 return hr;
5062 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5063 IWineD3DSwapChain *swapChain;
5064 HRESULT hr;
5065 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5066 if(hr == WINED3D_OK) {
5067 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5068 IWineD3DSwapChain_Release(swapChain);
5070 return hr;
5073 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5075 /* return a sensible default */
5076 *pNumPasses = 1;
5077 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5078 FIXME("(%p) : stub\n", This);
5079 return WINED3D_OK;
5082 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5084 int j;
5085 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5086 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5087 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5088 return WINED3DERR_INVALIDCALL;
5090 for (j = 0; j < 256; ++j) {
5091 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5092 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5093 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5094 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5096 TRACE("(%p) : returning\n", This);
5097 return WINED3D_OK;
5100 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5102 int j;
5103 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5104 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5105 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5106 return WINED3DERR_INVALIDCALL;
5108 for (j = 0; j < 256; ++j) {
5109 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5110 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5111 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5112 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5114 TRACE("(%p) : returning\n", This);
5115 return WINED3D_OK;
5118 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5121 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5122 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5123 return WINED3DERR_INVALIDCALL;
5125 /*TODO: stateblocks */
5126 This->currentPalette = PaletteNumber;
5127 TRACE("(%p) : returning\n", This);
5128 return WINED3D_OK;
5131 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5133 if (PaletteNumber == NULL) {
5134 WARN("(%p) : returning Invalid Call\n", This);
5135 return WINED3DERR_INVALIDCALL;
5137 /*TODO: stateblocks */
5138 *PaletteNumber = This->currentPalette;
5139 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5140 return WINED3D_OK;
5143 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5145 static BOOL showFixmes = TRUE;
5146 if (showFixmes) {
5147 FIXME("(%p) : stub\n", This);
5148 showFixmes = FALSE;
5151 This->softwareVertexProcessing = bSoftware;
5152 return WINED3D_OK;
5156 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5158 static BOOL showFixmes = TRUE;
5159 if (showFixmes) {
5160 FIXME("(%p) : stub\n", This);
5161 showFixmes = FALSE;
5163 return This->softwareVertexProcessing;
5167 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 IWineD3DSwapChain *swapChain;
5170 HRESULT hr;
5172 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5174 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5175 if(hr == WINED3D_OK){
5176 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5177 IWineD3DSwapChain_Release(swapChain);
5178 }else{
5179 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5181 return hr;
5185 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5187 static BOOL showfixmes = TRUE;
5188 if(nSegments != 0.0f) {
5189 if( showfixmes) {
5190 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5191 showfixmes = FALSE;
5194 return WINED3D_OK;
5197 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5199 static BOOL showfixmes = TRUE;
5200 if( showfixmes) {
5201 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5202 showfixmes = FALSE;
5204 return 0.0f;
5207 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5209 /** TODO: remove casts to IWineD3DSurfaceImpl
5210 * NOTE: move code to surface to accomplish this
5211 ****************************************/
5212 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5213 int srcWidth, srcHeight;
5214 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5215 WINED3DFORMAT destFormat, srcFormat;
5216 UINT destSize;
5217 int srcLeft, destLeft, destTop;
5218 WINED3DPOOL srcPool, destPool;
5219 int offset = 0;
5220 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5221 glDescriptor *glDescription = NULL;
5222 GLenum dummy;
5223 int bpp;
5224 CONVERT_TYPES convert = NO_CONVERSION;
5226 WINED3DSURFACE_DESC winedesc;
5228 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5229 memset(&winedesc, 0, sizeof(winedesc));
5230 winedesc.Width = &srcSurfaceWidth;
5231 winedesc.Height = &srcSurfaceHeight;
5232 winedesc.Pool = &srcPool;
5233 winedesc.Format = &srcFormat;
5235 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5237 winedesc.Width = &destSurfaceWidth;
5238 winedesc.Height = &destSurfaceHeight;
5239 winedesc.Pool = &destPool;
5240 winedesc.Format = &destFormat;
5241 winedesc.Size = &destSize;
5243 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5245 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5246 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5247 return WINED3DERR_INVALIDCALL;
5250 /* This call loads the opengl surface directly, instead of copying the surface to the
5251 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5252 * copy in sysmem and use regular surface loading.
5254 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5255 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5256 if(convert != NO_CONVERSION) {
5257 return IWineD3DSurface_BltFast(pDestinationSurface,
5258 pDestPoint ? pDestPoint->x : 0,
5259 pDestPoint ? pDestPoint->y : 0,
5260 pSourceSurface, (RECT *) pSourceRect, 0);
5263 if (destFormat == WINED3DFMT_UNKNOWN) {
5264 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5265 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5267 /* Get the update surface description */
5268 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5271 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5273 ENTER_GL();
5275 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5276 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5277 checkGLcall("glActiveTextureARB");
5280 /* Make sure the surface is loaded and up to date */
5281 IWineD3DSurface_PreLoad(pDestinationSurface);
5283 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5285 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5286 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5287 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5288 srcLeft = pSourceRect ? pSourceRect->left : 0;
5289 destLeft = pDestPoint ? pDestPoint->x : 0;
5290 destTop = pDestPoint ? pDestPoint->y : 0;
5293 /* This function doesn't support compressed textures
5294 the pitch is just bytesPerPixel * width */
5295 if(srcWidth != srcSurfaceWidth || srcLeft ){
5296 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5297 offset += srcLeft * pSrcSurface->bytesPerPixel;
5298 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5300 /* TODO DXT formats */
5302 if(pSourceRect != NULL && pSourceRect->top != 0){
5303 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5305 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5306 ,This
5307 ,glDescription->level
5308 ,destLeft
5309 ,destTop
5310 ,srcWidth
5311 ,srcHeight
5312 ,glDescription->glFormat
5313 ,glDescription->glType
5314 ,IWineD3DSurface_GetData(pSourceSurface)
5317 /* Sanity check */
5318 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5320 /* need to lock the surface to get the data */
5321 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5324 /* TODO: Cube and volume support */
5325 if(rowoffset != 0){
5326 /* not a whole row so we have to do it a line at a time */
5327 int j;
5329 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5330 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5332 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5334 glTexSubImage2D(glDescription->target
5335 ,glDescription->level
5336 ,destLeft
5338 ,srcWidth
5340 ,glDescription->glFormat
5341 ,glDescription->glType
5342 ,data /* could be quicker using */
5344 data += rowoffset;
5347 } else { /* Full width, so just write out the whole texture */
5349 if (WINED3DFMT_DXT1 == destFormat ||
5350 WINED3DFMT_DXT2 == destFormat ||
5351 WINED3DFMT_DXT3 == destFormat ||
5352 WINED3DFMT_DXT4 == destFormat ||
5353 WINED3DFMT_DXT5 == destFormat) {
5354 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5355 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5356 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5357 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5358 } if (destFormat != srcFormat) {
5359 FIXME("Updating mixed format compressed texture is not curretly support\n");
5360 } else {
5361 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5362 glDescription->level,
5363 glDescription->glFormatInternal,
5364 srcWidth,
5365 srcHeight,
5367 destSize,
5368 IWineD3DSurface_GetData(pSourceSurface));
5370 } else {
5371 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5375 } else {
5376 glTexSubImage2D(glDescription->target
5377 ,glDescription->level
5378 ,destLeft
5379 ,destTop
5380 ,srcWidth
5381 ,srcHeight
5382 ,glDescription->glFormat
5383 ,glDescription->glType
5384 ,IWineD3DSurface_GetData(pSourceSurface)
5388 checkGLcall("glTexSubImage2D");
5390 LEAVE_GL();
5392 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5393 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5396 return WINED3D_OK;
5399 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5401 struct WineD3DRectPatch *patch;
5402 unsigned int i;
5403 struct list *e;
5404 BOOL found;
5405 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5407 if(!(Handle || pRectPatchInfo)) {
5408 /* TODO: Write a test for the return value, thus the FIXME */
5409 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5410 return WINED3DERR_INVALIDCALL;
5413 if(Handle) {
5414 i = PATCHMAP_HASHFUNC(Handle);
5415 found = FALSE;
5416 LIST_FOR_EACH(e, &This->patches[i]) {
5417 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5418 if(patch->Handle == Handle) {
5419 found = TRUE;
5420 break;
5424 if(!found) {
5425 TRACE("Patch does not exist. Creating a new one\n");
5426 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5427 patch->Handle = Handle;
5428 list_add_head(&This->patches[i], &patch->entry);
5429 } else {
5430 TRACE("Found existing patch %p\n", patch);
5432 } else {
5433 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5434 * attributes we have to tesselate, read back, and draw. This needs a patch
5435 * management structure instance. Create one.
5437 * A possible improvement is to check if a vertex shader is used, and if not directly
5438 * draw the patch.
5440 FIXME("Drawing an uncached patch. This is slow\n");
5441 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5444 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5445 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5446 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5447 HRESULT hr;
5448 TRACE("Tesselation density or patch info changed, retesselating\n");
5450 if(pRectPatchInfo) {
5451 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5453 patch->numSegs[0] = pNumSegs[0];
5454 patch->numSegs[1] = pNumSegs[1];
5455 patch->numSegs[2] = pNumSegs[2];
5456 patch->numSegs[3] = pNumSegs[3];
5458 hr = tesselate_rectpatch(This, patch);
5459 if(FAILED(hr)) {
5460 WARN("Patch tesselation failed\n");
5462 /* Do not release the handle to store the params of the patch */
5463 if(!Handle) {
5464 HeapFree(GetProcessHeap(), 0, patch);
5466 return hr;
5470 This->currentPatch = patch;
5471 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5472 This->currentPatch = NULL;
5474 /* Destroy uncached patches */
5475 if(!Handle) {
5476 HeapFree(GetProcessHeap(), 0, patch->mem);
5477 HeapFree(GetProcessHeap(), 0, patch);
5479 return WINED3D_OK;
5482 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5483 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5485 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5486 FIXME("(%p) : Stub\n", This);
5487 return WINED3D_OK;
5490 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5492 int i;
5493 struct WineD3DRectPatch *patch;
5494 struct list *e;
5495 TRACE("(%p) Handle(%d)\n", This, Handle);
5497 i = PATCHMAP_HASHFUNC(Handle);
5498 LIST_FOR_EACH(e, &This->patches[i]) {
5499 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5500 if(patch->Handle == Handle) {
5501 TRACE("Deleting patch %p\n", patch);
5502 list_remove(&patch->entry);
5503 HeapFree(GetProcessHeap(), 0, patch->mem);
5504 HeapFree(GetProcessHeap(), 0, patch);
5505 return WINED3D_OK;
5509 /* TODO: Write a test for the return value */
5510 FIXME("Attempt to destroy nonexistant patch\n");
5511 return WINED3DERR_INVALIDCALL;
5514 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5515 HRESULT hr;
5516 IWineD3DSwapChain *swapchain;
5518 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5519 if (SUCCEEDED(hr)) {
5520 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5521 return swapchain;
5524 return NULL;
5527 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5530 if (!*fbo) {
5531 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5532 checkGLcall("glGenFramebuffersEXT()");
5534 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5535 checkGLcall("glBindFramebuffer()");
5538 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5539 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5540 IWineD3DBaseTextureImpl *texture_impl;
5541 GLenum texttarget, target;
5542 GLint old_binding;
5544 texttarget = surface_impl->glDescription.target;
5545 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5546 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5548 IWineD3DSurface_PreLoad(surface);
5550 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5551 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5552 glBindTexture(target, old_binding);
5554 /* Update base texture states array */
5555 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5556 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5557 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5558 if (texture_impl->baseTexture.bindCount) {
5559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5562 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5565 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5566 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5568 checkGLcall("attach_surface_fbo");
5571 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5573 IWineD3DSwapChain *swapchain;
5575 swapchain = get_swapchain(surface);
5576 if (swapchain) {
5577 GLenum buffer;
5579 TRACE("Surface %p is onscreen\n", surface);
5581 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5582 buffer = surface_get_gl_buffer(surface, swapchain);
5583 glDrawBuffer(buffer);
5584 checkGLcall("glDrawBuffer()");
5585 } else {
5586 TRACE("Surface %p is offscreen\n", surface);
5587 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5588 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5591 if (rect) {
5592 glEnable(GL_SCISSOR_TEST);
5593 if(!swapchain) {
5594 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5595 } else {
5596 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5597 rect->x2 - rect->x1, rect->y2 - rect->y1);
5599 checkGLcall("glScissor");
5600 } else {
5601 glDisable(GL_SCISSOR_TEST);
5603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5605 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5608 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5609 glClear(GL_COLOR_BUFFER_BIT);
5610 checkGLcall("glClear");
5612 if (This->render_offscreen) {
5613 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5614 } else {
5615 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5616 checkGLcall("glBindFramebuffer()");
5619 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5620 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5621 glDrawBuffer(GL_BACK);
5622 checkGLcall("glDrawBuffer()");
5626 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5628 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5629 WINEDDBLTFX BltFx;
5630 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5632 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5633 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5634 return WINED3DERR_INVALIDCALL;
5637 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5638 color_fill_fbo(iface, pSurface, pRect, color);
5639 return WINED3D_OK;
5640 } else {
5641 /* Just forward this to the DirectDraw blitting engine */
5642 memset(&BltFx, 0, sizeof(BltFx));
5643 BltFx.dwSize = sizeof(BltFx);
5644 BltFx.u5.dwFillColor = color;
5645 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5649 /* rendertarget and deptth stencil functions */
5650 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5653 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5654 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5655 return WINED3DERR_INVALIDCALL;
5658 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5659 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5660 /* Note inc ref on returned surface */
5661 if(*ppRenderTarget != NULL)
5662 IWineD3DSurface_AddRef(*ppRenderTarget);
5663 return WINED3D_OK;
5666 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5669 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5670 IWineD3DSwapChainImpl *Swapchain;
5671 HRESULT hr;
5673 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5675 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5676 if(hr != WINED3D_OK) {
5677 ERR("Can't get the swapchain\n");
5678 return hr;
5681 /* Make sure to release the swapchain */
5682 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5684 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5685 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5686 return WINED3DERR_INVALIDCALL;
5688 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5689 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5690 return WINED3DERR_INVALIDCALL;
5693 if(Swapchain->frontBuffer != Front) {
5694 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5696 if(Swapchain->frontBuffer)
5697 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5698 Swapchain->frontBuffer = Front;
5700 if(Swapchain->frontBuffer) {
5701 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5705 if(Back && !Swapchain->backBuffer) {
5706 /* We need memory for the back buffer array - only one back buffer this way */
5707 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5708 if(!Swapchain->backBuffer) {
5709 ERR("Out of memory\n");
5710 return E_OUTOFMEMORY;
5714 if(Swapchain->backBuffer[0] != Back) {
5715 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5717 /* What to do about the context here in the case of multithreading? Not sure.
5718 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5720 ENTER_GL();
5721 if(!Swapchain->backBuffer[0]) {
5722 /* GL was told to draw to the front buffer at creation,
5723 * undo that
5725 glDrawBuffer(GL_BACK);
5726 checkGLcall("glDrawBuffer(GL_BACK)");
5727 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5728 Swapchain->presentParms.BackBufferCount = 1;
5729 } else if (!Back) {
5730 /* That makes problems - disable for now */
5731 /* glDrawBuffer(GL_FRONT); */
5732 checkGLcall("glDrawBuffer(GL_FRONT)");
5733 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5734 Swapchain->presentParms.BackBufferCount = 0;
5736 LEAVE_GL();
5738 if(Swapchain->backBuffer[0])
5739 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5740 Swapchain->backBuffer[0] = Back;
5742 if(Swapchain->backBuffer[0]) {
5743 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5744 } else {
5745 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5750 return WINED3D_OK;
5753 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5755 *ppZStencilSurface = This->depthStencilBuffer;
5756 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5758 if(*ppZStencilSurface != NULL) {
5759 /* Note inc ref on returned surface */
5760 IWineD3DSurface_AddRef(*ppZStencilSurface);
5762 return WINED3D_OK;
5765 /* TODO: Handle stencil attachments */
5766 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5768 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5770 TRACE("Set depth stencil to %p\n", depth_stencil);
5772 if (depth_stencil_impl) {
5773 if (depth_stencil_impl->current_renderbuffer) {
5774 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5775 checkGLcall("glFramebufferRenderbufferEXT()");
5776 } else {
5777 IWineD3DBaseTextureImpl *texture_impl;
5778 GLenum texttarget, target;
5779 GLint old_binding = 0;
5781 texttarget = depth_stencil_impl->glDescription.target;
5782 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5783 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5785 IWineD3DSurface_PreLoad(depth_stencil);
5787 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5788 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5789 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5790 glBindTexture(target, old_binding);
5792 /* Update base texture states array */
5793 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5794 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5795 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5796 if (texture_impl->baseTexture.bindCount) {
5797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5800 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5803 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5804 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5805 checkGLcall("glFramebufferTexture2DEXT()");
5807 } else {
5808 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5809 checkGLcall("glFramebufferTexture2DEXT()");
5813 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5815 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5817 TRACE("Set render target %u to %p\n", idx, render_target);
5819 if (rtimpl) {
5820 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5821 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5822 } else {
5823 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5824 checkGLcall("glFramebufferTexture2DEXT()");
5826 This->draw_buffers[idx] = GL_NONE;
5830 static void check_fbo_status(IWineD3DDevice *iface) {
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5832 GLenum status;
5834 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5835 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5836 TRACE("FBO complete\n");
5837 } else {
5838 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5840 /* Dump the FBO attachments */
5841 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5842 IWineD3DSurfaceImpl *attachment;
5843 int i;
5845 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5846 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5847 if (attachment) {
5848 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5849 attachment->pow2Width, attachment->pow2Height);
5852 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5853 if (attachment) {
5854 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5855 attachment->pow2Width, attachment->pow2Height);
5861 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5863 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5864 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5866 if (!ds_impl) return FALSE;
5868 if (ds_impl->current_renderbuffer) {
5869 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5870 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5873 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5874 rt_impl->pow2Height != ds_impl->pow2Height);
5877 void apply_fbo_state(IWineD3DDevice *iface) {
5878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5879 unsigned int i;
5881 if (This->render_offscreen) {
5882 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5884 /* Apply render targets */
5885 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5886 IWineD3DSurface *render_target = This->render_targets[i];
5887 if (This->fbo_color_attachments[i] != render_target) {
5888 set_render_target_fbo(iface, i, render_target);
5889 This->fbo_color_attachments[i] = render_target;
5893 /* Apply depth targets */
5894 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5895 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5896 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5898 if (This->stencilBufferTarget) {
5899 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5901 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5902 This->fbo_depth_attachment = This->stencilBufferTarget;
5905 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5906 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5907 checkGLcall("glDrawBuffers()");
5908 } else {
5909 glDrawBuffer(This->draw_buffers[0]);
5910 checkGLcall("glDrawBuffer()");
5912 } else {
5913 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5916 check_fbo_status(iface);
5919 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5920 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5922 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5923 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5924 GLenum gl_filter;
5926 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5927 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5928 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5929 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5931 switch (filter) {
5932 case WINED3DTEXF_LINEAR:
5933 gl_filter = GL_LINEAR;
5934 break;
5936 default:
5937 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5938 case WINED3DTEXF_NONE:
5939 case WINED3DTEXF_POINT:
5940 gl_filter = GL_NEAREST;
5941 break;
5944 /* Attach src surface to src fbo */
5945 src_swapchain = get_swapchain(src_surface);
5946 if (src_swapchain) {
5947 GLenum buffer;
5949 TRACE("Source surface %p is onscreen\n", src_surface);
5950 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5952 ENTER_GL();
5953 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5954 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5955 glReadBuffer(buffer);
5956 checkGLcall("glReadBuffer()");
5958 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5959 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5960 } else {
5961 TRACE("Source surface %p is offscreen\n", src_surface);
5962 ENTER_GL();
5963 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5964 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5965 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5966 checkGLcall("glReadBuffer()");
5968 LEAVE_GL();
5970 /* Attach dst surface to dst fbo */
5971 dst_swapchain = get_swapchain(dst_surface);
5972 if (dst_swapchain) {
5973 GLenum buffer;
5975 TRACE("Destination surface %p is onscreen\n", dst_surface);
5976 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5978 ENTER_GL();
5979 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5980 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5981 glDrawBuffer(buffer);
5982 checkGLcall("glDrawBuffer()");
5984 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5985 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5986 } else {
5987 TRACE("Destination surface %p is offscreen\n", dst_surface);
5989 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5990 if(!src_swapchain) {
5991 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5994 ENTER_GL();
5995 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5996 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5997 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5998 checkGLcall("glDrawBuffer()");
6000 glDisable(GL_SCISSOR_TEST);
6001 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6003 if (flip) {
6004 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6005 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6006 checkGLcall("glBlitFramebuffer()");
6007 } else {
6008 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6009 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6010 checkGLcall("glBlitFramebuffer()");
6013 if (This->render_offscreen) {
6014 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6015 } else {
6016 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6017 checkGLcall("glBindFramebuffer()");
6020 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6021 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6022 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6023 glDrawBuffer(GL_BACK);
6024 checkGLcall("glDrawBuffer()");
6026 LEAVE_GL();
6029 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6031 WINED3DVIEWPORT viewport;
6033 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6035 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6036 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6037 return WINED3DERR_INVALIDCALL;
6040 /* MSDN says that null disables the render target
6041 but a device must always be associated with a render target
6042 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6044 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6045 for more details
6047 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6048 FIXME("Trying to set render target 0 to NULL\n");
6049 return WINED3DERR_INVALIDCALL;
6051 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6052 FIXME("(%p)Trying to set the render target to a surface(%p) that wasn't created with a usage of WINED3DUSAGE_RENDERTARGET\n",This ,pRenderTarget);
6053 return WINED3DERR_INVALIDCALL;
6056 /* If we are trying to set what we already have, don't bother */
6057 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6058 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6059 return WINED3D_OK;
6061 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6062 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6063 This->render_targets[RenderTargetIndex] = pRenderTarget;
6065 /* Render target 0 is special */
6066 if(RenderTargetIndex == 0) {
6067 /* Finally, reset the viewport as the MSDN states. */
6068 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6069 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6070 viewport.X = 0;
6071 viewport.Y = 0;
6072 viewport.MaxZ = 1.0f;
6073 viewport.MinZ = 0.0f;
6074 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6075 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6076 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6078 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6080 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6081 * ctx properly.
6082 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6083 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6085 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6087 return WINED3D_OK;
6090 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6092 HRESULT hr = WINED3D_OK;
6093 IWineD3DSurface *tmp;
6095 TRACE("(%p) Swapping z-buffer\n",This);
6097 if (pNewZStencil == This->stencilBufferTarget) {
6098 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6099 } else {
6100 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6101 * depending on the renter target implementation being used.
6102 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6103 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6104 * stencil buffer and incure an extra memory overhead
6105 ******************************************************/
6107 tmp = This->stencilBufferTarget;
6108 This->stencilBufferTarget = pNewZStencil;
6109 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6110 /* should we be calling the parent or the wined3d surface? */
6111 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6112 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6113 hr = WINED3D_OK;
6115 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6116 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6123 return hr;
6126 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6127 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6129 /* TODO: the use of Impl is deprecated. */
6130 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6131 WINED3DLOCKED_RECT lockedRect;
6133 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6135 /* some basic validation checks */
6136 if(This->cursorTexture) {
6137 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6138 ENTER_GL();
6139 glDeleteTextures(1, &This->cursorTexture);
6140 LEAVE_GL();
6141 This->cursorTexture = 0;
6144 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6145 This->haveHardwareCursor = TRUE;
6146 else
6147 This->haveHardwareCursor = FALSE;
6149 if(pCursorBitmap) {
6150 WINED3DLOCKED_RECT rect;
6152 /* MSDN: Cursor must be A8R8G8B8 */
6153 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6154 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6155 return WINED3DERR_INVALIDCALL;
6158 /* MSDN: Cursor must be smaller than the display mode */
6159 if(pSur->currentDesc.Width > This->ddraw_width ||
6160 pSur->currentDesc.Height > This->ddraw_height) {
6161 ERR("(%p) : Surface(%p) is %dx%d pixels, but screen res is %dx%d\n", This, pSur, pSur->currentDesc.Width, pSur->currentDesc.Height, This->ddraw_width, This->ddraw_height);
6162 return WINED3DERR_INVALIDCALL;
6165 if (!This->haveHardwareCursor) {
6166 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6168 /* Do not store the surface's pointer because the application may
6169 * release it after setting the cursor image. Windows doesn't
6170 * addref the set surface, so we can't do this either without
6171 * creating circular refcount dependencies. Copy out the gl texture
6172 * instead.
6174 This->cursorWidth = pSur->currentDesc.Width;
6175 This->cursorHeight = pSur->currentDesc.Height;
6176 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6178 const GlPixelFormatDesc *glDesc;
6179 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6180 char *mem, *bits = (char *)rect.pBits;
6181 GLint intfmt = glDesc->glInternal;
6182 GLint format = glDesc->glFormat;
6183 GLint type = glDesc->glType;
6184 INT height = This->cursorHeight;
6185 INT width = This->cursorWidth;
6186 INT bpp = tableEntry->bpp;
6187 INT i;
6189 /* Reformat the texture memory (pitch and width can be
6190 * different) */
6191 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6192 for(i = 0; i < height; i++)
6193 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6194 IWineD3DSurface_UnlockRect(pCursorBitmap);
6195 ENTER_GL();
6197 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6198 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6199 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6202 /* Make sure that a proper texture unit is selected */
6203 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6204 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6205 checkGLcall("glActiveTextureARB");
6207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6208 /* Create a new cursor texture */
6209 glGenTextures(1, &This->cursorTexture);
6210 checkGLcall("glGenTextures");
6211 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6212 checkGLcall("glBindTexture");
6213 /* Copy the bitmap memory into the cursor texture */
6214 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6215 HeapFree(GetProcessHeap(), 0, mem);
6216 checkGLcall("glTexImage2D");
6218 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6219 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6220 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6223 LEAVE_GL();
6225 else
6227 FIXME("A cursor texture was not returned.\n");
6228 This->cursorTexture = 0;
6231 else
6233 /* Draw a hardware cursor */
6234 ICONINFO cursorInfo;
6235 HCURSOR cursor;
6236 /* Create and clear maskBits because it is not needed for
6237 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6238 * chunks. */
6239 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6240 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6241 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6242 WINED3DLOCK_NO_DIRTY_UPDATE |
6243 WINED3DLOCK_READONLY
6245 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6246 pSur->currentDesc.Height);
6248 cursorInfo.fIcon = FALSE;
6249 cursorInfo.xHotspot = XHotSpot;
6250 cursorInfo.yHotspot = YHotSpot;
6251 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6252 pSur->currentDesc.Height, 1,
6253 1, &maskBits);
6254 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6255 pSur->currentDesc.Height, 1,
6256 32, lockedRect.pBits);
6257 IWineD3DSurface_UnlockRect(pCursorBitmap);
6258 /* Create our cursor and clean up. */
6259 cursor = CreateIconIndirect(&cursorInfo);
6260 SetCursor(cursor);
6261 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6262 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6263 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6264 This->hardwareCursor = cursor;
6265 HeapFree(GetProcessHeap(), 0, maskBits);
6269 This->xHotSpot = XHotSpot;
6270 This->yHotSpot = YHotSpot;
6271 return WINED3D_OK;
6274 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6276 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6278 This->xScreenSpace = XScreenSpace;
6279 This->yScreenSpace = YScreenSpace;
6281 return;
6285 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6287 BOOL oldVisible = This->bCursorVisible;
6288 POINT pt;
6290 TRACE("(%p) : visible(%d)\n", This, bShow);
6293 * When ShowCursor is first called it should make the cursor appear at the OS's last
6294 * known cursor position. Because of this, some applications just repetitively call
6295 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6297 GetCursorPos(&pt);
6298 This->xScreenSpace = pt.x;
6299 This->yScreenSpace = pt.y;
6301 if (This->haveHardwareCursor) {
6302 This->bCursorVisible = bShow;
6303 if (bShow)
6304 SetCursor(This->hardwareCursor);
6305 else
6306 SetCursor(NULL);
6308 else
6310 if (This->cursorTexture)
6311 This->bCursorVisible = bShow;
6314 return oldVisible;
6317 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6319 TRACE("(%p) : state (%u)\n", This, This->state);
6320 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6321 switch (This->state) {
6322 case WINED3D_OK:
6323 return WINED3D_OK;
6324 case WINED3DERR_DEVICELOST:
6326 ResourceList *resourceList = This->resources;
6327 while (NULL != resourceList) {
6328 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6329 return WINED3DERR_DEVICENOTRESET;
6330 resourceList = resourceList->next;
6332 return WINED3DERR_DEVICELOST;
6334 case WINED3DERR_DRIVERINTERNALERROR:
6335 return WINED3DERR_DRIVERINTERNALERROR;
6338 /* Unknown state */
6339 return WINED3DERR_DRIVERINTERNALERROR;
6343 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6345 /** FIXME: Resource tracking needs to be done,
6346 * The closes we can do to this is set the priorities of all managed textures low
6347 * and then reset them.
6348 ***********************************************************/
6349 FIXME("(%p) : stub\n", This);
6350 return WINED3D_OK;
6353 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6354 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6356 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6357 if(surface->Flags & SFLAG_DIBSECTION) {
6358 /* Release the DC */
6359 SelectObject(surface->hDC, surface->dib.holdbitmap);
6360 DeleteDC(surface->hDC);
6361 /* Release the DIB section */
6362 DeleteObject(surface->dib.DIBsection);
6363 surface->dib.bitmap_data = NULL;
6364 surface->resource.allocatedMemory = NULL;
6365 surface->Flags &= ~SFLAG_DIBSECTION;
6367 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6368 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6369 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6370 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6371 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6372 } else {
6373 surface->pow2Width = surface->pow2Height = 1;
6374 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6375 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6377 if(surface->glDescription.textureName) {
6378 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6379 ENTER_GL();
6380 glDeleteTextures(1, &surface->glDescription.textureName);
6381 LEAVE_GL();
6382 surface->glDescription.textureName = 0;
6383 surface->Flags &= ~SFLAG_CLIENT;
6385 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6386 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6387 surface->Flags |= SFLAG_NONPOW2;
6388 } else {
6389 surface->Flags &= ~SFLAG_NONPOW2;
6391 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6392 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6395 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6397 IWineD3DSwapChainImpl *swapchain;
6398 HRESULT hr;
6399 BOOL DisplayModeChanged = FALSE;
6400 WINED3DDISPLAYMODE mode;
6401 TRACE("(%p)\n", This);
6403 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6404 if(FAILED(hr)) {
6405 ERR("Failed to get the first implicit swapchain\n");
6406 return hr;
6409 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6410 * on an existing gl context, so there's no real need for recreation.
6412 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6414 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6416 TRACE("New params:\n");
6417 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6418 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6419 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6420 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6421 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6422 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6423 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6424 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6425 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6426 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6427 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6428 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6429 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6431 /* No special treatment of these parameters. Just store them */
6432 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6433 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6434 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6435 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6437 /* What to do about these? */
6438 if(pPresentationParameters->BackBufferCount != 0 &&
6439 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6440 ERR("Cannot change the back buffer count yet\n");
6442 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6443 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6444 ERR("Cannot change the back buffer format yet\n");
6446 if(pPresentationParameters->hDeviceWindow != NULL &&
6447 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6448 ERR("Cannot change the device window yet\n");
6450 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6451 ERR("What do do about a changed auto depth stencil parameter?\n");
6454 if(pPresentationParameters->Windowed) {
6455 mode.Width = swapchain->orig_width;
6456 mode.Height = swapchain->orig_height;
6457 mode.RefreshRate = 0;
6458 mode.Format = swapchain->presentParms.BackBufferFormat;
6459 } else {
6460 mode.Width = pPresentationParameters->BackBufferWidth;
6461 mode.Height = pPresentationParameters->BackBufferHeight;
6462 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6463 mode.Format = swapchain->presentParms.BackBufferFormat;
6466 /* Should Width == 800 && Height == 0 set 800x600? */
6467 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6468 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6469 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6471 WINED3DVIEWPORT vp;
6472 int i;
6474 vp.X = 0;
6475 vp.Y = 0;
6476 vp.Width = pPresentationParameters->BackBufferWidth;
6477 vp.Height = pPresentationParameters->BackBufferHeight;
6478 vp.MinZ = 0;
6479 vp.MaxZ = 1;
6481 if(!pPresentationParameters->Windowed) {
6482 DisplayModeChanged = TRUE;
6484 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6485 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6487 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6488 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6489 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6492 /* Now set the new viewport */
6493 IWineD3DDevice_SetViewport(iface, &vp);
6496 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6497 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6498 DisplayModeChanged) {
6500 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6501 if(!pPresentationParameters->Windowed) {
6502 IWineD3DDevice_SetFullscreen(iface, TRUE);
6505 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6507 /* Switching out of fullscreen mode? First set the original res, then change the window */
6508 if(pPresentationParameters->Windowed) {
6509 IWineD3DDevice_SetFullscreen(iface, FALSE);
6511 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6514 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6515 return WINED3D_OK;
6518 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6520 /** FIXME: always true at the moment **/
6521 if(!bEnableDialogs) {
6522 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6524 return WINED3D_OK;
6528 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6530 TRACE("(%p) : pParameters %p\n", This, pParameters);
6532 *pParameters = This->createParms;
6533 return WINED3D_OK;
6536 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6537 IWineD3DSwapChain *swapchain;
6538 HRESULT hrc = WINED3D_OK;
6540 TRACE("Relaying to swapchain\n");
6542 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6543 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6544 IWineD3DSwapChain_Release(swapchain);
6546 return;
6549 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6550 IWineD3DSwapChain *swapchain;
6551 HRESULT hrc = WINED3D_OK;
6553 TRACE("Relaying to swapchain\n");
6555 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6556 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6557 IWineD3DSwapChain_Release(swapchain);
6559 return;
6563 /** ********************************************************
6564 * Notification functions
6565 ** ********************************************************/
6566 /** This function must be called in the release of a resource when ref == 0,
6567 * the contents of resource must still be correct,
6568 * any handels to other resource held by the caller must be closed
6569 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6570 *****************************************************/
6571 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6573 ResourceList* resourceList;
6575 TRACE("(%p) : resource %p\n", This, resource);
6576 /* add a new texture to the frot of the linked list */
6577 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6578 resourceList->resource = resource;
6580 /* Get the old head */
6581 resourceList->next = This->resources;
6583 This->resources = resourceList;
6584 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6586 return;
6589 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6591 ResourceList* resourceList = NULL;
6592 ResourceList* previousResourceList = NULL;
6594 TRACE("(%p) : resource %p\n", This, resource);
6596 resourceList = This->resources;
6598 while (resourceList != NULL) {
6599 if(resourceList->resource == resource) break;
6600 previousResourceList = resourceList;
6601 resourceList = resourceList->next;
6604 if (resourceList == NULL) {
6605 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6606 return;
6607 } else {
6608 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6610 /* make sure we don't leave a hole in the list */
6611 if (previousResourceList != NULL) {
6612 previousResourceList->next = resourceList->next;
6613 } else {
6614 This->resources = resourceList->next;
6617 return;
6621 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6623 int counter;
6625 TRACE("(%p) : resource %p\n", This, resource);
6626 switch(IWineD3DResource_GetType(resource)){
6627 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6628 case WINED3DRTYPE_SURFACE: {
6629 unsigned int i;
6631 /* Cleanup any FBO attachments if d3d is enabled */
6632 if(This->d3d_initialized) {
6633 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6634 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6635 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6636 set_render_target_fbo(iface, i, NULL);
6637 This->fbo_color_attachments[i] = NULL;
6640 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6641 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6642 set_depth_stencil_fbo(iface, NULL);
6643 This->fbo_depth_attachment = NULL;
6647 break;
6649 case WINED3DRTYPE_TEXTURE:
6650 case WINED3DRTYPE_CUBETEXTURE:
6651 case WINED3DRTYPE_VOLUMETEXTURE:
6652 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6653 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6654 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6655 This->stateBlock->textures[counter] = NULL;
6657 if (This->updateStateBlock != This->stateBlock ){
6658 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6659 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6660 This->updateStateBlock->textures[counter] = NULL;
6664 break;
6665 case WINED3DRTYPE_VOLUME:
6666 /* TODO: nothing really? */
6667 break;
6668 case WINED3DRTYPE_VERTEXBUFFER:
6669 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6671 int streamNumber;
6672 TRACE("Cleaning up stream pointers\n");
6674 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6675 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6676 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6678 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6679 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6680 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6681 This->updateStateBlock->streamSource[streamNumber] = 0;
6682 /* Set changed flag? */
6685 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6686 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6687 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6688 This->stateBlock->streamSource[streamNumber] = 0;
6691 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6692 else { /* This shouldn't happen */
6693 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6695 #endif
6699 break;
6700 case WINED3DRTYPE_INDEXBUFFER:
6701 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6702 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6703 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6704 This->updateStateBlock->pIndexData = NULL;
6707 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6708 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6709 This->stateBlock->pIndexData = NULL;
6713 break;
6714 default:
6715 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6716 break;
6720 /* Remove the resoruce from the resourceStore */
6721 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6723 TRACE("Resource released\n");
6727 /**********************************************************
6728 * IWineD3DDevice VTbl follows
6729 **********************************************************/
6731 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6733 /*** IUnknown methods ***/
6734 IWineD3DDeviceImpl_QueryInterface,
6735 IWineD3DDeviceImpl_AddRef,
6736 IWineD3DDeviceImpl_Release,
6737 /*** IWineD3DDevice methods ***/
6738 IWineD3DDeviceImpl_GetParent,
6739 /*** Creation methods**/
6740 IWineD3DDeviceImpl_CreateVertexBuffer,
6741 IWineD3DDeviceImpl_CreateIndexBuffer,
6742 IWineD3DDeviceImpl_CreateStateBlock,
6743 IWineD3DDeviceImpl_CreateSurface,
6744 IWineD3DDeviceImpl_CreateTexture,
6745 IWineD3DDeviceImpl_CreateVolumeTexture,
6746 IWineD3DDeviceImpl_CreateVolume,
6747 IWineD3DDeviceImpl_CreateCubeTexture,
6748 IWineD3DDeviceImpl_CreateQuery,
6749 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6750 IWineD3DDeviceImpl_CreateVertexDeclaration,
6751 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6752 IWineD3DDeviceImpl_CreateVertexShader,
6753 IWineD3DDeviceImpl_CreatePixelShader,
6754 IWineD3DDeviceImpl_CreatePalette,
6755 /*** Odd functions **/
6756 IWineD3DDeviceImpl_Init3D,
6757 IWineD3DDeviceImpl_Uninit3D,
6758 IWineD3DDeviceImpl_SetFullscreen,
6759 IWineD3DDeviceImpl_SetMultithreaded,
6760 IWineD3DDeviceImpl_EvictManagedResources,
6761 IWineD3DDeviceImpl_GetAvailableTextureMem,
6762 IWineD3DDeviceImpl_GetBackBuffer,
6763 IWineD3DDeviceImpl_GetCreationParameters,
6764 IWineD3DDeviceImpl_GetDeviceCaps,
6765 IWineD3DDeviceImpl_GetDirect3D,
6766 IWineD3DDeviceImpl_GetDisplayMode,
6767 IWineD3DDeviceImpl_SetDisplayMode,
6768 IWineD3DDeviceImpl_GetHWND,
6769 IWineD3DDeviceImpl_SetHWND,
6770 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6771 IWineD3DDeviceImpl_GetRasterStatus,
6772 IWineD3DDeviceImpl_GetSwapChain,
6773 IWineD3DDeviceImpl_Reset,
6774 IWineD3DDeviceImpl_SetDialogBoxMode,
6775 IWineD3DDeviceImpl_SetCursorProperties,
6776 IWineD3DDeviceImpl_SetCursorPosition,
6777 IWineD3DDeviceImpl_ShowCursor,
6778 IWineD3DDeviceImpl_TestCooperativeLevel,
6779 /*** Getters and setters **/
6780 IWineD3DDeviceImpl_SetClipPlane,
6781 IWineD3DDeviceImpl_GetClipPlane,
6782 IWineD3DDeviceImpl_SetClipStatus,
6783 IWineD3DDeviceImpl_GetClipStatus,
6784 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6785 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6786 IWineD3DDeviceImpl_SetDepthStencilSurface,
6787 IWineD3DDeviceImpl_GetDepthStencilSurface,
6788 IWineD3DDeviceImpl_SetFVF,
6789 IWineD3DDeviceImpl_GetFVF,
6790 IWineD3DDeviceImpl_SetGammaRamp,
6791 IWineD3DDeviceImpl_GetGammaRamp,
6792 IWineD3DDeviceImpl_SetIndices,
6793 IWineD3DDeviceImpl_GetIndices,
6794 IWineD3DDeviceImpl_SetBaseVertexIndex,
6795 IWineD3DDeviceImpl_GetBaseVertexIndex,
6796 IWineD3DDeviceImpl_SetLight,
6797 IWineD3DDeviceImpl_GetLight,
6798 IWineD3DDeviceImpl_SetLightEnable,
6799 IWineD3DDeviceImpl_GetLightEnable,
6800 IWineD3DDeviceImpl_SetMaterial,
6801 IWineD3DDeviceImpl_GetMaterial,
6802 IWineD3DDeviceImpl_SetNPatchMode,
6803 IWineD3DDeviceImpl_GetNPatchMode,
6804 IWineD3DDeviceImpl_SetPaletteEntries,
6805 IWineD3DDeviceImpl_GetPaletteEntries,
6806 IWineD3DDeviceImpl_SetPixelShader,
6807 IWineD3DDeviceImpl_GetPixelShader,
6808 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6809 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6810 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6811 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6812 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6813 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6814 IWineD3DDeviceImpl_SetRenderState,
6815 IWineD3DDeviceImpl_GetRenderState,
6816 IWineD3DDeviceImpl_SetRenderTarget,
6817 IWineD3DDeviceImpl_GetRenderTarget,
6818 IWineD3DDeviceImpl_SetFrontBackBuffers,
6819 IWineD3DDeviceImpl_SetSamplerState,
6820 IWineD3DDeviceImpl_GetSamplerState,
6821 IWineD3DDeviceImpl_SetScissorRect,
6822 IWineD3DDeviceImpl_GetScissorRect,
6823 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6824 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6825 IWineD3DDeviceImpl_SetStreamSource,
6826 IWineD3DDeviceImpl_GetStreamSource,
6827 IWineD3DDeviceImpl_SetStreamSourceFreq,
6828 IWineD3DDeviceImpl_GetStreamSourceFreq,
6829 IWineD3DDeviceImpl_SetTexture,
6830 IWineD3DDeviceImpl_GetTexture,
6831 IWineD3DDeviceImpl_SetTextureStageState,
6832 IWineD3DDeviceImpl_GetTextureStageState,
6833 IWineD3DDeviceImpl_SetTransform,
6834 IWineD3DDeviceImpl_GetTransform,
6835 IWineD3DDeviceImpl_SetVertexDeclaration,
6836 IWineD3DDeviceImpl_GetVertexDeclaration,
6837 IWineD3DDeviceImpl_SetVertexShader,
6838 IWineD3DDeviceImpl_GetVertexShader,
6839 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6840 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6841 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6842 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6843 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6844 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6845 IWineD3DDeviceImpl_SetViewport,
6846 IWineD3DDeviceImpl_GetViewport,
6847 IWineD3DDeviceImpl_MultiplyTransform,
6848 IWineD3DDeviceImpl_ValidateDevice,
6849 IWineD3DDeviceImpl_ProcessVertices,
6850 /*** State block ***/
6851 IWineD3DDeviceImpl_BeginStateBlock,
6852 IWineD3DDeviceImpl_EndStateBlock,
6853 /*** Scene management ***/
6854 IWineD3DDeviceImpl_BeginScene,
6855 IWineD3DDeviceImpl_EndScene,
6856 IWineD3DDeviceImpl_Present,
6857 IWineD3DDeviceImpl_Clear,
6858 /*** Drawing ***/
6859 IWineD3DDeviceImpl_DrawPrimitive,
6860 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6861 IWineD3DDeviceImpl_DrawPrimitiveUP,
6862 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6863 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6864 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6865 IWineD3DDeviceImpl_DrawRectPatch,
6866 IWineD3DDeviceImpl_DrawTriPatch,
6867 IWineD3DDeviceImpl_DeletePatch,
6868 IWineD3DDeviceImpl_ColorFill,
6869 IWineD3DDeviceImpl_UpdateTexture,
6870 IWineD3DDeviceImpl_UpdateSurface,
6871 IWineD3DDeviceImpl_GetFrontBufferData,
6872 /*** object tracking ***/
6873 IWineD3DDeviceImpl_ResourceReleased
6877 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6878 WINED3DRS_ALPHABLENDENABLE ,
6879 WINED3DRS_ALPHAFUNC ,
6880 WINED3DRS_ALPHAREF ,
6881 WINED3DRS_ALPHATESTENABLE ,
6882 WINED3DRS_BLENDOP ,
6883 WINED3DRS_COLORWRITEENABLE ,
6884 WINED3DRS_DESTBLEND ,
6885 WINED3DRS_DITHERENABLE ,
6886 WINED3DRS_FILLMODE ,
6887 WINED3DRS_FOGDENSITY ,
6888 WINED3DRS_FOGEND ,
6889 WINED3DRS_FOGSTART ,
6890 WINED3DRS_LASTPIXEL ,
6891 WINED3DRS_SHADEMODE ,
6892 WINED3DRS_SRCBLEND ,
6893 WINED3DRS_STENCILENABLE ,
6894 WINED3DRS_STENCILFAIL ,
6895 WINED3DRS_STENCILFUNC ,
6896 WINED3DRS_STENCILMASK ,
6897 WINED3DRS_STENCILPASS ,
6898 WINED3DRS_STENCILREF ,
6899 WINED3DRS_STENCILWRITEMASK ,
6900 WINED3DRS_STENCILZFAIL ,
6901 WINED3DRS_TEXTUREFACTOR ,
6902 WINED3DRS_WRAP0 ,
6903 WINED3DRS_WRAP1 ,
6904 WINED3DRS_WRAP2 ,
6905 WINED3DRS_WRAP3 ,
6906 WINED3DRS_WRAP4 ,
6907 WINED3DRS_WRAP5 ,
6908 WINED3DRS_WRAP6 ,
6909 WINED3DRS_WRAP7 ,
6910 WINED3DRS_ZENABLE ,
6911 WINED3DRS_ZFUNC ,
6912 WINED3DRS_ZWRITEENABLE
6915 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6916 WINED3DTSS_ADDRESSW ,
6917 WINED3DTSS_ALPHAARG0 ,
6918 WINED3DTSS_ALPHAARG1 ,
6919 WINED3DTSS_ALPHAARG2 ,
6920 WINED3DTSS_ALPHAOP ,
6921 WINED3DTSS_BUMPENVLOFFSET ,
6922 WINED3DTSS_BUMPENVLSCALE ,
6923 WINED3DTSS_BUMPENVMAT00 ,
6924 WINED3DTSS_BUMPENVMAT01 ,
6925 WINED3DTSS_BUMPENVMAT10 ,
6926 WINED3DTSS_BUMPENVMAT11 ,
6927 WINED3DTSS_COLORARG0 ,
6928 WINED3DTSS_COLORARG1 ,
6929 WINED3DTSS_COLORARG2 ,
6930 WINED3DTSS_COLOROP ,
6931 WINED3DTSS_RESULTARG ,
6932 WINED3DTSS_TEXCOORDINDEX ,
6933 WINED3DTSS_TEXTURETRANSFORMFLAGS
6936 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6937 WINED3DSAMP_ADDRESSU ,
6938 WINED3DSAMP_ADDRESSV ,
6939 WINED3DSAMP_ADDRESSW ,
6940 WINED3DSAMP_BORDERCOLOR ,
6941 WINED3DSAMP_MAGFILTER ,
6942 WINED3DSAMP_MINFILTER ,
6943 WINED3DSAMP_MIPFILTER ,
6944 WINED3DSAMP_MIPMAPLODBIAS ,
6945 WINED3DSAMP_MAXMIPLEVEL ,
6946 WINED3DSAMP_MAXANISOTROPY ,
6947 WINED3DSAMP_SRGBTEXTURE ,
6948 WINED3DSAMP_ELEMENTINDEX
6951 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6952 WINED3DRS_AMBIENT ,
6953 WINED3DRS_AMBIENTMATERIALSOURCE ,
6954 WINED3DRS_CLIPPING ,
6955 WINED3DRS_CLIPPLANEENABLE ,
6956 WINED3DRS_COLORVERTEX ,
6957 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6958 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6959 WINED3DRS_FOGDENSITY ,
6960 WINED3DRS_FOGEND ,
6961 WINED3DRS_FOGSTART ,
6962 WINED3DRS_FOGTABLEMODE ,
6963 WINED3DRS_FOGVERTEXMODE ,
6964 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6965 WINED3DRS_LIGHTING ,
6966 WINED3DRS_LOCALVIEWER ,
6967 WINED3DRS_MULTISAMPLEANTIALIAS ,
6968 WINED3DRS_MULTISAMPLEMASK ,
6969 WINED3DRS_NORMALIZENORMALS ,
6970 WINED3DRS_PATCHEDGESTYLE ,
6971 WINED3DRS_POINTSCALE_A ,
6972 WINED3DRS_POINTSCALE_B ,
6973 WINED3DRS_POINTSCALE_C ,
6974 WINED3DRS_POINTSCALEENABLE ,
6975 WINED3DRS_POINTSIZE ,
6976 WINED3DRS_POINTSIZE_MAX ,
6977 WINED3DRS_POINTSIZE_MIN ,
6978 WINED3DRS_POINTSPRITEENABLE ,
6979 WINED3DRS_RANGEFOGENABLE ,
6980 WINED3DRS_SPECULARMATERIALSOURCE ,
6981 WINED3DRS_TWEENFACTOR ,
6982 WINED3DRS_VERTEXBLEND ,
6983 WINED3DRS_CULLMODE ,
6984 WINED3DRS_FOGCOLOR
6987 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6988 WINED3DTSS_TEXCOORDINDEX ,
6989 WINED3DTSS_TEXTURETRANSFORMFLAGS
6992 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6993 WINED3DSAMP_DMAPOFFSET
6996 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6997 DWORD rep = StateTable[state].representative;
6998 DWORD idx;
6999 BYTE shift;
7000 UINT i;
7001 WineD3DContext *context;
7003 if(!rep) return;
7004 for(i = 0; i < This->numContexts; i++) {
7005 context = This->contexts[i];
7006 if(isStateDirty(context, rep)) continue;
7008 context->dirtyArray[context->numDirtyEntries++] = rep;
7009 idx = rep >> 5;
7010 shift = rep & 0x1f;
7011 context->isStateDirty[idx] |= (1 << shift);