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-2008 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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
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; \
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->baseShader.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); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This->resources)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
182 dumpResources(&This->resources);
185 if(This->contexts) ERR("Context array not freed!\n");
186 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
187 This->haveHardwareCursor = FALSE;
189 IWineD3D_Release(This->wineD3D);
190 This->wineD3D = NULL;
191 HeapFree(GetProcessHeap(), 0, This);
192 TRACE("Freed device %p\n", This);
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 *pParent = This->parent;
204 IUnknown_AddRef(This->parent);
208 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
209 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
212 IWineD3DVertexBufferImpl *object;
213 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
214 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer = NULL;
220 return WINED3DERR_INVALIDCALL;
221 } else if(Pool == WINED3DPOOL_SCRATCH) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer = NULL;
227 return WINED3DERR_INVALIDCALL;
230 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
232 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
233 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion <= 7 && conv) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
262 object->Flags |= VBFLAG_CREATEVBO;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
268 GLenum error, glUsage;
269 TRACE("Creating VBO for Index Buffer %p\n", object);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR || object->vbo == 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage = GL_STATIC_DRAW_ARB;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
301 error = glGetError();
302 if(error != GL_NO_ERROR) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
307 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
317 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
318 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
319 HANDLE *sharedHandle, IUnknown *parent) {
320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
321 IWineD3DIndexBufferImpl *object;
322 TRACE("(%p) Creating index buffer\n", This);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
327 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 CreateIndexBufferVBO(This, object);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
332 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
333 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
338 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DStateBlockImpl *object;
345 D3DCREATEOBJECTINSTANCE(object, StateBlock)
346 object->blockType = Type;
348 for(i = 0; i < LIGHTMAP_SIZE; i++) {
349 list_init(&object->lightMap[i]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type == WINED3DSBT_INIT) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
360 temp_result = allocate_shader_constants(object);
361 if (WINED3D_OK != temp_result)
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This->stateBlock != NULL)
366 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
368 memset(object->streamFreq, 1, sizeof(object->streamFreq));
370 /* Reset the ref and type after kludging it */
371 object->wineD3DDevice = This;
373 object->blockType = Type;
375 TRACE("Updating changed flags appropriate for type %d\n", Type);
377 if (Type == WINED3DSBT_ALL) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
382 /* Lights are not part of the changed / set structure */
383 for(j = 0; j < LIGHTMAP_SIZE; j++) {
385 LIST_FOR_EACH(e, &object->lightMap[j]) {
386 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
387 light->changed = TRUE;
388 light->enabledChanged = TRUE;
391 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
392 object->contained_render_states[j - 1] = j;
394 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
397 object->contained_transform_states[j - 1] = j;
399 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
400 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
401 object->contained_vs_consts_f[j] = j;
403 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_vs_consts_i[j] = j;
407 object->num_contained_vs_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_vs_consts_b[j] = j;
411 object->num_contained_vs_consts_b = MAX_CONST_B;
412 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
413 object->contained_ps_consts_f[j] = j;
415 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
416 for(j = 0; j < MAX_CONST_I; j++) {
417 object->contained_ps_consts_i[j] = j;
419 object->num_contained_ps_consts_i = MAX_CONST_I;
420 for(j = 0; j < MAX_CONST_B; j++) {
421 object->contained_ps_consts_b[j] = j;
423 object->num_contained_ps_consts_b = MAX_CONST_B;
424 for(i = 0; i < MAX_TEXTURES; i++) {
425 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
426 object->contained_tss_states[object->num_contained_tss_states].stage = i;
427 object->contained_tss_states[object->num_contained_tss_states].state = j;
428 object->num_contained_tss_states++;
431 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
432 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
433 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
434 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
435 object->num_contained_sampler_states++;
439 for(i = 0; i < MAX_STREAMS; i++) {
440 if(object->streamSource[i]) {
441 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
444 if(object->pIndexData) {
445 IWineD3DIndexBuffer_AddRef(object->pIndexData);
447 if(object->vertexShader) {
448 IWineD3DVertexShader_AddRef(object->vertexShader);
450 if(object->pixelShader) {
451 IWineD3DPixelShader_AddRef(object->pixelShader);
454 } else if (Type == WINED3DSBT_PIXELSTATE) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
459 object->changed.pixelShader = TRUE;
461 /* Pixel Shader Constants */
462 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
463 object->contained_ps_consts_f[i] = i;
464 object->changed.pixelShaderConstantsF[i] = TRUE;
466 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
467 for (i = 0; i < MAX_CONST_B; ++i) {
468 object->contained_ps_consts_b[i] = i;
469 object->changed.pixelShaderConstantsB[i] = TRUE;
471 object->num_contained_ps_consts_b = MAX_CONST_B;
472 for (i = 0; i < MAX_CONST_I; ++i) {
473 object->contained_ps_consts_i[i] = i;
474 object->changed.pixelShaderConstantsI[i] = TRUE;
476 object->num_contained_ps_consts_i = MAX_CONST_I;
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
479 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
480 object->contained_render_states[i] = SavedPixelStates_R[i];
482 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
483 for (j = 0; j < MAX_TEXTURES; j++) {
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
485 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
486 object->contained_tss_states[object->num_contained_tss_states].stage = j;
487 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
488 object->num_contained_tss_states++;
491 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
492 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
493 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
494 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
495 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
496 object->num_contained_sampler_states++;
499 if(object->pixelShader) {
500 IWineD3DPixelShader_AddRef(object->pixelShader);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i = 0; i < MAX_STREAMS; i++) {
507 object->streamSource[i] = NULL;
509 object->pIndexData = NULL;
510 object->vertexShader = NULL;
512 } else if (Type == WINED3DSBT_VERTEXSTATE) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
517 object->changed.vertexShader = TRUE;
519 /* Vertex Shader Constants */
520 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
521 object->changed.vertexShaderConstantsF[i] = TRUE;
522 object->contained_vs_consts_f[i] = i;
524 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
525 for (i = 0; i < MAX_CONST_B; ++i) {
526 object->changed.vertexShaderConstantsB[i] = TRUE;
527 object->contained_vs_consts_b[i] = i;
529 object->num_contained_vs_consts_b = MAX_CONST_B;
530 for (i = 0; i < MAX_CONST_I; ++i) {
531 object->changed.vertexShaderConstantsI[i] = TRUE;
532 object->contained_vs_consts_i[i] = i;
534 object->num_contained_vs_consts_i = MAX_CONST_I;
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
536 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 object->contained_render_states[i] = SavedVertexStates_R[i];
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
545 object->num_contained_tss_states++;
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
551 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
552 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
553 object->num_contained_sampler_states++;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 for(i = 0; i < MAX_STREAMS; i++) {
567 if(object->streamSource[i]) {
568 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
571 if(object->vertexShader) {
572 IWineD3DVertexShader_AddRef(object->vertexShader);
574 object->pIndexData = NULL;
575 object->pixelShader = NULL;
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
584 /* ************************************
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 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.
593 ******************************** */
595 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) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size = 1;
599 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
600 TRACE("(%p) Create surface\n",This);
602 /** FIXME: Check ranges on the inputs are valid
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
610 *******************************/
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality > 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
626 MultisampleQuality=0;
629 /** FIXME: Check that the format is supported
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
636 *********************************/
637 if (WINED3DFMT_UNKNOWN == Format) {
639 } else if (Format == WINED3DFMT_DXT1) {
640 /* DXT1 is half byte per pixel */
641 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
643 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
644 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
645 Format == WINED3DFMT_ATI2N) {
646 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
648 /* The pitch is a multiple of 4 bytes */
649 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
653 /** Create and initialise the surface resource **/
654 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
655 /* "Standalone" surface */
656 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
658 object->currentDesc.Width = Width;
659 object->currentDesc.Height = Height;
660 object->currentDesc.MultiSampleType = MultiSample;
661 object->currentDesc.MultiSampleQuality = MultisampleQuality;
662 object->glDescription.level = Level;
663 list_init(&object->overlays);
666 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
687 case WINED3DPOOL_SCRATCH:
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
722 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
723 This->ddraw_primary = (IWineD3DSurface *) object;
725 /* Look at the implementation and set the correct Vtable */
728 /* Check if a 3D adapter is available when creating gl surfaces */
730 ERR("OpenGL surfaces are not available without opengl\n");
731 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
732 HeapFree(GetProcessHeap(), 0, object);
733 return WINED3DERR_NOTAVAILABLE;
738 object->lpVtbl = &IWineGDISurface_Vtbl;
742 /* To be sure to catch this */
743 ERR("Unknown requested surface implementation %d!\n", Impl);
744 IWineD3DSurface_Release((IWineD3DSurface *) object);
745 return WINED3DERR_INVALIDCALL;
748 list_init(&object->renderbuffers);
750 /* Call the private setup routine */
751 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
756 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
757 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
758 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DTextureImpl *object;
766 unsigned int pow2Width;
767 unsigned int pow2Height;
768 const GlPixelFormatDesc *glDesc;
769 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
771 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
772 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
773 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
775 /* TODO: It should only be possible to create textures for formats
776 that are reported as supported */
777 if (WINED3DFMT_UNKNOWN >= Format) {
778 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
779 return WINED3DERR_INVALIDCALL;
782 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
783 D3DINITIALIZEBASETEXTURE(object->baseTexture);
784 object->width = Width;
785 object->height = Height;
787 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
788 object->baseTexture.minMipLookup = &minMipLookup;
789 object->baseTexture.magLookup = &magLookup;
791 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
792 object->baseTexture.magLookup = &magLookup_noFilter;
795 /** Non-power2 support **/
796 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
800 /* Find the nearest pow2 match */
801 pow2Width = pow2Height = 1;
802 while (pow2Width < Width) pow2Width <<= 1;
803 while (pow2Height < Height) pow2Height <<= 1;
805 if(pow2Width != Width || pow2Height != Height) {
807 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
808 HeapFree(GetProcessHeap(), 0, object);
810 return WINED3DERR_INVALIDCALL;
817 /** FIXME: add support for real non-power-two if it's provided by the video card **/
818 /* Precalculated scaling for 'faked' non power of two texture coords.
819 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
820 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
821 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
823 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
824 object->baseTexture.pow2Matrix[0] = 1.0;
825 object->baseTexture.pow2Matrix[5] = 1.0;
826 object->baseTexture.pow2Matrix[10] = 1.0;
827 object->baseTexture.pow2Matrix[15] = 1.0;
828 object->target = GL_TEXTURE_2D;
829 object->cond_np2 = TRUE;
832 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
833 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
834 (Width != pow2Width || Height != pow2Height) &&
835 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
837 object->baseTexture.pow2Matrix[0] = (float)Width;
838 object->baseTexture.pow2Matrix[5] = (float)Height;
839 object->baseTexture.pow2Matrix[10] = 1.0;
840 object->baseTexture.pow2Matrix[15] = 1.0;
841 object->target = GL_TEXTURE_RECTANGLE_ARB;
842 object->cond_np2 = TRUE;
843 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
845 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
846 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
847 object->baseTexture.pow2Matrix[10] = 1.0;
848 object->baseTexture.pow2Matrix[15] = 1.0;
849 object->target = GL_TEXTURE_2D;
850 object->cond_np2 = FALSE;
852 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
854 /* Calculate levels for mip mapping */
855 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
856 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
857 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
858 return WINED3DERR_INVALIDCALL;
861 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
862 return WINED3DERR_INVALIDCALL;
864 object->baseTexture.levels = 1;
865 } else if (Levels == 0) {
866 TRACE("calculating levels %d\n", object->baseTexture.levels);
867 object->baseTexture.levels++;
870 while (tmpW > 1 || tmpH > 1) {
871 tmpW = max(1, tmpW >> 1);
872 tmpH = max(1, tmpH >> 1);
873 object->baseTexture.levels++;
875 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
878 /* Generate all the surfaces */
881 for (i = 0; i < object->baseTexture.levels; i++)
883 /* use the callback to create the texture surface */
884 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
885 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
886 FIXME("Failed to create surface %p\n", object);
888 object->surfaces[i] = NULL;
889 IWineD3DTexture_Release((IWineD3DTexture *)object);
895 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
896 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
897 /* calculate the next mipmap level */
898 tmpW = max(1, tmpW >> 1);
899 tmpH = max(1, tmpH >> 1);
901 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
903 TRACE("(%p) : Created texture %p\n", This, object);
907 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
908 UINT Width, UINT Height, UINT Depth,
909 UINT Levels, DWORD Usage,
910 WINED3DFORMAT Format, WINED3DPOOL Pool,
911 IWineD3DVolumeTexture **ppVolumeTexture,
912 HANDLE *pSharedHandle, IUnknown *parent,
913 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
916 IWineD3DVolumeTextureImpl *object;
921 const GlPixelFormatDesc *glDesc;
923 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
925 /* TODO: It should only be possible to create textures for formats
926 that are reported as supported */
927 if (WINED3DFMT_UNKNOWN >= Format) {
928 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
929 return WINED3DERR_INVALIDCALL;
931 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
932 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
933 return WINED3DERR_INVALIDCALL;
936 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
937 D3DINITIALIZEBASETEXTURE(object->baseTexture);
939 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
940 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
942 object->width = Width;
943 object->height = Height;
944 object->depth = Depth;
946 /* Is NP2 support for volumes needed? */
947 object->baseTexture.pow2Matrix[ 0] = 1.0;
948 object->baseTexture.pow2Matrix[ 5] = 1.0;
949 object->baseTexture.pow2Matrix[10] = 1.0;
950 object->baseTexture.pow2Matrix[15] = 1.0;
952 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
953 object->baseTexture.minMipLookup = &minMipLookup;
954 object->baseTexture.magLookup = &magLookup;
956 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
957 object->baseTexture.magLookup = &magLookup_noFilter;
960 /* Calculate levels for mip mapping */
961 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
962 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
963 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
964 return WINED3DERR_INVALIDCALL;
967 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
968 return WINED3DERR_INVALIDCALL;
971 } else if (Levels == 0) {
972 object->baseTexture.levels++;
976 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
977 tmpW = max(1, tmpW >> 1);
978 tmpH = max(1, tmpH >> 1);
979 tmpD = max(1, tmpD >> 1);
980 object->baseTexture.levels++;
982 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
985 /* Generate all the surfaces */
990 for (i = 0; i < object->baseTexture.levels; i++)
993 /* Create the volume */
994 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
995 &object->volumes[i], pSharedHandle);
998 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
999 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1000 *ppVolumeTexture = NULL;
1004 /* Set its container to this object */
1005 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1007 /* calculate the next mipmap level */
1008 tmpW = max(1, tmpW >> 1);
1009 tmpH = max(1, tmpH >> 1);
1010 tmpD = max(1, tmpD >> 1);
1012 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1014 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1015 TRACE("(%p) : Created volume texture %p\n", This, object);
1019 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1020 UINT Width, UINT Height, UINT Depth,
1022 WINED3DFORMAT Format, WINED3DPOOL Pool,
1023 IWineD3DVolume** ppVolume,
1024 HANDLE* pSharedHandle, IUnknown *parent) {
1026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1027 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1028 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1030 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1031 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1032 return WINED3DERR_INVALIDCALL;
1035 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1037 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1038 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1040 object->currentDesc.Width = Width;
1041 object->currentDesc.Height = Height;
1042 object->currentDesc.Depth = Depth;
1043 object->bytesPerPixel = formatDesc->bpp;
1045 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1046 object->lockable = TRUE;
1047 object->locked = FALSE;
1048 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1049 object->dirty = TRUE;
1051 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1054 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1055 UINT Levels, DWORD Usage,
1056 WINED3DFORMAT Format, WINED3DPOOL Pool,
1057 IWineD3DCubeTexture **ppCubeTexture,
1058 HANDLE *pSharedHandle, IUnknown *parent,
1059 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1062 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1066 unsigned int pow2EdgeLength = EdgeLength;
1067 const GlPixelFormatDesc *glDesc;
1068 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1070 /* TODO: It should only be possible to create textures for formats
1071 that are reported as supported */
1072 if (WINED3DFMT_UNKNOWN >= Format) {
1073 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1074 return WINED3DERR_INVALIDCALL;
1077 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1078 WARN("(%p) : Tried to create not supported cube texture\n", This);
1079 return WINED3DERR_INVALIDCALL;
1082 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1083 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1085 TRACE("(%p) Create Cube Texture\n", This);
1087 /** Non-power2 support **/
1089 /* Find the nearest pow2 match */
1091 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1093 object->edgeLength = EdgeLength;
1094 /* TODO: support for native non-power 2 */
1095 /* Precalculated scaling for 'faked' non power of two texture coords */
1096 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1099 object->baseTexture.pow2Matrix[15] = 1.0;
1101 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1102 object->baseTexture.minMipLookup = &minMipLookup;
1103 object->baseTexture.magLookup = &magLookup;
1105 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1106 object->baseTexture.magLookup = &magLookup_noFilter;
1109 /* Calculate levels for mip mapping */
1110 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1111 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1112 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1113 HeapFree(GetProcessHeap(), 0, object);
1114 *ppCubeTexture = NULL;
1116 return WINED3DERR_INVALIDCALL;
1119 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1120 HeapFree(GetProcessHeap(), 0, object);
1121 *ppCubeTexture = NULL;
1123 return WINED3DERR_INVALIDCALL;
1126 } else if (Levels == 0) {
1127 object->baseTexture.levels++;
1130 tmpW = max(1, tmpW >> 1);
1131 object->baseTexture.levels++;
1133 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1136 /* Generate all the surfaces */
1138 for (i = 0; i < object->baseTexture.levels; i++) {
1140 /* Create the 6 faces */
1141 for (j = 0; j < 6; j++) {
1143 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1144 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1146 if(hr!= WINED3D_OK) {
1150 for (l = 0; l < j; l++) {
1151 IWineD3DSurface_Release(object->surfaces[l][i]);
1153 for (k = 0; k < i; k++) {
1154 for (l = 0; l < 6; l++) {
1155 IWineD3DSurface_Release(object->surfaces[l][k]);
1159 FIXME("(%p) Failed to create surface\n",object);
1160 HeapFree(GetProcessHeap(),0,object);
1161 *ppCubeTexture = NULL;
1164 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1165 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1167 tmpW = max(1, tmpW >> 1);
1169 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1171 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1172 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1176 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1178 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1179 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1180 const IWineD3DQueryVtbl *vtable;
1182 /* Just a check to see if we support this type of query */
1184 case WINED3DQUERYTYPE_OCCLUSION:
1185 TRACE("(%p) occlusion query\n", This);
1186 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1189 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1191 vtable = &IWineD3DOcclusionQuery_Vtbl;
1194 case WINED3DQUERYTYPE_EVENT:
1195 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1196 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1197 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1199 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1201 vtable = &IWineD3DEventQuery_Vtbl;
1205 case WINED3DQUERYTYPE_VCACHE:
1206 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1207 case WINED3DQUERYTYPE_VERTEXSTATS:
1208 case WINED3DQUERYTYPE_TIMESTAMP:
1209 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1210 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1211 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1212 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1213 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1214 case WINED3DQUERYTYPE_PIXELTIMINGS:
1215 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1216 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1218 /* Use the base Query vtable until we have a special one for each query */
1219 vtable = &IWineD3DQuery_Vtbl;
1220 FIXME("(%p) Unhandled query type %d\n", This, Type);
1222 if(NULL == ppQuery || hr != WINED3D_OK) {
1226 D3DCREATEOBJECTINSTANCE(object, Query)
1227 object->lpVtbl = vtable;
1228 object->type = Type;
1229 object->state = QUERY_CREATED;
1230 /* allocated the 'extended' data based on the type of query requested */
1232 case WINED3DQUERYTYPE_OCCLUSION:
1233 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1234 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1236 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1237 TRACE("(%p) Allocating data for an occlusion query\n", This);
1238 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1241 case WINED3DQUERYTYPE_EVENT:
1242 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1243 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1245 if(GL_SUPPORT(APPLE_FENCE)) {
1246 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1247 checkGLcall("glGenFencesAPPLE");
1248 } else if(GL_SUPPORT(NV_FENCE)) {
1249 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1250 checkGLcall("glGenFencesNV");
1254 case WINED3DQUERYTYPE_VCACHE:
1255 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1256 case WINED3DQUERYTYPE_VERTEXSTATS:
1257 case WINED3DQUERYTYPE_TIMESTAMP:
1258 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1259 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1260 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1261 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1262 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1263 case WINED3DQUERYTYPE_PIXELTIMINGS:
1264 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1265 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1267 object->extendedData = 0;
1268 FIXME("(%p) Unhandled query type %d\n",This , Type);
1270 TRACE("(%p) : Created Query %p\n", This, object);
1274 /*****************************************************************************
1275 * IWineD3DDeviceImpl_SetupFullscreenWindow
1277 * Helper function that modifies a HWND's Style and ExStyle for proper
1281 * iface: Pointer to the IWineD3DDevice interface
1282 * window: Window to setup
1284 *****************************************************************************/
1285 static LONG fullscreen_style(LONG orig_style) {
1286 LONG style = orig_style;
1287 style &= ~WS_CAPTION;
1288 style &= ~WS_THICKFRAME;
1290 /* Make sure the window is managed, otherwise we won't get keyboard input */
1291 style |= WS_POPUP | WS_SYSMENU;
1296 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1297 LONG exStyle = orig_exStyle;
1299 /* Filter out window decorations */
1300 exStyle &= ~WS_EX_WINDOWEDGE;
1301 exStyle &= ~WS_EX_CLIENTEDGE;
1306 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1309 LONG style, exStyle;
1310 /* Don't do anything if an original style is stored.
1311 * That shouldn't happen
1313 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1314 if (This->style || This->exStyle) {
1315 ERR("(%p): Want to change the window parameters of HWND %p, but "
1316 "another style is stored for restoration afterwards\n", This, window);
1319 /* Get the parameters and save them */
1320 style = GetWindowLongW(window, GWL_STYLE);
1321 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1322 This->style = style;
1323 This->exStyle = exStyle;
1325 style = fullscreen_style(style);
1326 exStyle = fullscreen_exStyle(exStyle);
1328 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1329 This->style, This->exStyle, style, exStyle);
1331 SetWindowLongW(window, GWL_STYLE, style);
1332 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1334 /* Inform the window about the update. */
1335 SetWindowPos(window, HWND_TOP, 0, 0,
1336 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1337 ShowWindow(window, SW_NORMAL);
1340 /*****************************************************************************
1341 * IWineD3DDeviceImpl_RestoreWindow
1343 * Helper function that restores a windows' properties when taking it out
1344 * of fullscreen mode
1347 * iface: Pointer to the IWineD3DDevice interface
1348 * window: Window to setup
1350 *****************************************************************************/
1351 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1353 LONG style, exStyle;
1355 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1356 * switch, do nothing
1358 if (!This->style && !This->exStyle) return;
1360 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1361 This, window, This->style, This->exStyle);
1363 style = GetWindowLongW(window, GWL_STYLE);
1364 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1366 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1367 * Some applications change it before calling Reset() when switching between windowed and
1368 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1370 if(style == fullscreen_style(This->style) &&
1371 exStyle == fullscreen_style(This->exStyle)) {
1372 SetWindowLongW(window, GWL_STYLE, This->style);
1373 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1376 /* Delete the old values */
1380 /* Inform the window about the update */
1381 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1382 0, 0, 0, 0, /* Pos, Size, ignored */
1383 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1386 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1387 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1389 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1390 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1394 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1395 HRESULT hr = WINED3D_OK;
1396 IUnknown *bufferParent;
1397 BOOL displaymode_set = FALSE;
1398 WINED3DDISPLAYMODE Mode;
1399 const StaticPixelFormatDesc *formatDesc;
1401 TRACE("(%p) : Created Additional Swap Chain\n", This);
1403 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1404 * does a device hold a reference to a swap chain giving them a lifetime of the device
1405 * or does the swap chain notify the device of its destruction.
1406 *******************************/
1408 /* Check the params */
1409 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1410 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1411 return WINED3DERR_INVALIDCALL;
1412 } else if (pPresentationParameters->BackBufferCount > 1) {
1413 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");
1416 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1418 /*********************
1419 * Lookup the window Handle and the relating X window handle
1420 ********************/
1422 /* Setup hwnd we are using, plus which display this equates to */
1423 object->win_handle = pPresentationParameters->hDeviceWindow;
1424 if (!object->win_handle) {
1425 object->win_handle = This->createParms.hFocusWindow;
1427 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1429 hDc = GetDC(object->win_handle);
1430 TRACE("Using hDc %p\n", hDc);
1433 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1434 return WINED3DERR_NOTAVAILABLE;
1437 /* Get info on the current display setup */
1438 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1439 object->orig_width = Mode.Width;
1440 object->orig_height = Mode.Height;
1441 object->orig_fmt = Mode.Format;
1442 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1444 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1445 * then the corresponding dimension of the client area of the hDeviceWindow
1446 * (or the focus window, if hDeviceWindow is NULL) is taken.
1447 **********************/
1449 if (pPresentationParameters->Windowed &&
1450 ((pPresentationParameters->BackBufferWidth == 0) ||
1451 (pPresentationParameters->BackBufferHeight == 0) ||
1452 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1455 GetClientRect(object->win_handle, &Rect);
1457 if (pPresentationParameters->BackBufferWidth == 0) {
1458 pPresentationParameters->BackBufferWidth = Rect.right;
1459 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1461 if (pPresentationParameters->BackBufferHeight == 0) {
1462 pPresentationParameters->BackBufferHeight = Rect.bottom;
1463 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1465 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1466 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1467 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1471 /* Put the correct figures in the presentation parameters */
1472 TRACE("Copying across presentation parameters\n");
1473 object->presentParms = *pPresentationParameters;
1475 TRACE("calling rendertarget CB\n");
1476 hr = D3DCB_CreateRenderTarget(This->parent,
1478 object->presentParms.BackBufferWidth,
1479 object->presentParms.BackBufferHeight,
1480 object->presentParms.BackBufferFormat,
1481 object->presentParms.MultiSampleType,
1482 object->presentParms.MultiSampleQuality,
1483 TRUE /* Lockable */,
1484 &object->frontBuffer,
1485 NULL /* pShared (always null)*/);
1486 if (object->frontBuffer != NULL) {
1487 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1488 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1490 ERR("Failed to create the front buffer\n");
1494 /*********************
1495 * Windowed / Fullscreen
1496 *******************/
1499 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1500 * so we should really check to see if there is a fullscreen swapchain already
1501 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1502 **************************************/
1504 if (!pPresentationParameters->Windowed) {
1505 WINED3DDISPLAYMODE mode;
1508 /* Change the display settings */
1509 mode.Width = pPresentationParameters->BackBufferWidth;
1510 mode.Height = pPresentationParameters->BackBufferHeight;
1511 mode.Format = pPresentationParameters->BackBufferFormat;
1512 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1514 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1515 displaymode_set = TRUE;
1516 IWineD3DDevice_SetFullscreen(iface, TRUE);
1520 * Create an opengl context for the display visual
1521 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1522 * use different properties after that point in time. FIXME: How to handle when requested format
1523 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1524 * it chooses is identical to the one already being used!
1525 **********************************/
1526 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1528 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1529 if(!object->context)
1530 return E_OUTOFMEMORY;
1531 object->num_contexts = 1;
1533 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1534 if (!object->context[0]) {
1535 ERR("Failed to create a new context\n");
1536 hr = WINED3DERR_NOTAVAILABLE;
1539 TRACE("Context created (HWND=%p, glContext=%p)\n",
1540 object->win_handle, object->context[0]->glCtx);
1543 /*********************
1544 * Create the back, front and stencil buffers
1545 *******************/
1546 if(object->presentParms.BackBufferCount > 0) {
1549 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1550 if(!object->backBuffer) {
1551 ERR("Out of memory\n");
1556 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1557 TRACE("calling rendertarget CB\n");
1558 hr = D3DCB_CreateRenderTarget(This->parent,
1560 object->presentParms.BackBufferWidth,
1561 object->presentParms.BackBufferHeight,
1562 object->presentParms.BackBufferFormat,
1563 object->presentParms.MultiSampleType,
1564 object->presentParms.MultiSampleQuality,
1565 TRUE /* Lockable */,
1566 &object->backBuffer[i],
1567 NULL /* pShared (always null)*/);
1568 if(hr == WINED3D_OK && object->backBuffer[i]) {
1569 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1571 ERR("Cannot create new back buffer\n");
1575 glDrawBuffer(GL_BACK);
1576 checkGLcall("glDrawBuffer(GL_BACK)");
1580 object->backBuffer = NULL;
1582 /* Single buffering - draw to front buffer */
1584 glDrawBuffer(GL_FRONT);
1585 checkGLcall("glDrawBuffer(GL_FRONT)");
1589 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1590 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1591 TRACE("Creating depth stencil buffer\n");
1592 if (This->auto_depth_stencil_buffer == NULL ) {
1593 hr = D3DCB_CreateDepthStencil(This->parent,
1595 object->presentParms.BackBufferWidth,
1596 object->presentParms.BackBufferHeight,
1597 object->presentParms.AutoDepthStencilFormat,
1598 object->presentParms.MultiSampleType,
1599 object->presentParms.MultiSampleQuality,
1600 FALSE /* FIXME: Discard */,
1601 &This->auto_depth_stencil_buffer,
1602 NULL /* pShared (always null)*/ );
1603 if (This->auto_depth_stencil_buffer != NULL)
1604 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1607 /** TODO: A check on width, height and multisample types
1608 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1609 ****************************/
1610 object->wantsDepthStencilBuffer = TRUE;
1612 object->wantsDepthStencilBuffer = FALSE;
1615 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1617 TRACE("Created swapchain %p\n", object);
1618 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1622 if (displaymode_set) {
1626 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1629 /* Change the display settings */
1630 memset(&devmode, 0, sizeof(devmode));
1631 devmode.dmSize = sizeof(devmode);
1632 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1633 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1634 devmode.dmPelsWidth = object->orig_width;
1635 devmode.dmPelsHeight = object->orig_height;
1636 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1639 if (object->backBuffer) {
1641 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1642 if(object->backBuffer[i]) {
1643 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1644 IUnknown_Release(bufferParent); /* once for the get parent */
1645 if (IUnknown_Release(bufferParent) > 0) {
1646 FIXME("(%p) Something's still holding the back buffer\n",This);
1650 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1651 object->backBuffer = NULL;
1653 if(object->context[0])
1654 DestroyContext(This, object->context[0]);
1655 if(object->frontBuffer) {
1656 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1657 IUnknown_Release(bufferParent); /* once for the get parent */
1658 if (IUnknown_Release(bufferParent) > 0) {
1659 FIXME("(%p) Something's still holding the front buffer\n",This);
1662 HeapFree(GetProcessHeap(), 0, object);
1666 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1667 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1669 TRACE("(%p)\n", This);
1671 return This->NumberOfSwapChains;
1674 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1676 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1678 if(iSwapChain < This->NumberOfSwapChains) {
1679 *pSwapChain = This->swapchains[iSwapChain];
1680 IWineD3DSwapChain_AddRef(*pSwapChain);
1681 TRACE("(%p) returning %p\n", This, *pSwapChain);
1684 TRACE("Swapchain out of range\n");
1686 return WINED3DERR_INVALIDCALL;
1691 * Vertex Declaration
1693 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1694 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1696 IWineD3DVertexDeclarationImpl *object = NULL;
1697 HRESULT hr = WINED3D_OK;
1699 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1700 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1702 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1704 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1706 *ppVertexDeclaration = NULL;
1707 HeapFree(GetProcessHeap(), 0, object);
1713 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1714 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1716 unsigned int idx, idx2;
1717 unsigned int offset;
1718 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1719 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1720 BOOL has_blend_idx = has_blend &&
1721 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1722 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1723 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1724 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1725 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1726 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1727 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1729 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1730 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1732 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1733 WINED3DVERTEXELEMENT *elements = NULL;
1736 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1737 if (has_blend_idx) num_blends--;
1739 /* Compute declaration size */
1740 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1741 has_psize + has_diffuse + has_specular + num_textures + 1;
1743 /* convert the declaration */
1744 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1748 elements[size-1] = end_element;
1751 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1752 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1753 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1756 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1757 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1759 elements[idx].UsageIndex = 0;
1762 if (has_blend && (num_blends > 0)) {
1763 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1764 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1766 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1767 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1768 elements[idx].UsageIndex = 0;
1771 if (has_blend_idx) {
1772 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1773 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1774 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1775 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1776 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1778 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1779 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1780 elements[idx].UsageIndex = 0;
1784 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1785 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1786 elements[idx].UsageIndex = 0;
1790 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1791 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1792 elements[idx].UsageIndex = 0;
1796 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1797 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1798 elements[idx].UsageIndex = 0;
1802 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1803 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1804 elements[idx].UsageIndex = 1;
1807 for (idx2 = 0; idx2 < num_textures; idx2++) {
1808 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1809 switch (numcoords) {
1810 case WINED3DFVF_TEXTUREFORMAT1:
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1813 case WINED3DFVF_TEXTUREFORMAT2:
1814 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1816 case WINED3DFVF_TEXTUREFORMAT3:
1817 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1819 case WINED3DFVF_TEXTUREFORMAT4:
1820 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1823 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1824 elements[idx].UsageIndex = idx2;
1828 /* Now compute offsets, and initialize the rest of the fields */
1829 for (idx = 0, offset = 0; idx < size-1; idx++) {
1830 elements[idx].Stream = 0;
1831 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1832 elements[idx].Offset = offset;
1833 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1836 *ppVertexElements = elements;
1840 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1841 WINED3DVERTEXELEMENT* elements = NULL;
1842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1846 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1847 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1849 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1850 HeapFree(GetProcessHeap(), 0, elements);
1851 if (hr != S_OK) return hr;
1856 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1858 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1859 HRESULT hr = WINED3D_OK;
1860 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1861 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1863 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1865 if (vertex_declaration) {
1866 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1869 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1871 if (WINED3D_OK != hr) {
1872 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1873 IWineD3DVertexShader_Release(*ppVertexShader);
1874 return WINED3DERR_INVALIDCALL;
1876 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1881 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1883 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1884 HRESULT hr = WINED3D_OK;
1886 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1887 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1888 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1889 if (WINED3D_OK == hr) {
1890 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1891 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1893 WARN("(%p) : Failed to create pixel shader\n", This);
1899 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1901 IWineD3DPaletteImpl *object;
1903 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1905 /* Create the new object */
1906 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1908 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1909 return E_OUTOFMEMORY;
1912 object->lpVtbl = &IWineD3DPalette_Vtbl;
1914 object->Flags = Flags;
1915 object->parent = Parent;
1916 object->wineD3DDevice = This;
1917 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1919 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1922 HeapFree( GetProcessHeap(), 0, object);
1923 return E_OUTOFMEMORY;
1926 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1928 IWineD3DPalette_Release((IWineD3DPalette *) object);
1932 *Palette = (IWineD3DPalette *) object;
1937 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1941 HDC dcb = NULL, dcs = NULL;
1942 WINEDDCOLORKEY colorkey;
1944 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1947 GetObjectA(hbm, sizeof(BITMAP), &bm);
1948 dcb = CreateCompatibleDC(NULL);
1950 SelectObject(dcb, hbm);
1954 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1955 * couldn't be loaded
1957 memset(&bm, 0, sizeof(bm));
1962 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1963 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1964 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1966 ERR("Wine logo requested, but failed to create surface\n");
1971 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1972 if(FAILED(hr)) goto out;
1973 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1974 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1976 colorkey.dwColorSpaceLowValue = 0;
1977 colorkey.dwColorSpaceHighValue = 0;
1978 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1980 /* Fill the surface with a white color to show that wined3d is there */
1981 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1994 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1996 /* Under DirectX you can have texture stage operations even if no texture is
1997 bound, whereas opengl will only do texture operations when a valid texture is
1998 bound. We emulate this by creating dummy textures and binding them to each
1999 texture stage, but disable all stages by default. Hence if a stage is enabled
2000 then the default texture will kick in until replaced by a SetTexture call */
2003 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2004 /* The dummy texture does not have client storage backing */
2005 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2006 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2008 for (i = 0; i < GL_LIMITS(textures); i++) {
2009 GLubyte white = 255;
2011 /* Make appropriate texture active */
2012 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2013 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2014 checkGLcall("glActiveTextureARB");
2016 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2019 /* Generate an opengl texture name */
2020 glGenTextures(1, &This->dummyTextureName[i]);
2021 checkGLcall("glGenTextures");
2022 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2024 /* Generate a dummy 2d texture (not using 1d because they cause many
2025 * DRI drivers fall back to sw) */
2026 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2027 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2028 checkGLcall("glBindTexture");
2030 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2031 checkGLcall("glTexImage2D");
2033 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2034 /* Reenable because if supported it is enabled by default */
2035 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2036 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2042 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2044 IWineD3DSwapChainImpl *swapchain = NULL;
2049 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2050 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2051 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2053 /* TODO: Test if OpenGL is compiled in and loaded */
2055 TRACE("(%p) : Creating stateblock\n", This);
2056 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2057 hr = IWineD3DDevice_CreateStateBlock(iface,
2059 (IWineD3DStateBlock **)&This->stateBlock,
2061 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2062 WARN("Failed to create stateblock\n");
2065 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2066 This->updateStateBlock = This->stateBlock;
2067 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2069 hr = allocate_shader_constants(This->updateStateBlock);
2070 if (WINED3D_OK != hr) {
2074 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2075 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2076 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2078 This->NumberOfPalettes = 1;
2079 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2080 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2081 ERR("Out of memory!\n");
2084 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2085 if(!This->palettes[0]) {
2086 ERR("Out of memory!\n");
2089 for (i = 0; i < 256; ++i) {
2090 This->palettes[0][i].peRed = 0xFF;
2091 This->palettes[0][i].peGreen = 0xFF;
2092 This->palettes[0][i].peBlue = 0xFF;
2093 This->palettes[0][i].peFlags = 0xFF;
2095 This->currentPalette = 0;
2097 /* Initialize the texture unit mapping to a 1:1 mapping */
2098 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2099 if (state < GL_LIMITS(fragment_samplers)) {
2100 This->texUnitMap[state] = state;
2101 This->rev_tex_unit_map[state] = state;
2103 This->texUnitMap[state] = -1;
2104 This->rev_tex_unit_map[state] = -1;
2108 /* Setup the implicit swapchain */
2109 TRACE("Creating implicit swapchain\n");
2110 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2111 if (FAILED(hr) || !swapchain) {
2112 WARN("Failed to create implicit swapchain\n");
2116 This->NumberOfSwapChains = 1;
2117 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2118 if(!This->swapchains) {
2119 ERR("Out of memory!\n");
2122 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2124 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2125 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2126 This->render_targets[0] = swapchain->backBuffer[0];
2127 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2130 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2131 This->render_targets[0] = swapchain->frontBuffer;
2132 This->lastActiveRenderTarget = swapchain->frontBuffer;
2134 IWineD3DSurface_AddRef(This->render_targets[0]);
2135 This->activeContext = swapchain->context[0];
2136 This->lastThread = GetCurrentThreadId();
2138 /* Depth Stencil support */
2139 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2140 if (NULL != This->stencilBufferTarget) {
2141 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2144 hr = This->shader_backend->shader_alloc_private(iface);
2146 TRACE("Shader private data couldn't be allocated\n");
2149 hr = This->frag_pipe->alloc_private(iface);
2151 TRACE("Fragment pipeline private data couldn't be allocated\n");
2155 /* Set up some starting GL setup */
2157 /* Setup all the devices defaults */
2158 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2159 create_dummy_textures(This);
2164 IWineD3DImpl_CheckGraphicsMemory();
2167 { /* Set a default viewport */
2171 vp.Width = pPresentationParameters->BackBufferWidth;
2172 vp.Height = pPresentationParameters->BackBufferHeight;
2175 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2178 /* Initialize the current view state */
2179 This->view_ident = 1;
2180 This->contexts[0]->last_was_rhw = 0;
2181 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2182 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2184 switch(wined3d_settings.offscreen_rendering_mode) {
2187 This->offscreenBuffer = GL_BACK;
2190 case ORM_BACKBUFFER:
2192 if(This->activeContext->aux_buffers > 0) {
2193 TRACE("Using auxilliary buffer for offscreen rendering\n");
2194 This->offscreenBuffer = GL_AUX0;
2196 TRACE("Using back buffer for offscreen rendering\n");
2197 This->offscreenBuffer = GL_BACK;
2202 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2205 /* Clear the screen */
2206 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2207 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2210 This->d3d_initialized = TRUE;
2212 if(wined3d_settings.logo) {
2213 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2215 This->highest_dirty_ps_const = 0;
2216 This->highest_dirty_vs_const = 0;
2220 HeapFree(GetProcessHeap(), 0, This->render_targets);
2221 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2222 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2223 HeapFree(GetProcessHeap(), 0, This->swapchains);
2224 This->NumberOfSwapChains = 0;
2225 if(This->palettes) {
2226 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2227 HeapFree(GetProcessHeap(), 0, This->palettes);
2229 This->NumberOfPalettes = 0;
2231 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2233 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2234 if(This->stateBlock) {
2235 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2236 This->stateBlock = NULL;
2238 This->frag_pipe->free_private(iface);
2239 This->shader_backend->shader_free_private(iface);
2243 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2247 TRACE("(%p)\n", This);
2249 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2251 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2252 * it was created. Thus make sure a context is active for the glDelete* calls
2254 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2256 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2258 TRACE("Deleting high order patches\n");
2259 for(i = 0; i < PATCHMAP_SIZE; i++) {
2260 struct list *e1, *e2;
2261 struct WineD3DRectPatch *patch;
2262 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2263 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2264 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2268 /* Delete the palette conversion shader if it is around */
2269 if(This->paletteConversionShader) {
2271 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2273 This->paletteConversionShader = 0;
2276 /* Delete the pbuffer context if there is any */
2277 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2279 /* Delete the mouse cursor texture */
2280 if(This->cursorTexture) {
2282 glDeleteTextures(1, &This->cursorTexture);
2284 This->cursorTexture = 0;
2287 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2288 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2290 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2291 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2294 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2295 * private data, it might contain opengl pointers
2297 if(This->depth_blt_texture) {
2298 glDeleteTextures(1, &This->depth_blt_texture);
2299 This->depth_blt_texture = 0;
2301 if (This->depth_blt_rb) {
2302 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2303 This->depth_blt_rb = 0;
2304 This->depth_blt_rb_w = 0;
2305 This->depth_blt_rb_h = 0;
2308 /* Release the update stateblock */
2309 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2310 if(This->updateStateBlock != This->stateBlock)
2311 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2313 This->updateStateBlock = NULL;
2315 { /* because were not doing proper internal refcounts releasing the primary state block
2316 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2317 to set this->stateBlock = NULL; first */
2318 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2319 This->stateBlock = NULL;
2321 /* Release the stateblock */
2322 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2323 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2327 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2328 This->frag_pipe->free_private(iface);
2329 This->shader_backend->shader_free_private(iface);
2331 /* Release the buffers (with sanity checks)*/
2332 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2333 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2334 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2335 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2337 This->stencilBufferTarget = NULL;
2339 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2340 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2341 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2343 TRACE("Setting rendertarget to NULL\n");
2344 This->render_targets[0] = NULL;
2346 if (This->auto_depth_stencil_buffer) {
2347 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2348 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2350 This->auto_depth_stencil_buffer = NULL;
2353 for(i=0; i < This->NumberOfSwapChains; i++) {
2354 TRACE("Releasing the implicit swapchain %d\n", i);
2355 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2356 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2360 HeapFree(GetProcessHeap(), 0, This->swapchains);
2361 This->swapchains = NULL;
2362 This->NumberOfSwapChains = 0;
2364 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2365 HeapFree(GetProcessHeap(), 0, This->palettes);
2366 This->palettes = NULL;
2367 This->NumberOfPalettes = 0;
2369 HeapFree(GetProcessHeap(), 0, This->render_targets);
2370 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2371 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2372 This->render_targets = NULL;
2373 This->fbo_color_attachments = NULL;
2374 This->draw_buffers = NULL;
2376 This->d3d_initialized = FALSE;
2380 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2382 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2384 /* Setup the window for fullscreen mode */
2385 if(fullscreen && !This->ddraw_fullscreen) {
2386 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2387 } else if(!fullscreen && This->ddraw_fullscreen) {
2388 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2391 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2392 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2393 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2396 This->ddraw_fullscreen = fullscreen;
2399 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2400 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2401 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2403 * There is no way to deactivate thread safety once it is enabled.
2405 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2408 /*For now just store the flag(needed in case of ddraw) */
2409 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2414 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2418 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2421 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2423 /* Resize the screen even without a window:
2424 * The app could have unset it with SetCooperativeLevel, but not called
2425 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2426 * but we don't have any hwnd
2429 memset(&devmode, 0, sizeof(devmode));
2430 devmode.dmSize = sizeof(devmode);
2431 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2432 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2433 devmode.dmPelsWidth = pMode->Width;
2434 devmode.dmPelsHeight = pMode->Height;
2436 devmode.dmDisplayFrequency = pMode->RefreshRate;
2437 if (pMode->RefreshRate != 0) {
2438 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2441 /* Only change the mode if necessary */
2442 if( (This->ddraw_width == pMode->Width) &&
2443 (This->ddraw_height == pMode->Height) &&
2444 (This->ddraw_format == pMode->Format) &&
2445 (pMode->RefreshRate == 0) ) {
2449 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2450 if (ret != DISP_CHANGE_SUCCESSFUL) {
2451 if(devmode.dmDisplayFrequency != 0) {
2452 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2453 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2454 devmode.dmDisplayFrequency = 0;
2455 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2457 if(ret != DISP_CHANGE_SUCCESSFUL) {
2458 return WINED3DERR_NOTAVAILABLE;
2462 /* Store the new values */
2463 This->ddraw_width = pMode->Width;
2464 This->ddraw_height = pMode->Height;
2465 This->ddraw_format = pMode->Format;
2467 /* Only do this with a window of course, and only if we're fullscreened */
2468 if(This->ddraw_window && This->ddraw_fullscreen)
2469 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2471 /* And finally clip mouse to our screen */
2472 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2473 ClipCursor(&clip_rc);
2478 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2480 *ppD3D= This->wineD3D;
2481 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2482 IWineD3D_AddRef(*ppD3D);
2486 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2489 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2490 (This->adapter->TextureRam/(1024*1024)),
2491 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2492 /* return simulated texture memory left */
2493 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2501 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 /* Update the current state block */
2505 This->updateStateBlock->changed.fvf = TRUE;
2507 if(This->updateStateBlock->fvf == fvf) {
2508 TRACE("Application is setting the old fvf over, nothing to do\n");
2512 This->updateStateBlock->fvf = fvf;
2513 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2519 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2522 *pfvf = This->stateBlock->fvf;
2527 * Get / Set Stream Source
2529 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2531 IWineD3DVertexBuffer *oldSrc;
2533 if (StreamNumber >= MAX_STREAMS) {
2534 WARN("Stream out of range %d\n", StreamNumber);
2535 return WINED3DERR_INVALIDCALL;
2536 } else if(OffsetInBytes & 0x3) {
2537 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2538 return WINED3DERR_INVALIDCALL;
2541 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2542 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2544 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2546 if(oldSrc == pStreamData &&
2547 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2548 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2549 TRACE("Application is setting the old values over, nothing to do\n");
2553 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2555 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2556 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2559 /* Handle recording of state blocks */
2560 if (This->isRecordingState) {
2561 TRACE("Recording... not performing anything\n");
2562 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2563 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2567 /* Need to do a getParent and pass the references up */
2568 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2569 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2570 so for now, just count internally */
2571 if (pStreamData != NULL) {
2572 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2573 InterlockedIncrement(&vbImpl->bindCount);
2574 IWineD3DVertexBuffer_AddRef(pStreamData);
2576 if (oldSrc != NULL) {
2577 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2578 IWineD3DVertexBuffer_Release(oldSrc);
2581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2586 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2590 This->stateBlock->streamSource[StreamNumber],
2591 This->stateBlock->streamOffset[StreamNumber],
2592 This->stateBlock->streamStride[StreamNumber]);
2594 if (StreamNumber >= MAX_STREAMS) {
2595 WARN("Stream out of range %d\n", StreamNumber);
2596 return WINED3DERR_INVALIDCALL;
2598 *pStream = This->stateBlock->streamSource[StreamNumber];
2599 *pStride = This->stateBlock->streamStride[StreamNumber];
2601 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2604 if (*pStream != NULL) {
2605 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2610 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2612 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2613 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2615 /* Verify input at least in d3d9 this is invalid*/
2616 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2617 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2618 return WINED3DERR_INVALIDCALL;
2620 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2621 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2622 return WINED3DERR_INVALIDCALL;
2625 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2626 return WINED3DERR_INVALIDCALL;
2629 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2630 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2632 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2633 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2635 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2636 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2643 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2647 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2649 TRACE("(%p) : returning %d\n", This, *Divider);
2655 * Get / Set & Multiply Transform
2657 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2660 /* Most of this routine, comments included copied from ddraw tree initially: */
2661 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2663 /* Handle recording of state blocks */
2664 if (This->isRecordingState) {
2665 TRACE("Recording... not performing anything\n");
2666 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2667 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2672 * If the new matrix is the same as the current one,
2673 * we cut off any further processing. this seems to be a reasonable
2674 * optimization because as was noticed, some apps (warcraft3 for example)
2675 * tend towards setting the same matrix repeatedly for some reason.
2677 * From here on we assume that the new matrix is different, wherever it matters.
2679 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2680 TRACE("The app is setting the same matrix over again\n");
2683 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2687 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2688 where ViewMat = Camera space, WorldMat = world space.
2690 In OpenGL, camera and world space is combined into GL_MODELVIEW
2691 matrix. The Projection matrix stay projection matrix.
2694 /* Capture the times we can just ignore the change for now */
2695 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2696 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2697 /* Handled by the state manager */
2700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2704 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2706 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2707 *pMatrix = This->stateBlock->transforms[State];
2711 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2712 WINED3DMATRIX *mat = NULL;
2715 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2716 * below means it will be recorded in a state block change, but it
2717 * works regardless where it is recorded.
2718 * If this is found to be wrong, change to StateBlock.
2720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2721 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2723 if (State < HIGHEST_TRANSFORMSTATE)
2725 mat = &This->updateStateBlock->transforms[State];
2727 FIXME("Unhandled transform state!!\n");
2730 multiply_matrix(&temp, mat, pMatrix);
2732 /* Apply change via set transform - will reapply to eg. lights this way */
2733 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2739 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2740 you can reference any indexes you want as long as that number max are enabled at any
2741 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2742 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2743 but when recording, just build a chain pretty much of commands to be replayed. */
2745 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2747 PLIGHTINFOEL *object = NULL;
2748 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2754 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2758 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2759 return WINED3DERR_INVALIDCALL;
2762 switch(pLight->Type) {
2763 case WINED3DLIGHT_POINT:
2764 case WINED3DLIGHT_SPOT:
2765 case WINED3DLIGHT_PARALLELPOINT:
2766 case WINED3DLIGHT_GLSPOT:
2767 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2770 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2771 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2772 return WINED3DERR_INVALIDCALL;
2776 case WINED3DLIGHT_DIRECTIONAL:
2777 /* Ignores attenuation */
2781 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2782 return WINED3DERR_INVALIDCALL;
2785 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2786 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2787 if(object->OriginalIndex == Index) break;
2792 TRACE("Adding new light\n");
2793 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2795 ERR("Out of memory error when allocating a light\n");
2796 return E_OUTOFMEMORY;
2798 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2799 object->glIndex = -1;
2800 object->OriginalIndex = Index;
2801 object->changed = TRUE;
2804 /* Initialize the object */
2805 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,
2806 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2807 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2808 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2809 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2810 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2811 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2813 /* Save away the information */
2814 object->OriginalParms = *pLight;
2816 switch (pLight->Type) {
2817 case WINED3DLIGHT_POINT:
2819 object->lightPosn[0] = pLight->Position.x;
2820 object->lightPosn[1] = pLight->Position.y;
2821 object->lightPosn[2] = pLight->Position.z;
2822 object->lightPosn[3] = 1.0f;
2823 object->cutoff = 180.0f;
2827 case WINED3DLIGHT_DIRECTIONAL:
2829 object->lightPosn[0] = -pLight->Direction.x;
2830 object->lightPosn[1] = -pLight->Direction.y;
2831 object->lightPosn[2] = -pLight->Direction.z;
2832 object->lightPosn[3] = 0.0;
2833 object->exponent = 0.0f;
2834 object->cutoff = 180.0f;
2837 case WINED3DLIGHT_SPOT:
2839 object->lightPosn[0] = pLight->Position.x;
2840 object->lightPosn[1] = pLight->Position.y;
2841 object->lightPosn[2] = pLight->Position.z;
2842 object->lightPosn[3] = 1.0;
2845 object->lightDirn[0] = pLight->Direction.x;
2846 object->lightDirn[1] = pLight->Direction.y;
2847 object->lightDirn[2] = pLight->Direction.z;
2848 object->lightDirn[3] = 1.0;
2851 * opengl-ish and d3d-ish spot lights use too different models for the
2852 * light "intensity" as a function of the angle towards the main light direction,
2853 * so we only can approximate very roughly.
2854 * however spot lights are rather rarely used in games (if ever used at all).
2855 * furthermore if still used, probably nobody pays attention to such details.
2857 if (pLight->Falloff == 0) {
2858 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2859 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2860 * will always be 1.0 for both of them, and we don't have to care for the
2861 * rest of the rather complex calculation
2863 object->exponent = 0;
2865 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2866 if (rho < 0.0001) rho = 0.0001f;
2867 object->exponent = -0.3/log(cos(rho/2));
2869 if (object->exponent > 128.0) {
2870 object->exponent = 128.0;
2872 object->cutoff = pLight->Phi*90/M_PI;
2878 FIXME("Unrecognized light type %d\n", pLight->Type);
2881 /* Update the live definitions if the light is currently assigned a glIndex */
2882 if (object->glIndex != -1 && !This->isRecordingState) {
2883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2888 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2889 PLIGHTINFOEL *lightInfo = NULL;
2890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2891 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2893 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2895 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2896 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2897 if(lightInfo->OriginalIndex == Index) break;
2901 if (lightInfo == NULL) {
2902 TRACE("Light information requested but light not defined\n");
2903 return WINED3DERR_INVALIDCALL;
2906 *pLight = lightInfo->OriginalParms;
2911 * Get / Set Light Enable
2912 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2914 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2915 PLIGHTINFOEL *lightInfo = NULL;
2916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2917 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2919 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2921 /* Tests show true = 128...not clear why */
2922 Enable = Enable? 128: 0;
2924 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2925 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2926 if(lightInfo->OriginalIndex == Index) break;
2929 TRACE("Found light: %p\n", lightInfo);
2931 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2932 if (lightInfo == NULL) {
2934 TRACE("Light enabled requested but light not defined, so defining one!\n");
2935 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2937 /* Search for it again! Should be fairly quick as near head of list */
2938 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2939 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2940 if(lightInfo->OriginalIndex == Index) break;
2943 if (lightInfo == NULL) {
2944 FIXME("Adding default lights has failed dismally\n");
2945 return WINED3DERR_INVALIDCALL;
2949 lightInfo->enabledChanged = TRUE;
2951 if(lightInfo->glIndex != -1) {
2952 if(!This->isRecordingState) {
2953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2956 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2957 lightInfo->glIndex = -1;
2959 TRACE("Light already disabled, nothing to do\n");
2961 lightInfo->enabled = FALSE;
2963 lightInfo->enabled = TRUE;
2964 if (lightInfo->glIndex != -1) {
2966 TRACE("Nothing to do as light was enabled\n");
2969 /* Find a free gl light */
2970 for(i = 0; i < This->maxConcurrentLights; i++) {
2971 if(This->stateBlock->activeLights[i] == NULL) {
2972 This->stateBlock->activeLights[i] = lightInfo;
2973 lightInfo->glIndex = i;
2977 if(lightInfo->glIndex == -1) {
2978 /* Our tests show that Windows returns D3D_OK in this situation, even with
2979 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2980 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2981 * as well for those lights.
2983 * TODO: Test how this affects rendering
2985 FIXME("Too many concurrently active lights\n");
2989 /* i == lightInfo->glIndex */
2990 if(!This->isRecordingState) {
2991 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2999 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3001 PLIGHTINFOEL *lightInfo = NULL;
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3005 TRACE("(%p) : for idx(%d)\n", This, Index);
3007 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3008 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3009 if(lightInfo->OriginalIndex == Index) break;
3013 if (lightInfo == NULL) {
3014 TRACE("Light enabled state requested but light not defined\n");
3015 return WINED3DERR_INVALIDCALL;
3017 /* true is 128 according to SetLightEnable */
3018 *pEnable = lightInfo->enabled ? 128 : 0;
3023 * Get / Set Clip Planes
3025 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3027 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3029 /* Validate Index */
3030 if (Index >= GL_LIMITS(clipplanes)) {
3031 TRACE("Application has requested clipplane this device doesn't support\n");
3032 return WINED3DERR_INVALIDCALL;
3035 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3037 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3038 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3039 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3040 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3041 TRACE("Application is setting old values over, nothing to do\n");
3045 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3046 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3047 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3048 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3050 /* Handle recording of state blocks */
3051 if (This->isRecordingState) {
3052 TRACE("Recording... not performing anything\n");
3056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3061 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 TRACE("(%p) : for idx %d\n", This, Index);
3065 /* Validate Index */
3066 if (Index >= GL_LIMITS(clipplanes)) {
3067 TRACE("Application has requested clipplane this device doesn't support\n");
3068 return WINED3DERR_INVALIDCALL;
3071 pPlane[0] = This->stateBlock->clipplane[Index][0];
3072 pPlane[1] = This->stateBlock->clipplane[Index][1];
3073 pPlane[2] = This->stateBlock->clipplane[Index][2];
3074 pPlane[3] = This->stateBlock->clipplane[Index][3];
3079 * Get / Set Clip Plane Status
3080 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3082 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 FIXME("(%p) : stub\n", This);
3085 if (NULL == pClipStatus) {
3086 return WINED3DERR_INVALIDCALL;
3088 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3089 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3093 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3095 FIXME("(%p) : stub\n", This);
3096 if (NULL == pClipStatus) {
3097 return WINED3DERR_INVALIDCALL;
3099 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3100 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3105 * Get / Set Material
3107 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3112 This->updateStateBlock->changed.material = TRUE;
3113 This->updateStateBlock->material = *pMaterial;
3115 /* Handle recording of state blocks */
3116 if (This->isRecordingState) {
3117 TRACE("Recording... not performing anything\n");
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3125 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 *pMaterial = This->updateStateBlock->material;
3128 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3129 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3130 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3131 pMaterial->Ambient.b, pMaterial->Ambient.a);
3132 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3133 pMaterial->Specular.b, pMaterial->Specular.a);
3134 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3135 pMaterial->Emissive.b, pMaterial->Emissive.a);
3136 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3144 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 IWineD3DIndexBuffer *oldIdxs;
3148 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3149 oldIdxs = This->updateStateBlock->pIndexData;
3151 This->updateStateBlock->changed.indices = TRUE;
3152 This->updateStateBlock->pIndexData = pIndexData;
3154 /* Handle recording of state blocks */
3155 if (This->isRecordingState) {
3156 TRACE("Recording... not performing anything\n");
3157 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3158 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3162 if(oldIdxs != pIndexData) {
3163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3164 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3165 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3170 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 *ppIndexData = This->stateBlock->pIndexData;
3175 /* up ref count on ppindexdata */
3177 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3178 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3180 TRACE("(%p) No index data set\n", This);
3182 TRACE("Returning %p\n", *ppIndexData);
3187 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3188 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3190 TRACE("(%p)->(%d)\n", This, BaseIndex);
3192 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3193 TRACE("Application is setting the old value over, nothing to do\n");
3197 This->updateStateBlock->baseVertexIndex = BaseIndex;
3199 if (This->isRecordingState) {
3200 TRACE("Recording... not performing anything\n");
3203 /* The base vertex index affects the stream sources */
3204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3210 TRACE("(%p) : base_index %p\n", This, base_index);
3212 *base_index = This->stateBlock->baseVertexIndex;
3214 TRACE("Returning %u\n", *base_index);
3220 * Get / Set Viewports
3222 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 TRACE("(%p)\n", This);
3226 This->updateStateBlock->changed.viewport = TRUE;
3227 This->updateStateBlock->viewport = *pViewport;
3229 /* Handle recording of state blocks */
3230 if (This->isRecordingState) {
3231 TRACE("Recording... not performing anything\n");
3235 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3236 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3238 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3243 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 TRACE("(%p)\n", This);
3246 *pViewport = This->stateBlock->viewport;
3251 * Get / Set Render States
3252 * TODO: Verify against dx9 definitions
3254 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 DWORD oldValue = This->stateBlock->renderState[State];
3259 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3261 This->updateStateBlock->changed.renderState[State] = TRUE;
3262 This->updateStateBlock->renderState[State] = Value;
3264 /* Handle recording of state blocks */
3265 if (This->isRecordingState) {
3266 TRACE("Recording... not performing anything\n");
3270 /* Compared here and not before the assignment to allow proper stateblock recording */
3271 if(Value == oldValue) {
3272 TRACE("Application is setting the old value over, nothing to do\n");
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3280 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3283 *pValue = This->stateBlock->renderState[State];
3288 * Get / Set Sampler States
3289 * TODO: Verify against dx9 definitions
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3296 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3297 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3299 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3300 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3303 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3304 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3305 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3308 * SetSampler is designed to allow for more than the standard up to 8 textures
3309 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3310 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3312 * http://developer.nvidia.com/object/General_FAQ.html#t6
3314 * There are two new settings for GForce
3316 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3317 * and the texture one:
3318 * GL_MAX_TEXTURE_COORDS_ARB.
3319 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3322 oldValue = This->stateBlock->samplerState[Sampler][Type];
3323 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3324 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3326 /* Handle recording of state blocks */
3327 if (This->isRecordingState) {
3328 TRACE("Recording... not performing anything\n");
3332 if(oldValue == Value) {
3333 TRACE("Application is setting the old value over, nothing to do\n");
3337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3342 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3345 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3346 This, Sampler, debug_d3dsamplerstate(Type), Type);
3348 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3349 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3352 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3353 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3354 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3356 *Value = This->stateBlock->samplerState[Sampler][Type];
3357 TRACE("(%p) : Returning %#x\n", This, *Value);
3362 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3365 This->updateStateBlock->changed.scissorRect = TRUE;
3366 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3367 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3370 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3372 if(This->isRecordingState) {
3373 TRACE("Recording... not performing anything\n");
3377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3382 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 *pRect = This->updateStateBlock->scissorRect;
3386 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3390 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3392 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3394 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3396 This->updateStateBlock->vertexDecl = pDecl;
3397 This->updateStateBlock->changed.vertexDecl = TRUE;
3399 if (This->isRecordingState) {
3400 TRACE("Recording... not performing anything\n");
3402 } else if(pDecl == oldDecl) {
3403 /* Checked after the assignment to allow proper stateblock recording */
3404 TRACE("Application is setting the old declaration over, nothing to do\n");
3408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3412 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3415 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3417 *ppDecl = This->stateBlock->vertexDecl;
3418 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3422 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3424 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3426 This->updateStateBlock->vertexShader = pShader;
3427 This->updateStateBlock->changed.vertexShader = TRUE;
3429 if (This->isRecordingState) {
3430 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3431 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3432 TRACE("Recording... not performing anything\n");
3434 } else if(oldShader == pShader) {
3435 /* Checked here to allow proper stateblock recording */
3436 TRACE("App is setting the old shader over, nothing to do\n");
3440 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3441 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3442 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3449 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3452 if (NULL == ppShader) {
3453 return WINED3DERR_INVALIDCALL;
3455 *ppShader = This->stateBlock->vertexShader;
3456 if( NULL != *ppShader)
3457 IWineD3DVertexShader_AddRef(*ppShader);
3459 TRACE("(%p) : returning %p\n", This, *ppShader);
3463 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3464 IWineD3DDevice *iface,
3466 CONST BOOL *srcData,
3469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3470 int i, cnt = min(count, MAX_CONST_B - start);
3472 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3473 iface, srcData, start, count);
3475 if (srcData == NULL || cnt < 0)
3476 return WINED3DERR_INVALIDCALL;
3478 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3479 for (i = 0; i < cnt; i++)
3480 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3482 for (i = start; i < cnt + start; ++i) {
3483 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3491 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3492 IWineD3DDevice *iface,
3497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3498 int cnt = min(count, MAX_CONST_B - start);
3500 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3501 iface, dstData, start, count);
3503 if (dstData == NULL || cnt < 0)
3504 return WINED3DERR_INVALIDCALL;
3506 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3510 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3511 IWineD3DDevice *iface,
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 int i, cnt = min(count, MAX_CONST_I - start);
3519 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3520 iface, srcData, start, count);
3522 if (srcData == NULL || cnt < 0)
3523 return WINED3DERR_INVALIDCALL;
3525 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3526 for (i = 0; i < cnt; i++)
3527 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3528 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3530 for (i = start; i < cnt + start; ++i) {
3531 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3539 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3540 IWineD3DDevice *iface,
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 int cnt = min(count, MAX_CONST_I - start);
3548 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3549 iface, dstData, start, count);
3551 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3552 return WINED3DERR_INVALIDCALL;
3554 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3558 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3559 IWineD3DDevice *iface,
3561 CONST float *srcData,
3564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3567 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3568 iface, srcData, start, count);
3570 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3571 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3572 return WINED3DERR_INVALIDCALL;
3574 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3576 for (i = 0; i < count; i++)
3577 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3578 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3581 for (i = start; i < count + start; ++i) {
3582 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3583 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3584 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3585 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3586 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3588 ptr->idx[ptr->count++] = i;
3589 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3598 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3599 IWineD3DDevice *iface,
3601 CONST float *srcData,
3604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3607 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3608 iface, srcData, start, count);
3610 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3611 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3612 return WINED3DERR_INVALIDCALL;
3614 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3616 for (i = 0; i < count; i++)
3617 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3618 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3621 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3622 * context. On a context switch the old context will be fully dirtified
3624 memset(This->activeContext->vshader_const_dirty + start, 1,
3625 sizeof(*This->activeContext->vshader_const_dirty) * count);
3626 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3633 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3634 IWineD3DDevice *iface,
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3642 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3643 iface, dstData, start, count);
3645 if (dstData == NULL || cnt < 0)
3646 return WINED3DERR_INVALIDCALL;
3648 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3652 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3654 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3655 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3659 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3660 int i = This->rev_tex_unit_map[unit];
3661 int j = This->texUnitMap[stage];
3663 This->texUnitMap[stage] = unit;
3664 if (i != -1 && i != stage) {
3665 This->texUnitMap[i] = -1;
3668 This->rev_tex_unit_map[unit] = stage;
3669 if (j != -1 && j != unit) {
3670 This->rev_tex_unit_map[j] = -1;
3674 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3677 for (i = 0; i < MAX_TEXTURES; ++i) {
3678 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3679 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3680 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3681 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3682 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3683 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3684 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3685 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3687 if (color_op == WINED3DTOP_DISABLE) {
3688 /* Not used, and disable higher stages */
3689 while (i < MAX_TEXTURES) {
3690 This->fixed_function_usage_map[i] = FALSE;
3696 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3697 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3698 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3699 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3700 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3701 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3702 This->fixed_function_usage_map[i] = TRUE;
3704 This->fixed_function_usage_map[i] = FALSE;
3707 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3708 This->fixed_function_usage_map[i+1] = TRUE;
3713 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3716 device_update_fixed_function_usage_map(This);
3718 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3719 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3720 if (!This->fixed_function_usage_map[i]) continue;
3722 if (This->texUnitMap[i] != i) {
3723 device_map_stage(This, i, i);
3724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3725 markTextureStagesDirty(This, i);
3731 /* Now work out the mapping */
3733 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3734 if (!This->fixed_function_usage_map[i]) continue;
3736 if (This->texUnitMap[i] != tex) {
3737 device_map_stage(This, i, tex);
3738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3739 markTextureStagesDirty(This, i);
3746 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3747 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3750 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3751 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3752 device_map_stage(This, i, i);
3753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3754 if (i < MAX_TEXTURES) {
3755 markTextureStagesDirty(This, i);
3761 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3762 int current_mapping = This->rev_tex_unit_map[unit];
3764 if (current_mapping == -1) {
3765 /* Not currently used */
3769 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3770 /* Used by a fragment sampler */
3772 if (!pshader_sampler_tokens) {
3773 /* No pixel shader, check fixed function */
3774 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3777 /* Pixel shader, check the shader's sampler map */
3778 return !pshader_sampler_tokens[current_mapping];
3781 /* Used by a vertex sampler */
3782 return !vshader_sampler_tokens[current_mapping];
3785 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3786 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3787 DWORD *pshader_sampler_tokens = NULL;
3788 int start = GL_LIMITS(combined_samplers) - 1;
3792 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3794 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3795 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3796 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3799 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3800 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3801 if (vshader_sampler_tokens[i]) {
3802 if (This->texUnitMap[vsampler_idx] != -1) {
3803 /* Already mapped somewhere */
3807 while (start >= 0) {
3808 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3809 device_map_stage(This, vsampler_idx, start);
3810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3822 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3823 BOOL vs = use_vs(This);
3824 BOOL ps = use_ps(This);
3827 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3828 * that would be really messy and require shader recompilation
3829 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3830 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3833 device_map_psamplers(This);
3835 device_map_fixed_function_samplers(This);
3839 device_map_vsamplers(This, ps);
3843 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3845 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3846 This->updateStateBlock->pixelShader = pShader;
3847 This->updateStateBlock->changed.pixelShader = TRUE;
3849 /* Handle recording of state blocks */
3850 if (This->isRecordingState) {
3851 TRACE("Recording... not performing anything\n");
3854 if (This->isRecordingState) {
3855 TRACE("Recording... not performing anything\n");
3856 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3857 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3861 if(pShader == oldShader) {
3862 TRACE("App is setting the old pixel shader over, nothing to do\n");
3866 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3867 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3869 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3875 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3878 if (NULL == ppShader) {
3879 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3880 return WINED3DERR_INVALIDCALL;
3883 *ppShader = This->stateBlock->pixelShader;
3884 if (NULL != *ppShader) {
3885 IWineD3DPixelShader_AddRef(*ppShader);
3887 TRACE("(%p) : returning %p\n", This, *ppShader);
3891 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3892 IWineD3DDevice *iface,
3894 CONST BOOL *srcData,
3897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3898 int i, cnt = min(count, MAX_CONST_B - start);
3900 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3901 iface, srcData, start, count);
3903 if (srcData == NULL || cnt < 0)
3904 return WINED3DERR_INVALIDCALL;
3906 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3907 for (i = 0; i < cnt; i++)
3908 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3910 for (i = start; i < cnt + start; ++i) {
3911 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3914 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3919 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3920 IWineD3DDevice *iface,
3925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3926 int cnt = min(count, MAX_CONST_B - start);
3928 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3929 iface, dstData, start, count);
3931 if (dstData == NULL || cnt < 0)
3932 return WINED3DERR_INVALIDCALL;
3934 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3938 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3939 IWineD3DDevice *iface,
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3945 int i, cnt = min(count, MAX_CONST_I - start);
3947 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3948 iface, srcData, start, count);
3950 if (srcData == NULL || cnt < 0)
3951 return WINED3DERR_INVALIDCALL;
3953 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3954 for (i = 0; i < cnt; i++)
3955 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3956 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3958 for (i = start; i < cnt + start; ++i) {
3959 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3967 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3968 IWineD3DDevice *iface,
3973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3974 int cnt = min(count, MAX_CONST_I - start);
3976 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3977 iface, dstData, start, count);
3979 if (dstData == NULL || cnt < 0)
3980 return WINED3DERR_INVALIDCALL;
3982 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3986 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3987 IWineD3DDevice *iface,
3989 CONST float *srcData,
3992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3995 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3996 iface, srcData, start, count);
3998 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3999 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4000 return WINED3DERR_INVALIDCALL;
4002 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4004 for (i = 0; i < count; i++)
4005 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4006 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4009 for (i = start; i < count + start; ++i) {
4010 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4011 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4012 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4013 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4014 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4016 ptr->idx[ptr->count++] = i;
4017 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4026 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4027 IWineD3DDevice *iface,
4029 CONST float *srcData,
4032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4035 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4036 iface, srcData, start, count);
4038 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4039 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4040 return WINED3DERR_INVALIDCALL;
4042 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4044 for (i = 0; i < count; i++)
4045 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4046 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4049 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4050 * context. On a context switch the old context will be fully dirtified
4052 memset(This->activeContext->pshader_const_dirty + start, 1,
4053 sizeof(*This->activeContext->pshader_const_dirty) * count);
4054 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4061 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4062 IWineD3DDevice *iface,
4067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4068 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4070 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4071 iface, dstData, start, count);
4073 if (dstData == NULL || cnt < 0)
4074 return WINED3DERR_INVALIDCALL;
4076 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4080 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4082 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4083 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4085 DWORD DestFVF = dest->fvf;
4087 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4091 if (lpStrideData->u.s.normal.lpData) {
4092 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4095 if (lpStrideData->u.s.position.lpData == NULL) {
4096 ERR("Source has no position mask\n");
4097 return WINED3DERR_INVALIDCALL;
4100 /* We might access VBOs from this code, so hold the lock */
4103 if (dest->resource.allocatedMemory == NULL) {
4104 /* This may happen if we do direct locking into a vbo. Unlikely,
4105 * but theoretically possible(ddraw processvertices test)
4107 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4108 if(!dest->resource.allocatedMemory) {
4110 ERR("Out of memory\n");
4111 return E_OUTOFMEMORY;
4115 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4116 checkGLcall("glBindBufferARB");
4117 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4119 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4121 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4122 checkGLcall("glUnmapBufferARB");
4126 /* Get a pointer into the destination vbo(create one if none exists) and
4127 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4129 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4130 dest->Flags |= VBFLAG_CREATEVBO;
4131 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4135 unsigned char extrabytes = 0;
4136 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4137 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4138 * this may write 4 extra bytes beyond the area that should be written
4140 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4141 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4142 if(!dest_conv_addr) {
4143 ERR("Out of memory\n");
4144 /* Continue without storing converted vertices */
4146 dest_conv = dest_conv_addr;
4150 * a) WINED3DRS_CLIPPING is enabled
4151 * b) WINED3DVOP_CLIP is passed
4153 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4154 static BOOL warned = FALSE;
4156 * The clipping code is not quite correct. Some things need
4157 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4158 * so disable clipping for now.
4159 * (The graphics in Half-Life are broken, and my processvertices
4160 * test crashes with IDirect3DDevice3)
4166 FIXME("Clipping is broken and disabled for now\n");
4168 } else doClip = FALSE;
4169 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4171 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4174 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4175 WINED3DTS_PROJECTION,
4177 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4178 WINED3DTS_WORLDMATRIX(0),
4181 TRACE("View mat:\n");
4182 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);
4183 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);
4184 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);
4185 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);
4187 TRACE("Proj mat:\n");
4188 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);
4189 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);
4190 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);
4191 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);
4193 TRACE("World mat:\n");
4194 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);
4195 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);
4196 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);
4197 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);
4199 /* Get the viewport */
4200 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4201 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4202 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4204 multiply_matrix(&mat,&view_mat,&world_mat);
4205 multiply_matrix(&mat,&proj_mat,&mat);
4207 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4209 for (i = 0; i < dwCount; i+= 1) {
4210 unsigned int tex_index;
4212 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4213 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4214 /* The position first */
4216 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4218 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4220 /* Multiplication with world, view and projection matrix */
4221 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);
4222 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);
4223 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);
4224 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);
4226 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4228 /* WARNING: The following things are taken from d3d7 and were not yet checked
4229 * against d3d8 or d3d9!
4232 /* Clipping conditions: From msdn
4234 * A vertex is clipped if it does not match the following requirements
4238 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4240 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4241 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4246 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4247 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4250 /* "Normal" viewport transformation (not clipped)
4251 * 1) The values are divided by rhw
4252 * 2) The y axis is negative, so multiply it with -1
4253 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4254 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4255 * 4) Multiply x with Width/2 and add Width/2
4256 * 5) The same for the height
4257 * 6) Add the viewpoint X and Y to the 2D coordinates and
4258 * The minimum Z value to z
4259 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4261 * Well, basically it's simply a linear transformation into viewport
4273 z *= vp.MaxZ - vp.MinZ;
4275 x += vp.Width / 2 + vp.X;
4276 y += vp.Height / 2 + vp.Y;
4281 /* That vertex got clipped
4282 * Contrary to OpenGL it is not dropped completely, it just
4283 * undergoes a different calculation.
4285 TRACE("Vertex got clipped\n");
4292 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4293 * outside of the main vertex buffer memory. That needs some more
4298 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4301 ( (float *) dest_ptr)[0] = x;
4302 ( (float *) dest_ptr)[1] = y;
4303 ( (float *) dest_ptr)[2] = z;
4304 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4306 dest_ptr += 3 * sizeof(float);
4308 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4309 dest_ptr += sizeof(float);
4314 ( (float *) dest_conv)[0] = x * w;
4315 ( (float *) dest_conv)[1] = y * w;
4316 ( (float *) dest_conv)[2] = z * w;
4317 ( (float *) dest_conv)[3] = w;
4319 dest_conv += 3 * sizeof(float);
4321 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4322 dest_conv += sizeof(float);
4326 if (DestFVF & WINED3DFVF_PSIZE) {
4327 dest_ptr += sizeof(DWORD);
4328 if(dest_conv) dest_conv += sizeof(DWORD);
4330 if (DestFVF & WINED3DFVF_NORMAL) {
4332 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4333 /* AFAIK this should go into the lighting information */
4334 FIXME("Didn't expect the destination to have a normal\n");
4335 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4337 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4341 if (DestFVF & WINED3DFVF_DIFFUSE) {
4343 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4345 static BOOL warned = FALSE;
4348 ERR("No diffuse color in source, but destination has one\n");
4352 *( (DWORD *) dest_ptr) = 0xffffffff;
4353 dest_ptr += sizeof(DWORD);
4356 *( (DWORD *) dest_conv) = 0xffffffff;
4357 dest_conv += sizeof(DWORD);
4361 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4363 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4364 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4365 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4366 dest_conv += sizeof(DWORD);
4371 if (DestFVF & WINED3DFVF_SPECULAR) {
4372 /* What's the color value in the feedback buffer? */
4374 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4376 static BOOL warned = FALSE;
4379 ERR("No specular color in source, but destination has one\n");
4383 *( (DWORD *) dest_ptr) = 0xFF000000;
4384 dest_ptr += sizeof(DWORD);
4387 *( (DWORD *) dest_conv) = 0xFF000000;
4388 dest_conv += sizeof(DWORD);
4392 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4394 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4395 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4396 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4397 dest_conv += sizeof(DWORD);
4402 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4404 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4405 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4407 ERR("No source texture, but destination requests one\n");
4408 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4409 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4412 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4414 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4421 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4422 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4423 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4424 dwCount * get_flexible_vertex_size(DestFVF),
4426 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4427 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4434 #undef copy_and_next
4436 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4438 WineDirect3DVertexStridedData strided;
4439 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4440 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4443 ERR("Output vertex declaration not implemented yet\n");
4446 /* Need any context to write to the vbo. */
4447 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4449 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4450 * control the streamIsUP flag, thus restore it afterwards.
4452 This->stateBlock->streamIsUP = FALSE;
4453 memset(&strided, 0, sizeof(strided));
4454 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4455 This->stateBlock->streamIsUP = streamWasUP;
4457 if(vbo || SrcStartIndex) {
4459 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4460 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4462 * Also get the start index in, but only loop over all elements if there's something to add at all.
4464 #define FIXSRC(type) \
4465 if(strided.u.s.type.VBO) { \
4466 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4467 strided.u.s.type.VBO = 0; \
4468 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4470 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4474 if(strided.u.s.type.lpData) { \
4475 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4478 FIXSRC(blendWeights);
4479 FIXSRC(blendMatrixIndices);
4484 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4485 FIXSRC(texCoords[i]);
4498 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4502 * Get / Set Texture Stage States
4503 * TODO: Verify against dx9 definitions
4505 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4507 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4509 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4511 if (Stage >= MAX_TEXTURES) {
4512 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4516 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4517 This->updateStateBlock->textureState[Stage][Type] = Value;
4519 if (This->isRecordingState) {
4520 TRACE("Recording... not performing anything\n");
4524 /* Checked after the assignments to allow proper stateblock recording */
4525 if(oldValue == Value) {
4526 TRACE("App is setting the old value over, nothing to do\n");
4530 if(Stage > This->stateBlock->lowest_disabled_stage &&
4531 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4532 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4533 * Changes in other states are important on disabled stages too
4538 if(Type == WINED3DTSS_COLOROP) {
4541 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4542 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4543 * they have to be disabled
4545 * The current stage is dirtified below.
4547 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4548 TRACE("Additionally dirtifying stage %d\n", i);
4549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4551 This->stateBlock->lowest_disabled_stage = Stage;
4552 TRACE("New lowest disabled: %d\n", Stage);
4553 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4554 /* Previously disabled stage enabled. Stages above it may need enabling
4555 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4556 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4558 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4561 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4562 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4565 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4568 This->stateBlock->lowest_disabled_stage = i;
4569 TRACE("New lowest disabled: %d\n", i);
4571 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4572 /* TODO: Built a stage -> texture unit mapping for register combiners */
4576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4581 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4584 *pValue = This->updateStateBlock->textureState[Stage][Type];
4591 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4593 IWineD3DBaseTexture *oldTexture;
4595 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4597 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4598 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4601 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4602 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4603 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4606 oldTexture = This->updateStateBlock->textures[Stage];
4608 if(pTexture != NULL) {
4609 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4611 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4612 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4613 return WINED3DERR_INVALIDCALL;
4615 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4618 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4619 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4621 This->updateStateBlock->changed.textures[Stage] = TRUE;
4622 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4623 This->updateStateBlock->textures[Stage] = pTexture;
4625 /* Handle recording of state blocks */
4626 if (This->isRecordingState) {
4627 TRACE("Recording... not performing anything\n");
4631 if(oldTexture == pTexture) {
4632 TRACE("App is setting the same texture again, nothing to do\n");
4636 /** NOTE: MSDN says that setTexture increases the reference count,
4637 * and that the application must set the texture back to null (or have a leaky application),
4638 * This means we should pass the refcount up to the parent
4639 *******************************/
4640 if (NULL != This->updateStateBlock->textures[Stage]) {
4641 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4642 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4644 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4645 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4646 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4647 * so the COLOROP and ALPHAOP have to be dirtified.
4649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4652 if(bindCount == 1) {
4653 new->baseTexture.sampler = Stage;
4655 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4659 if (NULL != oldTexture) {
4660 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4661 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4663 IWineD3DBaseTexture_Release(oldTexture);
4664 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4669 if(bindCount && old->baseTexture.sampler == Stage) {
4671 /* Have to do a search for the other sampler(s) where the texture is bound to
4672 * Shouldn't happen as long as apps bind a texture only to one stage
4674 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4675 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4676 if(This->updateStateBlock->textures[i] == oldTexture) {
4677 old->baseTexture.sampler = i;
4684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4689 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4692 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4694 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4695 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4698 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4699 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4700 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4703 *ppTexture=This->stateBlock->textures[Stage];
4705 IWineD3DBaseTexture_AddRef(*ppTexture);
4707 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4715 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4716 IWineD3DSurface **ppBackBuffer) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 IWineD3DSwapChain *swapChain;
4721 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4723 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4724 if (hr == WINED3D_OK) {
4725 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4726 IWineD3DSwapChain_Release(swapChain);
4728 *ppBackBuffer = NULL;
4733 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4735 WARN("(%p) : stub, calling idirect3d for now\n", This);
4736 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4739 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4741 IWineD3DSwapChain *swapChain;
4744 if(iSwapChain > 0) {
4745 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4746 if (hr == WINED3D_OK) {
4747 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4748 IWineD3DSwapChain_Release(swapChain);
4750 FIXME("(%p) Error getting display mode\n", This);
4753 /* Don't read the real display mode,
4754 but return the stored mode instead. X11 can't change the color
4755 depth, and some apps are pretty angry if they SetDisplayMode from
4756 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4758 Also don't relay to the swapchain because with ddraw it's possible
4759 that there isn't a swapchain at all */
4760 pMode->Width = This->ddraw_width;
4761 pMode->Height = This->ddraw_height;
4762 pMode->Format = This->ddraw_format;
4763 pMode->RefreshRate = 0;
4770 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4772 TRACE("(%p)->(%p)\n", This, hWnd);
4774 if(This->ddraw_fullscreen) {
4775 if(This->ddraw_window && This->ddraw_window != hWnd) {
4776 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4778 if(hWnd && This->ddraw_window != hWnd) {
4779 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4783 This->ddraw_window = hWnd;
4787 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4789 TRACE("(%p)->(%p)\n", This, hWnd);
4791 *hWnd = This->ddraw_window;
4796 * Stateblock related functions
4799 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4801 IWineD3DStateBlockImpl *object;
4802 HRESULT temp_result;
4805 TRACE("(%p)\n", This);
4807 if (This->isRecordingState) {
4808 return WINED3DERR_INVALIDCALL;
4811 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4812 if (NULL == object ) {
4813 FIXME("(%p)Error allocating memory for stateblock\n", This);
4814 return E_OUTOFMEMORY;
4816 TRACE("(%p) created object %p\n", This, object);
4817 object->wineD3DDevice= This;
4818 /** FIXME: object->parent = parent; **/
4819 object->parent = NULL;
4820 object->blockType = WINED3DSBT_RECORDED;
4822 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4824 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4825 list_init(&object->lightMap[i]);
4828 temp_result = allocate_shader_constants(object);
4829 if (WINED3D_OK != temp_result)
4832 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4833 This->updateStateBlock = object;
4834 This->isRecordingState = TRUE;
4836 TRACE("(%p) recording stateblock %p\n",This , object);
4840 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4843 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4845 if (!This->isRecordingState) {
4846 FIXME("(%p) not recording! returning error\n", This);
4847 *ppStateBlock = NULL;
4848 return WINED3DERR_INVALIDCALL;
4851 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4852 if(object->changed.renderState[i]) {
4853 object->contained_render_states[object->num_contained_render_states] = i;
4854 object->num_contained_render_states++;
4857 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4858 if(object->changed.transform[i]) {
4859 object->contained_transform_states[object->num_contained_transform_states] = i;
4860 object->num_contained_transform_states++;
4863 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4864 if(object->changed.vertexShaderConstantsF[i]) {
4865 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4866 object->num_contained_vs_consts_f++;
4869 for(i = 0; i < MAX_CONST_I; i++) {
4870 if(object->changed.vertexShaderConstantsI[i]) {
4871 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4872 object->num_contained_vs_consts_i++;
4875 for(i = 0; i < MAX_CONST_B; i++) {
4876 if(object->changed.vertexShaderConstantsB[i]) {
4877 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4878 object->num_contained_vs_consts_b++;
4881 for(i = 0; i < MAX_CONST_I; i++) {
4882 if(object->changed.pixelShaderConstantsI[i]) {
4883 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4884 object->num_contained_ps_consts_i++;
4887 for(i = 0; i < MAX_CONST_B; i++) {
4888 if(object->changed.pixelShaderConstantsB[i]) {
4889 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4890 object->num_contained_ps_consts_b++;
4893 for(i = 0; i < MAX_TEXTURES; i++) {
4894 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4895 if(object->changed.textureState[i][j]) {
4896 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4897 object->contained_tss_states[object->num_contained_tss_states].state = j;
4898 object->num_contained_tss_states++;
4902 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4903 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4904 if(object->changed.samplerState[i][j]) {
4905 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4906 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4907 object->num_contained_sampler_states++;
4912 *ppStateBlock = (IWineD3DStateBlock*) object;
4913 This->isRecordingState = FALSE;
4914 This->updateStateBlock = This->stateBlock;
4915 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4916 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4917 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4922 * Scene related functions
4924 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4925 /* At the moment we have no need for any functionality at the beginning
4927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4928 TRACE("(%p)\n", This);
4931 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4932 return WINED3DERR_INVALIDCALL;
4934 This->inScene = TRUE;
4938 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4940 TRACE("(%p)\n", This);
4942 if(!This->inScene) {
4943 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4944 return WINED3DERR_INVALIDCALL;
4947 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4948 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4950 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4954 This->inScene = FALSE;
4958 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4959 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4960 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4962 IWineD3DSwapChain *swapChain = NULL;
4964 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4966 TRACE("(%p) Presenting the frame\n", This);
4968 for(i = 0 ; i < swapchains ; i ++) {
4970 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4971 TRACE("presentinng chain %d, %p\n", i, swapChain);
4972 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4973 IWineD3DSwapChain_Release(swapChain);
4979 /* Not called from the VTable (internal subroutine) */
4980 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4981 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4982 float Z, DWORD Stencil) {
4983 GLbitfield glMask = 0;
4985 WINED3DRECT curRect;
4987 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4988 UINT drawable_width, drawable_height;
4989 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4991 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4992 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4993 * for the cleared parts, and the untouched parts.
4995 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4996 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4997 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4998 * checking all this if the dest surface is in the drawable anyway.
5000 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5002 if(vp->X != 0 || vp->Y != 0 ||
5003 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5004 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5007 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5008 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5009 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5010 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5011 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5014 if(Count > 0 && pRects && (
5015 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5016 pRects[0].x2 < target->currentDesc.Width ||
5017 pRects[0].y2 < target->currentDesc.Height)) {
5018 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5025 target->get_drawable_size(target, &drawable_width, &drawable_height);
5027 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5030 /* Only set the values up once, as they are not changing */
5031 if (Flags & WINED3DCLEAR_STENCIL) {
5032 glClearStencil(Stencil);
5033 checkGLcall("glClearStencil");
5034 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5035 glStencilMask(0xFFFFFFFF);
5038 if (Flags & WINED3DCLEAR_ZBUFFER) {
5039 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5040 glDepthMask(GL_TRUE);
5042 checkGLcall("glClearDepth");
5043 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5046 if (vp->X != 0 || vp->Y != 0 ||
5047 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5048 surface_load_ds_location(This->stencilBufferTarget, location);
5050 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5051 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5052 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5053 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5054 surface_load_ds_location(This->stencilBufferTarget, location);
5056 else if (Count > 0 && pRects && (
5057 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5058 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5059 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5060 surface_load_ds_location(This->stencilBufferTarget, location);
5064 if (Flags & WINED3DCLEAR_TARGET) {
5065 TRACE("Clearing screen with glClear to color %x\n", Color);
5066 glClearColor(D3DCOLOR_R(Color),
5070 checkGLcall("glClearColor");
5072 /* Clear ALL colors! */
5073 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5074 glMask = glMask | GL_COLOR_BUFFER_BIT;
5077 vp_rect.left = vp->X;
5078 vp_rect.top = vp->Y;
5079 vp_rect.right = vp->X + vp->Width;
5080 vp_rect.bottom = vp->Y + vp->Height;
5081 if (!(Count > 0 && pRects)) {
5082 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5083 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5085 if(This->render_offscreen) {
5086 glScissor(vp_rect.left, vp_rect.top,
5087 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5089 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5090 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5092 checkGLcall("glScissor");
5094 checkGLcall("glClear");
5096 /* Now process each rect in turn */
5097 for (i = 0; i < Count; i++) {
5098 /* Note gl uses lower left, width/height */
5099 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5100 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5101 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5103 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5104 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5105 curRect.x1, (target->currentDesc.Height - curRect.y2),
5106 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5108 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5109 * The rectangle is not cleared, no error is returned, but further rectanlges are
5110 * still cleared if they are valid
5112 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5113 TRACE("Rectangle with negative dimensions, ignoring\n");
5117 if(This->render_offscreen) {
5118 glScissor(curRect.x1, curRect.y1,
5119 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5121 glScissor(curRect.x1, drawable_height - curRect.y2,
5122 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5124 checkGLcall("glScissor");
5127 checkGLcall("glClear");
5131 /* Restore the old values (why..?) */
5132 if (Flags & WINED3DCLEAR_STENCIL) {
5133 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5135 if (Flags & WINED3DCLEAR_TARGET) {
5136 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5137 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5138 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5139 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5140 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5142 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5143 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5145 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5146 /* TODO: Move the fbo logic into ModifyLocation() */
5147 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5148 target->Flags |= SFLAG_INTEXTURE;
5151 if (Flags & WINED3DCLEAR_ZBUFFER) {
5152 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5153 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5154 surface_modify_ds_location(This->stencilBufferTarget, location);
5162 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5163 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5165 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5167 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5168 Count, pRects, Flags, Color, Z, Stencil);
5170 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5171 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5172 /* TODO: What about depth stencil buffers without stencil bits? */
5173 return WINED3DERR_INVALIDCALL;
5176 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5182 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5183 UINT PrimitiveCount) {
5185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5187 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5188 debug_d3dprimitivetype(PrimitiveType),
5189 StartVertex, PrimitiveCount);
5191 if(!This->stateBlock->vertexDecl) {
5192 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5193 return WINED3DERR_INVALIDCALL;
5196 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5197 if(This->stateBlock->streamIsUP) {
5198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5199 This->stateBlock->streamIsUP = FALSE;
5202 if(This->stateBlock->loadBaseVertexIndex != 0) {
5203 This->stateBlock->loadBaseVertexIndex = 0;
5204 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5206 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5207 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5208 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5212 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5213 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5214 WINED3DPRIMITIVETYPE PrimitiveType,
5215 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5219 IWineD3DIndexBuffer *pIB;
5220 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5223 pIB = This->stateBlock->pIndexData;
5225 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5226 * without an index buffer set. (The first time at least...)
5227 * D3D8 simply dies, but I doubt it can do much harm to return
5228 * D3DERR_INVALIDCALL there as well. */
5229 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5230 return WINED3DERR_INVALIDCALL;
5233 if(!This->stateBlock->vertexDecl) {
5234 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5235 return WINED3DERR_INVALIDCALL;
5238 if(This->stateBlock->streamIsUP) {
5239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5240 This->stateBlock->streamIsUP = FALSE;
5242 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5244 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5245 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5246 minIndex, NumVertices, startIndex, primCount);
5248 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5249 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5255 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5256 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5260 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5261 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5266 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5267 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5268 UINT VertexStreamZeroStride) {
5269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5270 IWineD3DVertexBuffer *vb;
5272 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5273 debug_d3dprimitivetype(PrimitiveType),
5274 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5276 if(!This->stateBlock->vertexDecl) {
5277 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5278 return WINED3DERR_INVALIDCALL;
5281 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5282 vb = This->stateBlock->streamSource[0];
5283 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5284 if(vb) IWineD3DVertexBuffer_Release(vb);
5285 This->stateBlock->streamOffset[0] = 0;
5286 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5287 This->stateBlock->streamIsUP = TRUE;
5288 This->stateBlock->loadBaseVertexIndex = 0;
5290 /* TODO: Only mark dirty if drawing from a different UP address */
5291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5293 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5294 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5296 /* MSDN specifies stream zero settings must be set to NULL */
5297 This->stateBlock->streamStride[0] = 0;
5298 This->stateBlock->streamSource[0] = NULL;
5300 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5301 * the new stream sources or use UP drawing again
5306 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5307 UINT MinVertexIndex, UINT NumVertices,
5308 UINT PrimitiveCount, CONST void* pIndexData,
5309 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5310 UINT VertexStreamZeroStride) {
5312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5313 IWineD3DVertexBuffer *vb;
5314 IWineD3DIndexBuffer *ib;
5316 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5317 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5318 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5319 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5321 if(!This->stateBlock->vertexDecl) {
5322 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5323 return WINED3DERR_INVALIDCALL;
5326 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5332 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5333 vb = This->stateBlock->streamSource[0];
5334 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5335 if(vb) IWineD3DVertexBuffer_Release(vb);
5336 This->stateBlock->streamIsUP = TRUE;
5337 This->stateBlock->streamOffset[0] = 0;
5338 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5340 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5341 This->stateBlock->baseVertexIndex = 0;
5342 This->stateBlock->loadBaseVertexIndex = 0;
5343 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5347 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5349 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5350 This->stateBlock->streamSource[0] = NULL;
5351 This->stateBlock->streamStride[0] = 0;
5352 ib = This->stateBlock->pIndexData;
5354 IWineD3DIndexBuffer_Release(ib);
5355 This->stateBlock->pIndexData = NULL;
5357 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5358 * SetStreamSource to specify a vertex buffer
5364 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5367 /* Mark the state dirty until we have nicer tracking
5368 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5373 This->stateBlock->baseVertexIndex = 0;
5374 This->up_strided = DrawPrimStrideData;
5375 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5376 This->up_strided = NULL;
5380 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5382 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5384 /* Mark the state dirty until we have nicer tracking
5385 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5390 This->stateBlock->streamIsUP = TRUE;
5391 This->stateBlock->baseVertexIndex = 0;
5392 This->up_strided = DrawPrimStrideData;
5393 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5394 This->up_strided = NULL;
5398 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5399 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5400 * not callable by the app directly no parameter validation checks are needed here.
5402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5403 WINED3DLOCKED_BOX src;
5404 WINED3DLOCKED_BOX dst;
5406 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5408 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5409 * dirtification to improve loading performance.
5411 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5412 if(FAILED(hr)) return hr;
5413 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5415 IWineD3DVolume_UnlockBox(pSourceVolume);
5419 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5421 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5423 IWineD3DVolume_UnlockBox(pSourceVolume);
5425 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5430 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5431 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5433 HRESULT hr = WINED3D_OK;
5434 WINED3DRESOURCETYPE sourceType;
5435 WINED3DRESOURCETYPE destinationType;
5438 /* TODO: think about moving the code into IWineD3DBaseTexture */
5440 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5442 /* verify that the source and destination textures aren't NULL */
5443 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5444 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5445 This, pSourceTexture, pDestinationTexture);
5446 hr = WINED3DERR_INVALIDCALL;
5449 if (pSourceTexture == pDestinationTexture) {
5450 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5451 This, pSourceTexture, pDestinationTexture);
5452 hr = WINED3DERR_INVALIDCALL;
5454 /* Verify that the source and destination textures are the same type */
5455 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5456 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5458 if (sourceType != destinationType) {
5459 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5461 hr = WINED3DERR_INVALIDCALL;
5464 /* check that both textures have the identical numbers of levels */
5465 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5466 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5467 hr = WINED3DERR_INVALIDCALL;
5470 if (WINED3D_OK == hr) {
5472 /* Make sure that the destination texture is loaded */
5473 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5475 /* Update every surface level of the texture */
5476 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5478 switch (sourceType) {
5479 case WINED3DRTYPE_TEXTURE:
5481 IWineD3DSurface *srcSurface;
5482 IWineD3DSurface *destSurface;
5484 for (i = 0 ; i < levels ; ++i) {
5485 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5486 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5487 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5488 IWineD3DSurface_Release(srcSurface);
5489 IWineD3DSurface_Release(destSurface);
5490 if (WINED3D_OK != hr) {
5491 WARN("(%p) : Call to update surface failed\n", This);
5497 case WINED3DRTYPE_CUBETEXTURE:
5499 IWineD3DSurface *srcSurface;
5500 IWineD3DSurface *destSurface;
5501 WINED3DCUBEMAP_FACES faceType;
5503 for (i = 0 ; i < levels ; ++i) {
5504 /* Update each cube face */
5505 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5506 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5507 if (WINED3D_OK != hr) {
5508 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5510 TRACE("Got srcSurface %p\n", srcSurface);
5512 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5513 if (WINED3D_OK != hr) {
5514 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5516 TRACE("Got desrSurface %p\n", destSurface);
5518 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5519 IWineD3DSurface_Release(srcSurface);
5520 IWineD3DSurface_Release(destSurface);
5521 if (WINED3D_OK != hr) {
5522 WARN("(%p) : Call to update surface failed\n", This);
5530 case WINED3DRTYPE_VOLUMETEXTURE:
5532 IWineD3DVolume *srcVolume = NULL;
5533 IWineD3DVolume *destVolume = NULL;
5535 for (i = 0 ; i < levels ; ++i) {
5536 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5537 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5538 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5539 IWineD3DVolume_Release(srcVolume);
5540 IWineD3DVolume_Release(destVolume);
5541 if (WINED3D_OK != hr) {
5542 WARN("(%p) : Call to update volume failed\n", This);
5550 FIXME("(%p) : Unsupported source and destination type\n", This);
5551 hr = WINED3DERR_INVALIDCALL;
5558 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5559 IWineD3DSwapChain *swapChain;
5561 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5562 if(hr == WINED3D_OK) {
5563 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5564 IWineD3DSwapChain_Release(swapChain);
5569 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5571 /* return a sensible default */
5573 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5574 FIXME("(%p) : stub\n", This);
5578 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5582 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5583 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5584 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5585 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5590 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5594 PALETTEENTRY **palettes;
5596 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5598 if (PaletteNumber >= MAX_PALETTES) {
5599 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5600 return WINED3DERR_INVALIDCALL;
5603 if (PaletteNumber >= This->NumberOfPalettes) {
5604 NewSize = This->NumberOfPalettes;
5607 } while(PaletteNumber >= NewSize);
5608 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5610 ERR("Out of memory!\n");
5611 return E_OUTOFMEMORY;
5613 This->palettes = palettes;
5614 This->NumberOfPalettes = NewSize;
5617 if (!This->palettes[PaletteNumber]) {
5618 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5619 if (!This->palettes[PaletteNumber]) {
5620 ERR("Out of memory!\n");
5621 return E_OUTOFMEMORY;
5625 for (j = 0; j < 256; ++j) {
5626 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5627 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5628 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5629 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5631 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5632 TRACE("(%p) : returning\n", This);
5636 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5639 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5640 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5641 /* What happens in such situation isn't documented; Native seems to silently abort
5642 on such conditions. Return Invalid Call. */
5643 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5644 return WINED3DERR_INVALIDCALL;
5646 for (j = 0; j < 256; ++j) {
5647 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5648 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5649 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5650 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5652 TRACE("(%p) : returning\n", This);
5656 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5658 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5659 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5660 (tested with reference rasterizer). Return Invalid Call. */
5661 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5662 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5663 return WINED3DERR_INVALIDCALL;
5665 /*TODO: stateblocks */
5666 if (This->currentPalette != PaletteNumber) {
5667 This->currentPalette = PaletteNumber;
5668 dirtify_p8_texture_samplers(This);
5670 TRACE("(%p) : returning\n", This);
5674 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5676 if (PaletteNumber == NULL) {
5677 WARN("(%p) : returning Invalid Call\n", This);
5678 return WINED3DERR_INVALIDCALL;
5680 /*TODO: stateblocks */
5681 *PaletteNumber = This->currentPalette;
5682 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5686 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5688 static BOOL showFixmes = TRUE;
5690 FIXME("(%p) : stub\n", This);
5694 This->softwareVertexProcessing = bSoftware;
5699 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5701 static BOOL showFixmes = TRUE;
5703 FIXME("(%p) : stub\n", This);
5706 return This->softwareVertexProcessing;
5710 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 IWineD3DSwapChain *swapChain;
5715 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5717 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5718 if(hr == WINED3D_OK){
5719 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5720 IWineD3DSwapChain_Release(swapChain);
5722 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5728 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5730 static BOOL showfixmes = TRUE;
5731 if(nSegments != 0.0f) {
5733 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5740 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5742 static BOOL showfixmes = TRUE;
5744 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5750 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5752 /** TODO: remove casts to IWineD3DSurfaceImpl
5753 * NOTE: move code to surface to accomplish this
5754 ****************************************/
5755 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5756 int srcWidth, srcHeight;
5757 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5758 WINED3DFORMAT destFormat, srcFormat;
5760 int srcLeft, destLeft, destTop;
5761 WINED3DPOOL srcPool, destPool;
5763 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5764 glDescriptor *glDescription = NULL;
5768 CONVERT_TYPES convert = NO_CONVERSION;
5770 WINED3DSURFACE_DESC winedesc;
5772 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5773 memset(&winedesc, 0, sizeof(winedesc));
5774 winedesc.Width = &srcSurfaceWidth;
5775 winedesc.Height = &srcSurfaceHeight;
5776 winedesc.Pool = &srcPool;
5777 winedesc.Format = &srcFormat;
5779 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5781 winedesc.Width = &destSurfaceWidth;
5782 winedesc.Height = &destSurfaceHeight;
5783 winedesc.Pool = &destPool;
5784 winedesc.Format = &destFormat;
5785 winedesc.Size = &destSize;
5787 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5789 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5790 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5791 return WINED3DERR_INVALIDCALL;
5794 /* This call loads the opengl surface directly, instead of copying the surface to the
5795 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5796 * copy in sysmem and use regular surface loading.
5798 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5799 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5800 if(convert != NO_CONVERSION) {
5801 return IWineD3DSurface_BltFast(pDestinationSurface,
5802 pDestPoint ? pDestPoint->x : 0,
5803 pDestPoint ? pDestPoint->y : 0,
5804 pSourceSurface, (RECT *) pSourceRect, 0);
5807 if (destFormat == WINED3DFMT_UNKNOWN) {
5808 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5809 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5811 /* Get the update surface description */
5812 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5815 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5819 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5820 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5821 checkGLcall("glActiveTextureARB");
5824 /* Make sure the surface is loaded and up to date */
5825 IWineD3DSurface_PreLoad(pDestinationSurface);
5827 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5829 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5830 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5831 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5832 srcLeft = pSourceRect ? pSourceRect->left : 0;
5833 destLeft = pDestPoint ? pDestPoint->x : 0;
5834 destTop = pDestPoint ? pDestPoint->y : 0;
5837 /* This function doesn't support compressed textures
5838 the pitch is just bytesPerPixel * width */
5839 if(srcWidth != srcSurfaceWidth || srcLeft ){
5840 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5841 offset += srcLeft * pSrcSurface->bytesPerPixel;
5842 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5844 /* TODO DXT formats */
5846 if(pSourceRect != NULL && pSourceRect->top != 0){
5847 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5849 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5851 ,glDescription->level
5856 ,glDescription->glFormat
5857 ,glDescription->glType
5858 ,IWineD3DSurface_GetData(pSourceSurface)
5862 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5864 /* need to lock the surface to get the data */
5865 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5868 /* TODO: Cube and volume support */
5870 /* not a whole row so we have to do it a line at a time */
5873 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5874 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5876 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5878 glTexSubImage2D(glDescription->target
5879 ,glDescription->level
5884 ,glDescription->glFormat
5885 ,glDescription->glType
5886 ,data /* could be quicker using */
5891 } else { /* Full width, so just write out the whole texture */
5893 if (WINED3DFMT_DXT1 == destFormat ||
5894 WINED3DFMT_DXT2 == destFormat ||
5895 WINED3DFMT_DXT3 == destFormat ||
5896 WINED3DFMT_DXT4 == destFormat ||
5897 WINED3DFMT_DXT5 == destFormat) {
5898 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5899 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5900 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5901 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5902 } if (destFormat != srcFormat) {
5903 FIXME("Updating mixed format compressed texture is not curretly support\n");
5905 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5906 glDescription->level,
5907 glDescription->glFormatInternal,
5912 IWineD3DSurface_GetData(pSourceSurface));
5915 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5920 glTexSubImage2D(glDescription->target
5921 ,glDescription->level
5926 ,glDescription->glFormat
5927 ,glDescription->glType
5928 ,IWineD3DSurface_GetData(pSourceSurface)
5932 checkGLcall("glTexSubImage2D");
5936 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5937 sampler = This->rev_tex_unit_map[0];
5938 if (sampler != -1) {
5939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5945 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5947 struct WineD3DRectPatch *patch;
5951 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5953 if(!(Handle || pRectPatchInfo)) {
5954 /* TODO: Write a test for the return value, thus the FIXME */
5955 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5956 return WINED3DERR_INVALIDCALL;
5960 i = PATCHMAP_HASHFUNC(Handle);
5962 LIST_FOR_EACH(e, &This->patches[i]) {
5963 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5964 if(patch->Handle == Handle) {
5971 TRACE("Patch does not exist. Creating a new one\n");
5972 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5973 patch->Handle = Handle;
5974 list_add_head(&This->patches[i], &patch->entry);
5976 TRACE("Found existing patch %p\n", patch);
5979 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5980 * attributes we have to tesselate, read back, and draw. This needs a patch
5981 * management structure instance. Create one.
5983 * A possible improvement is to check if a vertex shader is used, and if not directly
5986 FIXME("Drawing an uncached patch. This is slow\n");
5987 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5990 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5991 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5992 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5994 TRACE("Tesselation density or patch info changed, retesselating\n");
5996 if(pRectPatchInfo) {
5997 patch->RectPatchInfo = *pRectPatchInfo;
5999 patch->numSegs[0] = pNumSegs[0];
6000 patch->numSegs[1] = pNumSegs[1];
6001 patch->numSegs[2] = pNumSegs[2];
6002 patch->numSegs[3] = pNumSegs[3];
6004 hr = tesselate_rectpatch(This, patch);
6006 WARN("Patch tesselation failed\n");
6008 /* Do not release the handle to store the params of the patch */
6010 HeapFree(GetProcessHeap(), 0, patch);
6016 This->currentPatch = patch;
6017 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6018 This->currentPatch = NULL;
6020 /* Destroy uncached patches */
6022 HeapFree(GetProcessHeap(), 0, patch->mem);
6023 HeapFree(GetProcessHeap(), 0, patch);
6028 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6030 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6031 FIXME("(%p) : Stub\n", This);
6035 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6038 struct WineD3DRectPatch *patch;
6040 TRACE("(%p) Handle(%d)\n", This, Handle);
6042 i = PATCHMAP_HASHFUNC(Handle);
6043 LIST_FOR_EACH(e, &This->patches[i]) {
6044 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6045 if(patch->Handle == Handle) {
6046 TRACE("Deleting patch %p\n", patch);
6047 list_remove(&patch->entry);
6048 HeapFree(GetProcessHeap(), 0, patch->mem);
6049 HeapFree(GetProcessHeap(), 0, patch);
6054 /* TODO: Write a test for the return value */
6055 FIXME("Attempt to destroy nonexistent patch\n");
6056 return WINED3DERR_INVALIDCALL;
6059 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6061 IWineD3DSwapChain *swapchain;
6063 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6064 if (SUCCEEDED(hr)) {
6065 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6072 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6076 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6077 checkGLcall("glGenFramebuffersEXT()");
6079 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6080 checkGLcall("glBindFramebuffer()");
6083 /* TODO: Handle stencil attachments */
6084 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6085 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6087 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6088 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6089 checkGLcall("glFramebufferRenderbufferEXT()");
6091 IWineD3DBaseTextureImpl *texture_impl;
6092 GLenum texttarget, target;
6093 GLint old_binding = 0;
6095 texttarget = depth_stencil_impl->glDescription.target;
6096 if(texttarget == GL_TEXTURE_2D) {
6097 target = GL_TEXTURE_2D;
6098 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6099 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6100 target = GL_TEXTURE_RECTANGLE_ARB;
6101 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6103 target = GL_TEXTURE_CUBE_MAP_ARB;
6104 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6107 IWineD3DSurface_PreLoad(depth_stencil);
6109 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6110 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6111 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6112 glBindTexture(target, old_binding);
6114 /* Update base texture states array */
6115 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6116 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6117 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6118 if (texture_impl->baseTexture.bindCount) {
6119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6122 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6125 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6126 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6127 checkGLcall("glFramebufferTexture2DEXT()");
6131 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6132 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6133 IWineD3DBaseTextureImpl *texture_impl;
6134 GLenum texttarget, target;
6137 texttarget = surface_impl->glDescription.target;
6138 if(texttarget == GL_TEXTURE_2D) {
6139 target = GL_TEXTURE_2D;
6140 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6141 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6142 target = GL_TEXTURE_RECTANGLE_ARB;
6143 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6145 target = GL_TEXTURE_CUBE_MAP_ARB;
6146 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6149 IWineD3DSurface_PreLoad(surface);
6151 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6152 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6153 glBindTexture(target, old_binding);
6155 /* Update base texture states array */
6156 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6157 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6158 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6159 if (texture_impl->baseTexture.bindCount) {
6160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6163 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6166 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6167 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6169 checkGLcall("attach_surface_fbo");
6172 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6174 IWineD3DSwapChain *swapchain;
6176 swapchain = get_swapchain(surface);
6180 TRACE("Surface %p is onscreen\n", surface);
6182 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6184 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6185 buffer = surface_get_gl_buffer(surface, swapchain);
6186 glDrawBuffer(buffer);
6187 checkGLcall("glDrawBuffer()");
6189 TRACE("Surface %p is offscreen\n", surface);
6191 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6193 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6194 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6195 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6196 checkGLcall("glFramebufferRenderbufferEXT");
6200 glEnable(GL_SCISSOR_TEST);
6202 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6204 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6205 rect->x2 - rect->x1, rect->y2 - rect->y1);
6207 checkGLcall("glScissor");
6208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6210 glDisable(GL_SCISSOR_TEST);
6212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6214 glDisable(GL_BLEND);
6215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6217 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6220 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6221 glClear(GL_COLOR_BUFFER_BIT);
6222 checkGLcall("glClear");
6224 if (This->render_offscreen) {
6225 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6227 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6228 checkGLcall("glBindFramebuffer()");
6231 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6232 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6233 glDrawBuffer(GL_BACK);
6234 checkGLcall("glDrawBuffer()");
6240 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6241 unsigned int r, g, b, a;
6244 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6245 destfmt == WINED3DFMT_R8G8B8)
6248 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6250 a = (color & 0xff000000) >> 24;
6251 r = (color & 0x00ff0000) >> 16;
6252 g = (color & 0x0000ff00) >> 8;
6253 b = (color & 0x000000ff) >> 0;
6257 case WINED3DFMT_R5G6B5:
6258 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6265 TRACE("Returning %08x\n", ret);
6268 case WINED3DFMT_X1R5G5B5:
6269 case WINED3DFMT_A1R5G5B5:
6278 TRACE("Returning %08x\n", ret);
6282 TRACE("Returning %08x\n", a);
6285 case WINED3DFMT_X4R4G4B4:
6286 case WINED3DFMT_A4R4G4B4:
6295 TRACE("Returning %08x\n", ret);
6298 case WINED3DFMT_R3G3B2:
6305 TRACE("Returning %08x\n", ret);
6308 case WINED3DFMT_X8B8G8R8:
6309 case WINED3DFMT_A8B8G8R8:
6314 TRACE("Returning %08x\n", ret);
6317 case WINED3DFMT_A2R10G10B10:
6319 r = (r * 1024) / 256;
6320 g = (g * 1024) / 256;
6321 b = (b * 1024) / 256;
6326 TRACE("Returning %08x\n", ret);
6329 case WINED3DFMT_A2B10G10R10:
6331 r = (r * 1024) / 256;
6332 g = (g * 1024) / 256;
6333 b = (b * 1024) / 256;
6338 TRACE("Returning %08x\n", ret);
6342 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6347 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6349 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6351 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6353 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6354 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6355 return WINED3DERR_INVALIDCALL;
6358 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6359 color_fill_fbo(iface, pSurface, pRect, color);
6362 /* Just forward this to the DirectDraw blitting engine */
6363 memset(&BltFx, 0, sizeof(BltFx));
6364 BltFx.dwSize = sizeof(BltFx);
6365 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6366 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6370 /* rendertarget and depth stencil functions */
6371 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6374 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6375 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6376 return WINED3DERR_INVALIDCALL;
6379 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6380 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6381 /* Note inc ref on returned surface */
6382 if(*ppRenderTarget != NULL)
6383 IWineD3DSurface_AddRef(*ppRenderTarget);
6387 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6389 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6390 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6391 IWineD3DSwapChainImpl *Swapchain;
6394 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6396 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6397 if(hr != WINED3D_OK) {
6398 ERR("Can't get the swapchain\n");
6402 /* Make sure to release the swapchain */
6403 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6405 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6406 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6407 return WINED3DERR_INVALIDCALL;
6409 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6410 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6411 return WINED3DERR_INVALIDCALL;
6414 if(Swapchain->frontBuffer != Front) {
6415 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6417 if(Swapchain->frontBuffer)
6418 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6419 Swapchain->frontBuffer = Front;
6421 if(Swapchain->frontBuffer) {
6422 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6426 if(Back && !Swapchain->backBuffer) {
6427 /* We need memory for the back buffer array - only one back buffer this way */
6428 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6429 if(!Swapchain->backBuffer) {
6430 ERR("Out of memory\n");
6431 return E_OUTOFMEMORY;
6435 if(Swapchain->backBuffer[0] != Back) {
6436 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6438 /* What to do about the context here in the case of multithreading? Not sure.
6439 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6442 if(!Swapchain->backBuffer[0]) {
6443 /* GL was told to draw to the front buffer at creation,
6446 glDrawBuffer(GL_BACK);
6447 checkGLcall("glDrawBuffer(GL_BACK)");
6448 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6449 Swapchain->presentParms.BackBufferCount = 1;
6451 /* That makes problems - disable for now */
6452 /* glDrawBuffer(GL_FRONT); */
6453 checkGLcall("glDrawBuffer(GL_FRONT)");
6454 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6455 Swapchain->presentParms.BackBufferCount = 0;
6459 if(Swapchain->backBuffer[0])
6460 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6461 Swapchain->backBuffer[0] = Back;
6463 if(Swapchain->backBuffer[0]) {
6464 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6466 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6467 Swapchain->backBuffer = NULL;
6475 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6477 *ppZStencilSurface = This->stencilBufferTarget;
6478 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6480 if(*ppZStencilSurface != NULL) {
6481 /* Note inc ref on returned surface */
6482 IWineD3DSurface_AddRef(*ppZStencilSurface);
6485 return WINED3DERR_NOTFOUND;
6489 /* TODO: Handle stencil attachments */
6490 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6493 TRACE("Set depth stencil to %p\n", depth_stencil);
6495 if (depth_stencil) {
6496 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6498 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6499 checkGLcall("glFramebufferTexture2DEXT()");
6503 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6506 TRACE("Set render target %u to %p\n", idx, render_target);
6508 if (render_target) {
6509 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6510 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6512 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6513 checkGLcall("glFramebufferTexture2DEXT()");
6515 This->draw_buffers[idx] = GL_NONE;
6519 static void check_fbo_status(IWineD3DDevice *iface) {
6520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6523 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6524 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6525 TRACE("FBO complete\n");
6527 IWineD3DSurfaceImpl *attachment;
6529 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6531 /* Dump the FBO attachments */
6532 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6533 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6535 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6536 attachment->pow2Width, attachment->pow2Height);
6539 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6541 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6542 attachment->pow2Width, attachment->pow2Height);
6547 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6549 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6550 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6552 if (!ds_impl) return FALSE;
6554 if (ds_impl->current_renderbuffer) {
6555 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6556 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6559 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6560 rt_impl->pow2Height != ds_impl->pow2Height);
6563 void apply_fbo_state(IWineD3DDevice *iface) {
6564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6567 if (This->render_offscreen) {
6568 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6570 /* Apply render targets */
6571 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6572 IWineD3DSurface *render_target = This->render_targets[i];
6573 if (This->fbo_color_attachments[i] != render_target) {
6574 set_render_target_fbo(iface, i, render_target);
6575 This->fbo_color_attachments[i] = render_target;
6579 /* Apply depth targets */
6580 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6581 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6582 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6584 if (This->stencilBufferTarget) {
6585 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6587 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6588 This->fbo_depth_attachment = This->stencilBufferTarget;
6591 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6594 check_fbo_status(iface);
6597 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6598 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6600 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6601 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6603 POINT offset = {0, 0};
6605 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6606 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6607 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6608 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6611 case WINED3DTEXF_LINEAR:
6612 gl_filter = GL_LINEAR;
6616 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6617 case WINED3DTEXF_NONE:
6618 case WINED3DTEXF_POINT:
6619 gl_filter = GL_NEAREST;
6623 /* Attach src surface to src fbo */
6624 src_swapchain = get_swapchain(src_surface);
6625 if (src_swapchain) {
6626 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6628 TRACE("Source surface %p is onscreen\n", src_surface);
6629 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6630 /* Make sure the drawable is up to date. In the offscreen case
6631 * attach_surface_fbo() implicitly takes care of this. */
6632 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6634 if(buffer == GL_FRONT) {
6637 ClientToScreen(This->ddraw_window, &offset);
6638 GetClientRect(This->ddraw_window, &windowsize);
6639 h = windowsize.bottom - windowsize.top;
6640 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6641 src_rect->y1 = offset.y + h - src_rect->y1;
6642 src_rect->y2 = offset.y + h - src_rect->y2;
6644 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6645 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6649 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6650 glReadBuffer(buffer);
6651 checkGLcall("glReadBuffer()");
6653 TRACE("Source surface %p is offscreen\n", src_surface);
6655 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6656 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6657 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6658 checkGLcall("glReadBuffer()");
6659 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6660 checkGLcall("glFramebufferRenderbufferEXT");
6664 /* Attach dst surface to dst fbo */
6665 dst_swapchain = get_swapchain(dst_surface);
6666 if (dst_swapchain) {
6667 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6669 TRACE("Destination surface %p is onscreen\n", dst_surface);
6670 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6671 /* Make sure the drawable is up to date. In the offscreen case
6672 * attach_surface_fbo() implicitly takes care of this. */
6673 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6675 if(buffer == GL_FRONT) {
6678 ClientToScreen(This->ddraw_window, &offset);
6679 GetClientRect(This->ddraw_window, &windowsize);
6680 h = windowsize.bottom - windowsize.top;
6681 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6682 dst_rect->y1 = offset.y + h - dst_rect->y1;
6683 dst_rect->y2 = offset.y + h - dst_rect->y2;
6685 /* Screen coords = window coords, surface height = window height */
6686 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6687 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6691 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6692 glDrawBuffer(buffer);
6693 checkGLcall("glDrawBuffer()");
6695 TRACE("Destination surface %p is offscreen\n", dst_surface);
6697 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6698 if(!src_swapchain) {
6699 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6703 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6704 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6705 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6706 checkGLcall("glDrawBuffer()");
6707 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6708 checkGLcall("glFramebufferRenderbufferEXT");
6710 glDisable(GL_SCISSOR_TEST);
6711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6714 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6715 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6716 checkGLcall("glBlitFramebuffer()");
6718 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6719 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6720 checkGLcall("glBlitFramebuffer()");
6723 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6725 if (This->render_offscreen) {
6726 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6728 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6729 checkGLcall("glBindFramebuffer()");
6732 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6733 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6734 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6735 glDrawBuffer(GL_BACK);
6736 checkGLcall("glDrawBuffer()");
6741 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6743 WINED3DVIEWPORT viewport;
6745 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6747 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6748 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6749 This, RenderTargetIndex, GL_LIMITS(buffers));
6750 return WINED3DERR_INVALIDCALL;
6753 /* MSDN says that null disables the render target
6754 but a device must always be associated with a render target
6755 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6757 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6758 FIXME("Trying to set render target 0 to NULL\n");
6759 return WINED3DERR_INVALIDCALL;
6761 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6762 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);
6763 return WINED3DERR_INVALIDCALL;
6766 /* If we are trying to set what we already have, don't bother */
6767 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6768 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6771 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6772 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6773 This->render_targets[RenderTargetIndex] = pRenderTarget;
6775 /* Render target 0 is special */
6776 if(RenderTargetIndex == 0) {
6777 /* Finally, reset the viewport as the MSDN states. */
6778 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6779 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6782 viewport.MaxZ = 1.0f;
6783 viewport.MinZ = 0.0f;
6784 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6785 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6786 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6788 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6793 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6795 HRESULT hr = WINED3D_OK;
6796 IWineD3DSurface *tmp;
6798 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6800 if (pNewZStencil == This->stencilBufferTarget) {
6801 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6803 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6804 * depending on the renter target implementation being used.
6805 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6806 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6807 * stencil buffer and incur an extra memory overhead
6808 ******************************************************/
6810 if (This->stencilBufferTarget) {
6811 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6812 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6813 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6816 tmp = This->stencilBufferTarget;
6817 This->stencilBufferTarget = pNewZStencil;
6818 /* should we be calling the parent or the wined3d surface? */
6819 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6820 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6823 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6824 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6834 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6835 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6837 /* TODO: the use of Impl is deprecated. */
6838 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6839 WINED3DLOCKED_RECT lockedRect;
6841 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6843 /* some basic validation checks */
6844 if(This->cursorTexture) {
6845 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6847 glDeleteTextures(1, &This->cursorTexture);
6849 This->cursorTexture = 0;
6852 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6853 This->haveHardwareCursor = TRUE;
6855 This->haveHardwareCursor = FALSE;
6858 WINED3DLOCKED_RECT rect;
6860 /* MSDN: Cursor must be A8R8G8B8 */
6861 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6862 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6863 return WINED3DERR_INVALIDCALL;
6866 /* MSDN: Cursor must be smaller than the display mode */
6867 if(pSur->currentDesc.Width > This->ddraw_width ||
6868 pSur->currentDesc.Height > This->ddraw_height) {
6869 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);
6870 return WINED3DERR_INVALIDCALL;
6873 if (!This->haveHardwareCursor) {
6874 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6876 /* Do not store the surface's pointer because the application may
6877 * release it after setting the cursor image. Windows doesn't
6878 * addref the set surface, so we can't do this either without
6879 * creating circular refcount dependencies. Copy out the gl texture
6882 This->cursorWidth = pSur->currentDesc.Width;
6883 This->cursorHeight = pSur->currentDesc.Height;
6884 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6886 const GlPixelFormatDesc *glDesc;
6887 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6888 char *mem, *bits = (char *)rect.pBits;
6889 GLint intfmt = glDesc->glInternal;
6890 GLint format = glDesc->glFormat;
6891 GLint type = glDesc->glType;
6892 INT height = This->cursorHeight;
6893 INT width = This->cursorWidth;
6894 INT bpp = tableEntry->bpp;
6897 /* Reformat the texture memory (pitch and width can be
6899 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6900 for(i = 0; i < height; i++)
6901 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6902 IWineD3DSurface_UnlockRect(pCursorBitmap);
6905 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6906 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6907 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6910 /* Make sure that a proper texture unit is selected */
6911 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6912 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6913 checkGLcall("glActiveTextureARB");
6915 sampler = This->rev_tex_unit_map[0];
6916 if (sampler != -1) {
6917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6919 /* Create a new cursor texture */
6920 glGenTextures(1, &This->cursorTexture);
6921 checkGLcall("glGenTextures");
6922 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6923 checkGLcall("glBindTexture");
6924 /* Copy the bitmap memory into the cursor texture */
6925 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6926 HeapFree(GetProcessHeap(), 0, mem);
6927 checkGLcall("glTexImage2D");
6929 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6930 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6931 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6938 FIXME("A cursor texture was not returned.\n");
6939 This->cursorTexture = 0;
6944 /* Draw a hardware cursor */
6945 ICONINFO cursorInfo;
6947 /* Create and clear maskBits because it is not needed for
6948 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6950 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6951 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6952 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6953 WINED3DLOCK_NO_DIRTY_UPDATE |
6954 WINED3DLOCK_READONLY
6956 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6957 pSur->currentDesc.Height);
6959 cursorInfo.fIcon = FALSE;
6960 cursorInfo.xHotspot = XHotSpot;
6961 cursorInfo.yHotspot = YHotSpot;
6962 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6963 pSur->currentDesc.Height, 1,
6965 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6966 pSur->currentDesc.Height, 1,
6967 32, lockedRect.pBits);
6968 IWineD3DSurface_UnlockRect(pCursorBitmap);
6969 /* Create our cursor and clean up. */
6970 cursor = CreateIconIndirect(&cursorInfo);
6972 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6973 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6974 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6975 This->hardwareCursor = cursor;
6976 HeapFree(GetProcessHeap(), 0, maskBits);
6980 This->xHotSpot = XHotSpot;
6981 This->yHotSpot = YHotSpot;
6985 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6987 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6989 This->xScreenSpace = XScreenSpace;
6990 This->yScreenSpace = YScreenSpace;
6996 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6998 BOOL oldVisible = This->bCursorVisible;
7001 TRACE("(%p) : visible(%d)\n", This, bShow);
7004 * When ShowCursor is first called it should make the cursor appear at the OS's last
7005 * known cursor position. Because of this, some applications just repetitively call
7006 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7009 This->xScreenSpace = pt.x;
7010 This->yScreenSpace = pt.y;
7012 if (This->haveHardwareCursor) {
7013 This->bCursorVisible = bShow;
7015 SetCursor(This->hardwareCursor);
7021 if (This->cursorTexture)
7022 This->bCursorVisible = bShow;
7028 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7030 IWineD3DResourceImpl *resource;
7031 TRACE("(%p) : state (%u)\n", This, This->state);
7033 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7034 switch (This->state) {
7037 case WINED3DERR_DEVICELOST:
7039 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7040 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7041 return WINED3DERR_DEVICENOTRESET;
7043 return WINED3DERR_DEVICELOST;
7045 case WINED3DERR_DRIVERINTERNALERROR:
7046 return WINED3DERR_DRIVERINTERNALERROR;
7050 return WINED3DERR_DRIVERINTERNALERROR;
7054 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7056 /** FIXME: Resource tracking needs to be done,
7057 * The closes we can do to this is set the priorities of all managed textures low
7058 * and then reset them.
7059 ***********************************************************/
7060 FIXME("(%p) : stub\n", This);
7064 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7065 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7067 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7068 if(surface->Flags & SFLAG_DIBSECTION) {
7069 /* Release the DC */
7070 SelectObject(surface->hDC, surface->dib.holdbitmap);
7071 DeleteDC(surface->hDC);
7072 /* Release the DIB section */
7073 DeleteObject(surface->dib.DIBsection);
7074 surface->dib.bitmap_data = NULL;
7075 surface->resource.allocatedMemory = NULL;
7076 surface->Flags &= ~SFLAG_DIBSECTION;
7078 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7079 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7080 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7081 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7082 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7083 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7085 surface->pow2Width = surface->pow2Height = 1;
7086 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7087 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7089 surface->glRect.left = 0;
7090 surface->glRect.top = 0;
7091 surface->glRect.right = surface->pow2Width;
7092 surface->glRect.bottom = surface->pow2Height;
7094 if(surface->glDescription.textureName) {
7095 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7097 glDeleteTextures(1, &surface->glDescription.textureName);
7099 surface->glDescription.textureName = 0;
7100 surface->Flags &= ~SFLAG_CLIENT;
7102 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7103 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7104 surface->Flags |= SFLAG_NONPOW2;
7106 surface->Flags &= ~SFLAG_NONPOW2;
7108 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7109 surface->resource.allocatedMemory = NULL;
7110 surface->resource.heapMemory = NULL;
7111 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7112 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7113 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7114 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7116 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7120 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7121 TRACE("Unloading resource %p\n", resource);
7122 IWineD3DResource_UnLoad(resource);
7123 IWineD3DResource_Release(resource);
7127 static void reset_fbo_state(IWineD3DDevice *iface) {
7128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7132 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7133 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7136 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7139 if (This->src_fbo) {
7140 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7143 if (This->dst_fbo) {
7144 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7147 checkGLcall("Tear down FBOs\n");
7150 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7151 This->fbo_color_attachments[i] = NULL;
7153 This->fbo_depth_attachment = NULL;
7156 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7158 WINED3DDISPLAYMODE m;
7161 /* All Windowed modes are supported, as is leaving the current mode */
7162 if(pp->Windowed) return TRUE;
7163 if(!pp->BackBufferWidth) return TRUE;
7164 if(!pp->BackBufferHeight) return TRUE;
7166 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7167 for(i = 0; i < count; i++) {
7168 memset(&m, 0, sizeof(m));
7169 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7171 ERR("EnumAdapterModes failed\n");
7173 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7174 /* Mode found, it is supported */
7178 /* Mode not found -> not supported */
7182 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7184 IWineD3DSwapChainImpl *swapchain;
7186 BOOL DisplayModeChanged = FALSE;
7187 WINED3DDISPLAYMODE mode;
7188 IWineD3DBaseShaderImpl *shader;
7189 IWineD3DSurfaceImpl *target;
7191 TRACE("(%p)\n", This);
7193 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7195 ERR("Failed to get the first implicit swapchain\n");
7199 if(!is_display_mode_supported(This, pPresentationParameters)) {
7200 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7201 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7202 pPresentationParameters->BackBufferHeight);
7203 return WINED3DERR_INVALIDCALL;
7206 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7207 * on an existing gl context, so there's no real need for recreation.
7209 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7211 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7213 TRACE("New params:\n");
7214 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7215 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7216 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7217 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7218 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7219 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7220 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7221 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7222 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7223 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7224 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7225 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7226 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7228 /* No special treatment of these parameters. Just store them */
7229 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7230 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7231 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7232 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7234 /* What to do about these? */
7235 if(pPresentationParameters->BackBufferCount != 0 &&
7236 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7237 ERR("Cannot change the back buffer count yet\n");
7239 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7240 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7241 ERR("Cannot change the back buffer format yet\n");
7243 if(pPresentationParameters->hDeviceWindow != NULL &&
7244 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7245 ERR("Cannot change the device window yet\n");
7247 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7248 ERR("What do do about a changed auto depth stencil parameter?\n");
7251 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7252 reset_fbo_state((IWineD3DDevice *) This);
7255 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7256 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7257 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7261 if(This->depth_blt_texture) {
7262 glDeleteTextures(1, &This->depth_blt_texture);
7263 This->depth_blt_texture = 0;
7265 if (This->depth_blt_rb) {
7266 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7267 This->depth_blt_rb = 0;
7268 This->depth_blt_rb_w = 0;
7269 This->depth_blt_rb_h = 0;
7271 This->frag_pipe->free_private(iface);
7272 This->shader_backend->shader_free_private(iface);
7274 for (i = 0; i < GL_LIMITS(textures); i++) {
7275 /* Textures are recreated below */
7276 glDeleteTextures(1, &This->dummyTextureName[i]);
7277 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7278 This->dummyTextureName[i] = 0;
7282 while(This->numContexts) {
7283 DestroyContext(This, This->contexts[0]);
7285 This->activeContext = NULL;
7286 HeapFree(GetProcessHeap(), 0, swapchain->context);
7287 swapchain->context = NULL;
7288 swapchain->num_contexts = 0;
7290 if(pPresentationParameters->Windowed) {
7291 mode.Width = swapchain->orig_width;
7292 mode.Height = swapchain->orig_height;
7293 mode.RefreshRate = 0;
7294 mode.Format = swapchain->presentParms.BackBufferFormat;
7296 mode.Width = pPresentationParameters->BackBufferWidth;
7297 mode.Height = pPresentationParameters->BackBufferHeight;
7298 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7299 mode.Format = swapchain->presentParms.BackBufferFormat;
7302 /* Should Width == 800 && Height == 0 set 800x600? */
7303 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7304 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7305 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7312 vp.Width = pPresentationParameters->BackBufferWidth;
7313 vp.Height = pPresentationParameters->BackBufferHeight;
7317 if(!pPresentationParameters->Windowed) {
7318 DisplayModeChanged = TRUE;
7320 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7321 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7323 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7324 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7325 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7327 if(This->auto_depth_stencil_buffer) {
7328 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7332 /* Now set the new viewport */
7333 IWineD3DDevice_SetViewport(iface, &vp);
7336 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7337 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7338 DisplayModeChanged) {
7340 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7341 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7342 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7343 } else if(!pPresentationParameters->Windowed) {
7344 DWORD style = This->style, exStyle = This->exStyle;
7345 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7346 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7347 * Reset to clear up their mess. Guild Wars also loses the device during that.
7351 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7352 This->style = style;
7353 This->exStyle = exStyle;
7356 /* Recreate the primary swapchain's context */
7357 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7358 if(swapchain->backBuffer) {
7359 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7361 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7363 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7364 &swapchain->presentParms);
7365 swapchain->num_contexts = 1;
7366 This->activeContext = swapchain->context[0];
7367 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7369 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7371 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7373 create_dummy_textures(This);
7376 hr = This->shader_backend->shader_alloc_private(iface);
7378 ERR("Failed to recreate shader private data\n");
7381 hr = This->frag_pipe->alloc_private(iface);
7383 TRACE("Fragment pipeline private data couldn't be allocated\n");
7387 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7393 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7395 /** FIXME: always true at the moment **/
7396 if(!bEnableDialogs) {
7397 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7403 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7405 TRACE("(%p) : pParameters %p\n", This, pParameters);
7407 *pParameters = This->createParms;
7411 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7412 IWineD3DSwapChain *swapchain;
7414 TRACE("Relaying to swapchain\n");
7416 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7417 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7418 IWineD3DSwapChain_Release(swapchain);
7423 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7424 IWineD3DSwapChain *swapchain;
7426 TRACE("Relaying to swapchain\n");
7428 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7429 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7430 IWineD3DSwapChain_Release(swapchain);
7436 /** ********************************************************
7437 * Notification functions
7438 ** ********************************************************/
7439 /** This function must be called in the release of a resource when ref == 0,
7440 * the contents of resource must still be correct,
7441 * any handles to other resource held by the caller must be closed
7442 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7443 *****************************************************/
7444 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7447 TRACE("(%p) : Adding Resource %p\n", This, resource);
7448 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7451 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7454 TRACE("(%p) : Removing resource %p\n", This, resource);
7456 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7460 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7464 TRACE("(%p) : resource %p\n", This, resource);
7465 switch(IWineD3DResource_GetType(resource)){
7466 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7467 case WINED3DRTYPE_SURFACE: {
7470 /* Cleanup any FBO attachments if d3d is enabled */
7471 if(This->d3d_initialized) {
7472 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7473 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7475 TRACE("Last active render target destroyed\n");
7476 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7477 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7478 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7479 * and the lastActiveRenderTarget member shouldn't matter
7482 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7483 TRACE("Activating primary back buffer\n");
7484 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7485 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7486 /* Single buffering environment */
7487 TRACE("Activating primary front buffer\n");
7488 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7490 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7491 /* Implicit render target destroyed, that means the device is being destroyed
7492 * whatever we set here, it shouldn't matter
7494 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7497 /* May happen during ddraw uninitialization */
7498 TRACE("Render target set, but swapchain does not exist!\n");
7499 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7504 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7505 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7506 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7507 set_render_target_fbo(iface, i, NULL);
7508 This->fbo_color_attachments[i] = NULL;
7511 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7512 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7513 set_depth_stencil_fbo(iface, NULL);
7514 This->fbo_depth_attachment = NULL;
7521 case WINED3DRTYPE_TEXTURE:
7522 case WINED3DRTYPE_CUBETEXTURE:
7523 case WINED3DRTYPE_VOLUMETEXTURE:
7524 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7525 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7526 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7527 This->stateBlock->textures[counter] = NULL;
7529 if (This->updateStateBlock != This->stateBlock ){
7530 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7531 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7532 This->updateStateBlock->textures[counter] = NULL;
7537 case WINED3DRTYPE_VOLUME:
7538 /* TODO: nothing really? */
7540 case WINED3DRTYPE_VERTEXBUFFER:
7541 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7544 TRACE("Cleaning up stream pointers\n");
7546 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7547 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7548 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7550 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7551 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7552 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7553 This->updateStateBlock->streamSource[streamNumber] = 0;
7554 /* Set changed flag? */
7557 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) */
7558 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7559 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7560 This->stateBlock->streamSource[streamNumber] = 0;
7563 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7564 else { /* This shouldn't happen */
7565 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7572 case WINED3DRTYPE_INDEXBUFFER:
7573 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7574 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7575 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7576 This->updateStateBlock->pIndexData = NULL;
7579 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7580 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7581 This->stateBlock->pIndexData = NULL;
7587 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7592 /* Remove the resource from the resourceStore */
7593 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7595 TRACE("Resource released\n");
7599 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7601 IWineD3DResourceImpl *resource, *cursor;
7603 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7605 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7606 TRACE("enumerating resource %p\n", resource);
7607 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7608 ret = pCallback((IWineD3DResource *) resource, pData);
7609 if(ret == S_FALSE) {
7610 TRACE("Canceling enumeration\n");
7617 /**********************************************************
7618 * IWineD3DDevice VTbl follows
7619 **********************************************************/
7621 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7623 /*** IUnknown methods ***/
7624 IWineD3DDeviceImpl_QueryInterface,
7625 IWineD3DDeviceImpl_AddRef,
7626 IWineD3DDeviceImpl_Release,
7627 /*** IWineD3DDevice methods ***/
7628 IWineD3DDeviceImpl_GetParent,
7629 /*** Creation methods**/
7630 IWineD3DDeviceImpl_CreateVertexBuffer,
7631 IWineD3DDeviceImpl_CreateIndexBuffer,
7632 IWineD3DDeviceImpl_CreateStateBlock,
7633 IWineD3DDeviceImpl_CreateSurface,
7634 IWineD3DDeviceImpl_CreateTexture,
7635 IWineD3DDeviceImpl_CreateVolumeTexture,
7636 IWineD3DDeviceImpl_CreateVolume,
7637 IWineD3DDeviceImpl_CreateCubeTexture,
7638 IWineD3DDeviceImpl_CreateQuery,
7639 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7640 IWineD3DDeviceImpl_CreateVertexDeclaration,
7641 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7642 IWineD3DDeviceImpl_CreateVertexShader,
7643 IWineD3DDeviceImpl_CreatePixelShader,
7644 IWineD3DDeviceImpl_CreatePalette,
7645 /*** Odd functions **/
7646 IWineD3DDeviceImpl_Init3D,
7647 IWineD3DDeviceImpl_Uninit3D,
7648 IWineD3DDeviceImpl_SetFullscreen,
7649 IWineD3DDeviceImpl_SetMultithreaded,
7650 IWineD3DDeviceImpl_EvictManagedResources,
7651 IWineD3DDeviceImpl_GetAvailableTextureMem,
7652 IWineD3DDeviceImpl_GetBackBuffer,
7653 IWineD3DDeviceImpl_GetCreationParameters,
7654 IWineD3DDeviceImpl_GetDeviceCaps,
7655 IWineD3DDeviceImpl_GetDirect3D,
7656 IWineD3DDeviceImpl_GetDisplayMode,
7657 IWineD3DDeviceImpl_SetDisplayMode,
7658 IWineD3DDeviceImpl_GetHWND,
7659 IWineD3DDeviceImpl_SetHWND,
7660 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7661 IWineD3DDeviceImpl_GetRasterStatus,
7662 IWineD3DDeviceImpl_GetSwapChain,
7663 IWineD3DDeviceImpl_Reset,
7664 IWineD3DDeviceImpl_SetDialogBoxMode,
7665 IWineD3DDeviceImpl_SetCursorProperties,
7666 IWineD3DDeviceImpl_SetCursorPosition,
7667 IWineD3DDeviceImpl_ShowCursor,
7668 IWineD3DDeviceImpl_TestCooperativeLevel,
7669 /*** Getters and setters **/
7670 IWineD3DDeviceImpl_SetClipPlane,
7671 IWineD3DDeviceImpl_GetClipPlane,
7672 IWineD3DDeviceImpl_SetClipStatus,
7673 IWineD3DDeviceImpl_GetClipStatus,
7674 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7675 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7676 IWineD3DDeviceImpl_SetDepthStencilSurface,
7677 IWineD3DDeviceImpl_GetDepthStencilSurface,
7678 IWineD3DDeviceImpl_SetFVF,
7679 IWineD3DDeviceImpl_GetFVF,
7680 IWineD3DDeviceImpl_SetGammaRamp,
7681 IWineD3DDeviceImpl_GetGammaRamp,
7682 IWineD3DDeviceImpl_SetIndices,
7683 IWineD3DDeviceImpl_GetIndices,
7684 IWineD3DDeviceImpl_SetBaseVertexIndex,
7685 IWineD3DDeviceImpl_GetBaseVertexIndex,
7686 IWineD3DDeviceImpl_SetLight,
7687 IWineD3DDeviceImpl_GetLight,
7688 IWineD3DDeviceImpl_SetLightEnable,
7689 IWineD3DDeviceImpl_GetLightEnable,
7690 IWineD3DDeviceImpl_SetMaterial,
7691 IWineD3DDeviceImpl_GetMaterial,
7692 IWineD3DDeviceImpl_SetNPatchMode,
7693 IWineD3DDeviceImpl_GetNPatchMode,
7694 IWineD3DDeviceImpl_SetPaletteEntries,
7695 IWineD3DDeviceImpl_GetPaletteEntries,
7696 IWineD3DDeviceImpl_SetPixelShader,
7697 IWineD3DDeviceImpl_GetPixelShader,
7698 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7699 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7700 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7701 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7702 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7703 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7704 IWineD3DDeviceImpl_SetRenderState,
7705 IWineD3DDeviceImpl_GetRenderState,
7706 IWineD3DDeviceImpl_SetRenderTarget,
7707 IWineD3DDeviceImpl_GetRenderTarget,
7708 IWineD3DDeviceImpl_SetFrontBackBuffers,
7709 IWineD3DDeviceImpl_SetSamplerState,
7710 IWineD3DDeviceImpl_GetSamplerState,
7711 IWineD3DDeviceImpl_SetScissorRect,
7712 IWineD3DDeviceImpl_GetScissorRect,
7713 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7714 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7715 IWineD3DDeviceImpl_SetStreamSource,
7716 IWineD3DDeviceImpl_GetStreamSource,
7717 IWineD3DDeviceImpl_SetStreamSourceFreq,
7718 IWineD3DDeviceImpl_GetStreamSourceFreq,
7719 IWineD3DDeviceImpl_SetTexture,
7720 IWineD3DDeviceImpl_GetTexture,
7721 IWineD3DDeviceImpl_SetTextureStageState,
7722 IWineD3DDeviceImpl_GetTextureStageState,
7723 IWineD3DDeviceImpl_SetTransform,
7724 IWineD3DDeviceImpl_GetTransform,
7725 IWineD3DDeviceImpl_SetVertexDeclaration,
7726 IWineD3DDeviceImpl_GetVertexDeclaration,
7727 IWineD3DDeviceImpl_SetVertexShader,
7728 IWineD3DDeviceImpl_GetVertexShader,
7729 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7730 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7731 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7732 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7733 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7734 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7735 IWineD3DDeviceImpl_SetViewport,
7736 IWineD3DDeviceImpl_GetViewport,
7737 IWineD3DDeviceImpl_MultiplyTransform,
7738 IWineD3DDeviceImpl_ValidateDevice,
7739 IWineD3DDeviceImpl_ProcessVertices,
7740 /*** State block ***/
7741 IWineD3DDeviceImpl_BeginStateBlock,
7742 IWineD3DDeviceImpl_EndStateBlock,
7743 /*** Scene management ***/
7744 IWineD3DDeviceImpl_BeginScene,
7745 IWineD3DDeviceImpl_EndScene,
7746 IWineD3DDeviceImpl_Present,
7747 IWineD3DDeviceImpl_Clear,
7749 IWineD3DDeviceImpl_DrawPrimitive,
7750 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7751 IWineD3DDeviceImpl_DrawPrimitiveUP,
7752 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7753 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7754 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7755 IWineD3DDeviceImpl_DrawRectPatch,
7756 IWineD3DDeviceImpl_DrawTriPatch,
7757 IWineD3DDeviceImpl_DeletePatch,
7758 IWineD3DDeviceImpl_ColorFill,
7759 IWineD3DDeviceImpl_UpdateTexture,
7760 IWineD3DDeviceImpl_UpdateSurface,
7761 IWineD3DDeviceImpl_GetFrontBufferData,
7762 /*** object tracking ***/
7763 IWineD3DDeviceImpl_ResourceReleased,
7764 IWineD3DDeviceImpl_EnumResources
7767 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7769 /*** IUnknown methods ***/
7770 IWineD3DDeviceImpl_QueryInterface,
7771 IWineD3DDeviceImpl_AddRef,
7772 IWineD3DDeviceImpl_Release,
7773 /*** IWineD3DDevice methods ***/
7774 IWineD3DDeviceImpl_GetParent,
7775 /*** Creation methods**/
7776 IWineD3DDeviceImpl_CreateVertexBuffer,
7777 IWineD3DDeviceImpl_CreateIndexBuffer,
7778 IWineD3DDeviceImpl_CreateStateBlock,
7779 IWineD3DDeviceImpl_CreateSurface,
7780 IWineD3DDeviceImpl_CreateTexture,
7781 IWineD3DDeviceImpl_CreateVolumeTexture,
7782 IWineD3DDeviceImpl_CreateVolume,
7783 IWineD3DDeviceImpl_CreateCubeTexture,
7784 IWineD3DDeviceImpl_CreateQuery,
7785 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7786 IWineD3DDeviceImpl_CreateVertexDeclaration,
7787 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7788 IWineD3DDeviceImpl_CreateVertexShader,
7789 IWineD3DDeviceImpl_CreatePixelShader,
7790 IWineD3DDeviceImpl_CreatePalette,
7791 /*** Odd functions **/
7792 IWineD3DDeviceImpl_Init3D,
7793 IWineD3DDeviceImpl_Uninit3D,
7794 IWineD3DDeviceImpl_SetFullscreen,
7795 IWineD3DDeviceImpl_SetMultithreaded,
7796 IWineD3DDeviceImpl_EvictManagedResources,
7797 IWineD3DDeviceImpl_GetAvailableTextureMem,
7798 IWineD3DDeviceImpl_GetBackBuffer,
7799 IWineD3DDeviceImpl_GetCreationParameters,
7800 IWineD3DDeviceImpl_GetDeviceCaps,
7801 IWineD3DDeviceImpl_GetDirect3D,
7802 IWineD3DDeviceImpl_GetDisplayMode,
7803 IWineD3DDeviceImpl_SetDisplayMode,
7804 IWineD3DDeviceImpl_GetHWND,
7805 IWineD3DDeviceImpl_SetHWND,
7806 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7807 IWineD3DDeviceImpl_GetRasterStatus,
7808 IWineD3DDeviceImpl_GetSwapChain,
7809 IWineD3DDeviceImpl_Reset,
7810 IWineD3DDeviceImpl_SetDialogBoxMode,
7811 IWineD3DDeviceImpl_SetCursorProperties,
7812 IWineD3DDeviceImpl_SetCursorPosition,
7813 IWineD3DDeviceImpl_ShowCursor,
7814 IWineD3DDeviceImpl_TestCooperativeLevel,
7815 /*** Getters and setters **/
7816 IWineD3DDeviceImpl_SetClipPlane,
7817 IWineD3DDeviceImpl_GetClipPlane,
7818 IWineD3DDeviceImpl_SetClipStatus,
7819 IWineD3DDeviceImpl_GetClipStatus,
7820 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7821 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7822 IWineD3DDeviceImpl_SetDepthStencilSurface,
7823 IWineD3DDeviceImpl_GetDepthStencilSurface,
7824 IWineD3DDeviceImpl_SetFVF,
7825 IWineD3DDeviceImpl_GetFVF,
7826 IWineD3DDeviceImpl_SetGammaRamp,
7827 IWineD3DDeviceImpl_GetGammaRamp,
7828 IWineD3DDeviceImpl_SetIndices,
7829 IWineD3DDeviceImpl_GetIndices,
7830 IWineD3DDeviceImpl_SetBaseVertexIndex,
7831 IWineD3DDeviceImpl_GetBaseVertexIndex,
7832 IWineD3DDeviceImpl_SetLight,
7833 IWineD3DDeviceImpl_GetLight,
7834 IWineD3DDeviceImpl_SetLightEnable,
7835 IWineD3DDeviceImpl_GetLightEnable,
7836 IWineD3DDeviceImpl_SetMaterial,
7837 IWineD3DDeviceImpl_GetMaterial,
7838 IWineD3DDeviceImpl_SetNPatchMode,
7839 IWineD3DDeviceImpl_GetNPatchMode,
7840 IWineD3DDeviceImpl_SetPaletteEntries,
7841 IWineD3DDeviceImpl_GetPaletteEntries,
7842 IWineD3DDeviceImpl_SetPixelShader,
7843 IWineD3DDeviceImpl_GetPixelShader,
7844 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7845 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7846 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7847 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7848 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7849 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7850 IWineD3DDeviceImpl_SetRenderState,
7851 IWineD3DDeviceImpl_GetRenderState,
7852 IWineD3DDeviceImpl_SetRenderTarget,
7853 IWineD3DDeviceImpl_GetRenderTarget,
7854 IWineD3DDeviceImpl_SetFrontBackBuffers,
7855 IWineD3DDeviceImpl_SetSamplerState,
7856 IWineD3DDeviceImpl_GetSamplerState,
7857 IWineD3DDeviceImpl_SetScissorRect,
7858 IWineD3DDeviceImpl_GetScissorRect,
7859 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7860 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7861 IWineD3DDeviceImpl_SetStreamSource,
7862 IWineD3DDeviceImpl_GetStreamSource,
7863 IWineD3DDeviceImpl_SetStreamSourceFreq,
7864 IWineD3DDeviceImpl_GetStreamSourceFreq,
7865 IWineD3DDeviceImpl_SetTexture,
7866 IWineD3DDeviceImpl_GetTexture,
7867 IWineD3DDeviceImpl_SetTextureStageState,
7868 IWineD3DDeviceImpl_GetTextureStageState,
7869 IWineD3DDeviceImpl_SetTransform,
7870 IWineD3DDeviceImpl_GetTransform,
7871 IWineD3DDeviceImpl_SetVertexDeclaration,
7872 IWineD3DDeviceImpl_GetVertexDeclaration,
7873 IWineD3DDeviceImpl_SetVertexShader,
7874 IWineD3DDeviceImpl_GetVertexShader,
7875 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7876 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7877 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7878 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7879 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7880 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7881 IWineD3DDeviceImpl_SetViewport,
7882 IWineD3DDeviceImpl_GetViewport,
7883 IWineD3DDeviceImpl_MultiplyTransform,
7884 IWineD3DDeviceImpl_ValidateDevice,
7885 IWineD3DDeviceImpl_ProcessVertices,
7886 /*** State block ***/
7887 IWineD3DDeviceImpl_BeginStateBlock,
7888 IWineD3DDeviceImpl_EndStateBlock,
7889 /*** Scene management ***/
7890 IWineD3DDeviceImpl_BeginScene,
7891 IWineD3DDeviceImpl_EndScene,
7892 IWineD3DDeviceImpl_Present,
7893 IWineD3DDeviceImpl_Clear,
7895 IWineD3DDeviceImpl_DrawPrimitive,
7896 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7897 IWineD3DDeviceImpl_DrawPrimitiveUP,
7898 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7899 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7900 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7901 IWineD3DDeviceImpl_DrawRectPatch,
7902 IWineD3DDeviceImpl_DrawTriPatch,
7903 IWineD3DDeviceImpl_DeletePatch,
7904 IWineD3DDeviceImpl_ColorFill,
7905 IWineD3DDeviceImpl_UpdateTexture,
7906 IWineD3DDeviceImpl_UpdateSurface,
7907 IWineD3DDeviceImpl_GetFrontBufferData,
7908 /*** object tracking ***/
7909 IWineD3DDeviceImpl_ResourceReleased,
7910 IWineD3DDeviceImpl_EnumResources
7913 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7914 WINED3DRS_ALPHABLENDENABLE ,
7915 WINED3DRS_ALPHAFUNC ,
7916 WINED3DRS_ALPHAREF ,
7917 WINED3DRS_ALPHATESTENABLE ,
7919 WINED3DRS_COLORWRITEENABLE ,
7920 WINED3DRS_DESTBLEND ,
7921 WINED3DRS_DITHERENABLE ,
7922 WINED3DRS_FILLMODE ,
7923 WINED3DRS_FOGDENSITY ,
7925 WINED3DRS_FOGSTART ,
7926 WINED3DRS_LASTPIXEL ,
7927 WINED3DRS_SHADEMODE ,
7928 WINED3DRS_SRCBLEND ,
7929 WINED3DRS_STENCILENABLE ,
7930 WINED3DRS_STENCILFAIL ,
7931 WINED3DRS_STENCILFUNC ,
7932 WINED3DRS_STENCILMASK ,
7933 WINED3DRS_STENCILPASS ,
7934 WINED3DRS_STENCILREF ,
7935 WINED3DRS_STENCILWRITEMASK ,
7936 WINED3DRS_STENCILZFAIL ,
7937 WINED3DRS_TEXTUREFACTOR ,
7948 WINED3DRS_ZWRITEENABLE
7951 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7952 WINED3DTSS_ADDRESSW ,
7953 WINED3DTSS_ALPHAARG0 ,
7954 WINED3DTSS_ALPHAARG1 ,
7955 WINED3DTSS_ALPHAARG2 ,
7956 WINED3DTSS_ALPHAOP ,
7957 WINED3DTSS_BUMPENVLOFFSET ,
7958 WINED3DTSS_BUMPENVLSCALE ,
7959 WINED3DTSS_BUMPENVMAT00 ,
7960 WINED3DTSS_BUMPENVMAT01 ,
7961 WINED3DTSS_BUMPENVMAT10 ,
7962 WINED3DTSS_BUMPENVMAT11 ,
7963 WINED3DTSS_COLORARG0 ,
7964 WINED3DTSS_COLORARG1 ,
7965 WINED3DTSS_COLORARG2 ,
7966 WINED3DTSS_COLOROP ,
7967 WINED3DTSS_RESULTARG ,
7968 WINED3DTSS_TEXCOORDINDEX ,
7969 WINED3DTSS_TEXTURETRANSFORMFLAGS
7972 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7973 WINED3DSAMP_ADDRESSU ,
7974 WINED3DSAMP_ADDRESSV ,
7975 WINED3DSAMP_ADDRESSW ,
7976 WINED3DSAMP_BORDERCOLOR ,
7977 WINED3DSAMP_MAGFILTER ,
7978 WINED3DSAMP_MINFILTER ,
7979 WINED3DSAMP_MIPFILTER ,
7980 WINED3DSAMP_MIPMAPLODBIAS ,
7981 WINED3DSAMP_MAXMIPLEVEL ,
7982 WINED3DSAMP_MAXANISOTROPY ,
7983 WINED3DSAMP_SRGBTEXTURE ,
7984 WINED3DSAMP_ELEMENTINDEX
7987 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7989 WINED3DRS_AMBIENTMATERIALSOURCE ,
7990 WINED3DRS_CLIPPING ,
7991 WINED3DRS_CLIPPLANEENABLE ,
7992 WINED3DRS_COLORVERTEX ,
7993 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7994 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7995 WINED3DRS_FOGDENSITY ,
7997 WINED3DRS_FOGSTART ,
7998 WINED3DRS_FOGTABLEMODE ,
7999 WINED3DRS_FOGVERTEXMODE ,
8000 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8001 WINED3DRS_LIGHTING ,
8002 WINED3DRS_LOCALVIEWER ,
8003 WINED3DRS_MULTISAMPLEANTIALIAS ,
8004 WINED3DRS_MULTISAMPLEMASK ,
8005 WINED3DRS_NORMALIZENORMALS ,
8006 WINED3DRS_PATCHEDGESTYLE ,
8007 WINED3DRS_POINTSCALE_A ,
8008 WINED3DRS_POINTSCALE_B ,
8009 WINED3DRS_POINTSCALE_C ,
8010 WINED3DRS_POINTSCALEENABLE ,
8011 WINED3DRS_POINTSIZE ,
8012 WINED3DRS_POINTSIZE_MAX ,
8013 WINED3DRS_POINTSIZE_MIN ,
8014 WINED3DRS_POINTSPRITEENABLE ,
8015 WINED3DRS_RANGEFOGENABLE ,
8016 WINED3DRS_SPECULARMATERIALSOURCE ,
8017 WINED3DRS_TWEENFACTOR ,
8018 WINED3DRS_VERTEXBLEND ,
8019 WINED3DRS_CULLMODE ,
8023 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8024 WINED3DTSS_TEXCOORDINDEX ,
8025 WINED3DTSS_TEXTURETRANSFORMFLAGS
8028 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8029 WINED3DSAMP_DMAPOFFSET
8032 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8033 DWORD rep = This->StateTable[state].representative;
8037 WineD3DContext *context;
8040 for(i = 0; i < This->numContexts; i++) {
8041 context = This->contexts[i];
8042 if(isStateDirty(context, rep)) continue;
8044 context->dirtyArray[context->numDirtyEntries++] = rep;
8047 context->isStateDirty[idx] |= (1 << shift);
8051 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8052 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8053 /* The drawable size of a pbuffer render target is the current pbuffer size
8055 *width = dev->pbufferWidth;
8056 *height = dev->pbufferHeight;
8059 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8060 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8062 *width = This->pow2Width;
8063 *height = This->pow2Height;
8066 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8067 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8068 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8069 * current context's drawable, which is the size of the back buffer of the swapchain
8070 * the active context belongs to. The back buffer of the swapchain is stored as the
8071 * surface the context belongs to.
8073 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8074 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;