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-2008 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 IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; ERR("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 D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->resource.wineD3DDevice = This; \
75 object->resource.parent = parent; \
76 object->resource.resourceType = d3dtype; \
77 object->resource.ref = 1; \
78 object->resource.pool = Pool; \
79 object->resource.format = Format; \
80 object->resource.usage = Usage; \
81 object->resource.size = _size; \
82 object->resource.priority = 0; \
83 list_init(&object->resource.privateData); \
84 /* Check that we have enough video ram left */ \
85 if (Pool == WINED3DPOOL_DEFAULT) { \
86 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
87 WARN("Out of 'bogus' video memory\n"); \
88 HeapFree(GetProcessHeap(), 0, object); \
90 return WINED3DERR_OUTOFVIDEOMEMORY; \
92 WineD3DAdapterChangeGLRam(This, _size); \
94 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
95 if (object->resource.heapMemory == NULL && _size != 0) { \
96 FIXME("Out of memory!\n"); \
97 HeapFree(GetProcessHeap(), 0, object); \
99 return WINED3DERR_OUTOFVIDEOMEMORY; \
101 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
102 *pp##type = (IWineD3D##type *) object; \
103 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
104 TRACE("(%p) : Created resource %p\n", This, object); \
107 /**********************************************************
108 * Global variable / Constants follow
109 **********************************************************/
110 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
112 /**********************************************************
113 * IUnknown parts follows
114 **********************************************************/
116 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
120 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
121 if (IsEqualGUID(riid, &IID_IUnknown)
122 || IsEqualGUID(riid, &IID_IWineD3DBase)
123 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
124 IUnknown_AddRef(iface);
129 return E_NOINTERFACE;
132 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
134 ULONG refCount = InterlockedIncrement(&This->ref);
136 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
140 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
142 ULONG refCount = InterlockedDecrement(&This->ref);
144 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
149 for (i = 0; i < sizeof(This->multistate_funcs)/sizeof(This->multistate_funcs[0]); ++i) {
150 HeapFree(GetProcessHeap(), 0, This->multistate_funcs[i]);
151 This->multistate_funcs[i] = NULL;
154 /* TODO: Clean up all the surfaces and textures! */
155 /* NOTE: You must release the parent if the object was created via a callback
156 ** ***************************/
158 if (!list_empty(&This->resources)) {
159 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
160 dumpResources(&This->resources);
163 if(This->contexts) ERR("Context array not freed!\n");
164 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
165 This->haveHardwareCursor = FALSE;
167 IWineD3D_Release(This->wineD3D);
168 This->wineD3D = NULL;
169 HeapFree(GetProcessHeap(), 0, This);
170 TRACE("Freed device %p\n", This);
176 /**********************************************************
177 * IWineD3DDevice implementation follows
178 **********************************************************/
179 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
181 *pParent = This->parent;
182 IUnknown_AddRef(This->parent);
186 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
187 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
190 IWineD3DVertexBufferImpl *object;
191 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
192 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
196 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
197 *ppVertexBuffer = NULL;
198 return WINED3DERR_INVALIDCALL;
199 } else if(Pool == WINED3DPOOL_SCRATCH) {
200 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
201 * anyway, SCRATCH vertex buffers aren't usable anywhere
203 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
204 *ppVertexBuffer = NULL;
205 return WINED3DERR_INVALIDCALL;
208 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
210 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);
211 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
215 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
216 * drawStridedFast (half-life 2).
218 * Basically converting the vertices in the buffer is quite expensive, and observations
219 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
220 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
222 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
223 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
224 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
225 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
227 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
228 * more. In this call we can convert dx7 buffers too.
230 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
231 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
232 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
233 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
234 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
235 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
236 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
237 } else if(dxVersion <= 7 && conv) {
238 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
240 object->Flags |= VBFLAG_CREATEVBO;
245 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
246 GLenum error, glUsage;
247 TRACE("Creating VBO for Index Buffer %p\n", object);
249 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
250 * restored on the next draw
252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
254 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
255 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
260 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
261 error = glGetError();
262 if(error != GL_NO_ERROR || object->vbo == 0) {
263 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
267 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
268 error = glGetError();
269 if(error != GL_NO_ERROR) {
270 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
274 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
275 * copy no readback will be needed
277 glUsage = GL_STATIC_DRAW_ARB;
278 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
279 error = glGetError();
280 if(error != GL_NO_ERROR) {
281 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
285 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
290 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
295 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
296 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
297 HANDLE *sharedHandle, IUnknown *parent) {
298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
299 IWineD3DIndexBufferImpl *object;
300 TRACE("(%p) Creating index buffer\n", This);
302 /* Allocate the storage for the device */
303 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
305 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
306 CreateIndexBufferVBO(This, object);
309 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
310 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
311 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
316 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
319 IWineD3DStateBlockImpl *object;
323 D3DCREATEOBJECTINSTANCE(object, StateBlock)
324 object->blockType = Type;
326 for(i = 0; i < LIGHTMAP_SIZE; i++) {
327 list_init(&object->lightMap[i]);
330 temp_result = allocate_shader_constants(object);
331 if (FAILED(temp_result))
333 HeapFree(GetProcessHeap(), 0, object);
337 /* Special case - Used during initialization to produce a placeholder stateblock
338 so other functions called can update a state block */
339 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
341 /* Don't bother increasing the reference count otherwise a device will never
342 be freed due to circular dependencies */
346 /* Otherwise, might as well set the whole state block to the appropriate values */
347 if (This->stateBlock != NULL)
348 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
350 memset(object->streamFreq, 1, sizeof(object->streamFreq));
352 /* Reset the ref and type after kludging it */
353 object->wineD3DDevice = This;
355 object->blockType = Type;
357 TRACE("Updating changed flags appropriate for type %d\n", Type);
359 if (Type == WINED3DSBT_ALL) {
361 TRACE("ALL => Pretend everything has changed\n");
362 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
364 /* Lights are not part of the changed / set structure */
365 for(j = 0; j < LIGHTMAP_SIZE; j++) {
367 LIST_FOR_EACH(e, &object->lightMap[j]) {
368 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
369 light->changed = TRUE;
370 light->enabledChanged = TRUE;
373 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
374 object->contained_render_states[j - 1] = j;
376 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
377 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
378 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
379 object->contained_transform_states[j - 1] = j;
381 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
382 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
383 object->contained_vs_consts_f[j] = j;
385 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
386 for(j = 0; j < MAX_CONST_I; j++) {
387 object->contained_vs_consts_i[j] = j;
389 object->num_contained_vs_consts_i = MAX_CONST_I;
390 for(j = 0; j < MAX_CONST_B; j++) {
391 object->contained_vs_consts_b[j] = j;
393 object->num_contained_vs_consts_b = MAX_CONST_B;
394 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
395 object->contained_ps_consts_f[j] = j;
397 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
398 for(j = 0; j < MAX_CONST_I; j++) {
399 object->contained_ps_consts_i[j] = j;
401 object->num_contained_ps_consts_i = MAX_CONST_I;
402 for(j = 0; j < MAX_CONST_B; j++) {
403 object->contained_ps_consts_b[j] = j;
405 object->num_contained_ps_consts_b = MAX_CONST_B;
406 for(i = 0; i < MAX_TEXTURES; i++) {
407 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
409 object->contained_tss_states[object->num_contained_tss_states].stage = i;
410 object->contained_tss_states[object->num_contained_tss_states].state = j;
411 object->num_contained_tss_states++;
414 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
415 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
416 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
417 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
418 object->num_contained_sampler_states++;
422 for(i = 0; i < MAX_STREAMS; i++) {
423 if(object->streamSource[i]) {
424 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
427 if(object->pIndexData) {
428 IWineD3DIndexBuffer_AddRef(object->pIndexData);
430 if(object->vertexShader) {
431 IWineD3DVertexShader_AddRef(object->vertexShader);
433 if(object->pixelShader) {
434 IWineD3DPixelShader_AddRef(object->pixelShader);
437 } else if (Type == WINED3DSBT_PIXELSTATE) {
439 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
440 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
442 object->changed.pixelShader = TRUE;
444 /* Pixel Shader Constants */
445 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
446 object->contained_ps_consts_f[i] = i;
447 object->changed.pixelShaderConstantsF[i] = TRUE;
449 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
450 for (i = 0; i < MAX_CONST_B; ++i) {
451 object->contained_ps_consts_b[i] = i;
452 object->changed.pixelShaderConstantsB |= (1 << i);
454 object->num_contained_ps_consts_b = MAX_CONST_B;
455 for (i = 0; i < MAX_CONST_I; ++i) {
456 object->contained_ps_consts_i[i] = i;
457 object->changed.pixelShaderConstantsI |= (1 << i);
459 object->num_contained_ps_consts_i = MAX_CONST_I;
461 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
462 DWORD rs = SavedPixelStates_R[i];
463 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
464 object->contained_render_states[i] = rs;
466 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
467 for (j = 0; j < MAX_TEXTURES; j++) {
468 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
469 DWORD state = SavedPixelStates_T[i];
470 object->changed.textureState[j] |= 1 << state;
471 object->contained_tss_states[object->num_contained_tss_states].stage = j;
472 object->contained_tss_states[object->num_contained_tss_states].state = state;
473 object->num_contained_tss_states++;
476 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
477 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
478 DWORD state = SavedPixelStates_S[i];
479 object->changed.samplerState[j] |= 1 << state;
480 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
481 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
482 object->num_contained_sampler_states++;
485 if(object->pixelShader) {
486 IWineD3DPixelShader_AddRef(object->pixelShader);
489 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
490 * on them. This makes releasing the buffer easier
492 for(i = 0; i < MAX_STREAMS; i++) {
493 object->streamSource[i] = NULL;
495 object->pIndexData = NULL;
496 object->vertexShader = NULL;
498 } else if (Type == WINED3DSBT_VERTEXSTATE) {
500 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
501 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
503 object->changed.vertexShader = TRUE;
505 /* Vertex Shader Constants */
506 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
507 object->changed.vertexShaderConstantsF[i] = TRUE;
508 object->contained_vs_consts_f[i] = i;
510 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
511 for (i = 0; i < MAX_CONST_B; ++i) {
512 object->contained_vs_consts_b[i] = i;
513 object->changed.vertexShaderConstantsB |= (1 << i);
515 object->num_contained_vs_consts_b = MAX_CONST_B;
516 for (i = 0; i < MAX_CONST_I; ++i) {
517 object->contained_vs_consts_i[i] = i;
518 object->changed.vertexShaderConstantsI |= (1 << i);
520 object->num_contained_vs_consts_i = MAX_CONST_I;
521 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
522 DWORD rs = SavedVertexStates_R[i];
523 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
524 object->contained_render_states[i] = rs;
526 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
527 for (j = 0; j < MAX_TEXTURES; j++) {
528 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
529 DWORD state = SavedVertexStates_T[i];
530 object->changed.textureState[j] |= 1 << state;
531 object->contained_tss_states[object->num_contained_tss_states].stage = j;
532 object->contained_tss_states[object->num_contained_tss_states].state = state;
533 object->num_contained_tss_states++;
536 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
537 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
538 DWORD state = SavedVertexStates_S[i];
539 object->changed.samplerState[j] |= 1 << state;
540 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
541 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
542 object->num_contained_sampler_states++;
546 for(j = 0; j < LIGHTMAP_SIZE; j++) {
548 LIST_FOR_EACH(e, &object->lightMap[j]) {
549 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
550 light->changed = TRUE;
551 light->enabledChanged = TRUE;
555 for(i = 0; i < MAX_STREAMS; i++) {
556 if(object->streamSource[i]) {
557 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
560 if(object->vertexShader) {
561 IWineD3DVertexShader_AddRef(object->vertexShader);
563 object->pIndexData = NULL;
564 object->pixelShader = NULL;
566 FIXME("Unrecognized state block type %d\n", Type);
569 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
573 /* ************************************
575 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
578 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
580 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.
582 ******************************** */
584 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) {
585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
586 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
587 unsigned int Size = 1;
588 const struct GlPixelFormatDesc *glDesc;
589 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
591 TRACE("(%p) Create surface\n",This);
593 /** FIXME: Check ranges on the inputs are valid
596 * [in] Quality level. The valid range is between zero and one less than the level
597 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
598 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
599 * values of paired render targets, depth stencil surfaces, and the MultiSample type
601 *******************************/
606 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
608 * If this flag is set, the contents of the depth stencil buffer will be
609 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
610 * with a different depth surface.
612 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
613 ***************************/
615 if(MultisampleQuality > 0) {
616 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
617 MultisampleQuality=0;
620 /** FIXME: Check that the format is supported
622 *******************************/
624 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
625 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
627 *********************************/
628 mul_4w = (Width + 3) & ~3;
629 mul_4h = (Height + 3) & ~3;
630 if (WINED3DFMT_UNKNOWN == Format) {
632 } else if (Format == WINED3DFMT_DXT1) {
633 /* DXT1 is half byte per pixel */
634 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
636 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
637 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
638 Format == WINED3DFMT_ATI2N) {
639 Size = (mul_4w * tableEntry->bpp * mul_4h);
641 /* The pitch is a multiple of 4 bytes */
642 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
646 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
648 /** Create and initialise the surface resource **/
649 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
650 /* "Standalone" surface */
651 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
653 object->currentDesc.Width = Width;
654 object->currentDesc.Height = Height;
655 object->currentDesc.MultiSampleType = MultiSample;
656 object->currentDesc.MultiSampleQuality = MultisampleQuality;
657 object->glDescription.level = Level;
658 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
659 list_init(&object->overlays);
662 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
663 object->Flags |= Discard ? SFLAG_DISCARD : 0;
664 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
665 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
668 if (WINED3DFMT_UNKNOWN != Format) {
669 object->bytesPerPixel = tableEntry->bpp;
671 object->bytesPerPixel = 0;
674 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
676 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
678 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
679 * this function is too deep to need to care about things like this.
680 * Levels need to be checked too, and possibly Type since they all affect what can be done.
681 * ****************************************/
683 case WINED3DPOOL_SCRATCH:
685 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
686 "which are mutually exclusive, setting lockable to TRUE\n");
689 case WINED3DPOOL_SYSTEMMEM:
690 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
691 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
692 case WINED3DPOOL_MANAGED:
693 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
694 "Usage of DYNAMIC which are mutually exclusive, not doing "
695 "anything just telling you.\n");
697 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
698 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
699 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
700 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
703 FIXME("(%p) Unknown pool %d\n", This, Pool);
707 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
708 FIXME("Trying to create a render target that isn't in the default pool\n");
711 /* mark the texture as dirty so that it gets loaded first time around*/
712 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
713 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
714 This, Width, Height, Format, debug_d3dformat(Format),
715 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
717 /* Look at the implementation and set the correct Vtable */
720 /* Check if a 3D adapter is available when creating gl surfaces */
722 ERR("OpenGL surfaces are not available without opengl\n");
723 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
724 HeapFree(GetProcessHeap(), 0, object);
725 return WINED3DERR_NOTAVAILABLE;
730 object->lpVtbl = &IWineGDISurface_Vtbl;
734 /* To be sure to catch this */
735 ERR("Unknown requested surface implementation %d!\n", Impl);
736 IWineD3DSurface_Release((IWineD3DSurface *) object);
737 return WINED3DERR_INVALIDCALL;
740 list_init(&object->renderbuffers);
742 /* Call the private setup routine */
743 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
747 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
748 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
749 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
750 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
753 IWineD3DTextureImpl *object;
758 unsigned int pow2Width;
759 unsigned int pow2Height;
760 const struct GlPixelFormatDesc *glDesc;
761 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
763 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
764 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
765 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
767 /* TODO: It should only be possible to create textures for formats
768 that are reported as supported */
769 if (WINED3DFMT_UNKNOWN >= Format) {
770 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
771 return WINED3DERR_INVALIDCALL;
774 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
775 basetexture_init(&object->baseTexture, Levels, Usage);
776 object->width = Width;
777 object->height = Height;
779 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
780 object->baseTexture.minMipLookup = minMipLookup;
781 object->baseTexture.magLookup = magLookup;
783 object->baseTexture.minMipLookup = minMipLookup_noFilter;
784 object->baseTexture.magLookup = magLookup_noFilter;
787 /** Non-power2 support **/
788 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
792 /* Find the nearest pow2 match */
793 pow2Width = pow2Height = 1;
794 while (pow2Width < Width) pow2Width <<= 1;
795 while (pow2Height < Height) pow2Height <<= 1;
797 if(pow2Width != Width || pow2Height != Height) {
799 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
800 HeapFree(GetProcessHeap(), 0, object);
802 return WINED3DERR_INVALIDCALL;
809 /** FIXME: add support for real non-power-two if it's provided by the video card **/
810 /* Precalculated scaling for 'faked' non power of two texture coords.
811 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
812 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
813 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
815 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
816 object->baseTexture.pow2Matrix[0] = 1.0;
817 object->baseTexture.pow2Matrix[5] = 1.0;
818 object->baseTexture.pow2Matrix[10] = 1.0;
819 object->baseTexture.pow2Matrix[15] = 1.0;
820 object->target = GL_TEXTURE_2D;
821 object->cond_np2 = TRUE;
822 object->baseTexture.minMipLookup = minMipLookup_noFilter;
823 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
824 (Width != pow2Width || Height != pow2Height) &&
825 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
827 object->baseTexture.pow2Matrix[0] = (float)Width;
828 object->baseTexture.pow2Matrix[5] = (float)Height;
829 object->baseTexture.pow2Matrix[10] = 1.0;
830 object->baseTexture.pow2Matrix[15] = 1.0;
831 object->target = GL_TEXTURE_RECTANGLE_ARB;
832 object->cond_np2 = TRUE;
833 object->baseTexture.minMipLookup = minMipLookup_noFilter;
835 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
836 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
837 object->baseTexture.pow2Matrix[10] = 1.0;
838 object->baseTexture.pow2Matrix[15] = 1.0;
839 object->target = GL_TEXTURE_2D;
840 object->cond_np2 = FALSE;
842 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
844 /* Calculate levels for mip mapping */
845 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
846 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
847 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
848 return WINED3DERR_INVALIDCALL;
851 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
852 return WINED3DERR_INVALIDCALL;
854 object->baseTexture.levels = 1;
855 } else if (Levels == 0) {
856 object->baseTexture.levels = wined3d_log2i(max(Width, Height)) + 1;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 surface_set_texture_target(object->surfaces[i], object->target);
880 /* calculate the next mipmap level */
881 tmpW = max(1, tmpW >> 1);
882 tmpH = max(1, tmpH >> 1);
884 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
886 TRACE("(%p) : Created texture %p\n", This, object);
890 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
891 UINT Width, UINT Height, UINT Depth,
892 UINT Levels, DWORD Usage,
893 WINED3DFORMAT Format, WINED3DPOOL Pool,
894 IWineD3DVolumeTexture **ppVolumeTexture,
895 HANDLE *pSharedHandle, IUnknown *parent,
896 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
899 IWineD3DVolumeTextureImpl *object;
904 const struct GlPixelFormatDesc *glDesc;
906 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
908 /* TODO: It should only be possible to create textures for formats
909 that are reported as supported */
910 if (WINED3DFMT_UNKNOWN >= Format) {
911 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
912 return WINED3DERR_INVALIDCALL;
914 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
915 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
916 return WINED3DERR_INVALIDCALL;
919 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
920 basetexture_init(&object->baseTexture, Levels, Usage);
922 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
923 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
925 /* Is NP2 support for volumes needed? */
926 object->baseTexture.pow2Matrix[ 0] = 1.0;
927 object->baseTexture.pow2Matrix[ 5] = 1.0;
928 object->baseTexture.pow2Matrix[10] = 1.0;
929 object->baseTexture.pow2Matrix[15] = 1.0;
931 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
932 object->baseTexture.minMipLookup = minMipLookup;
933 object->baseTexture.magLookup = magLookup;
935 object->baseTexture.minMipLookup = minMipLookup_noFilter;
936 object->baseTexture.magLookup = magLookup_noFilter;
939 /* Calculate levels for mip mapping */
940 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
941 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
942 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
943 return WINED3DERR_INVALIDCALL;
946 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
947 return WINED3DERR_INVALIDCALL;
949 object->baseTexture.levels = 1;
950 } else if (Levels == 0) {
951 object->baseTexture.levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
952 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
955 /* Generate all the surfaces */
960 for (i = 0; i < object->baseTexture.levels; i++)
963 /* Create the volume */
964 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
965 &object->volumes[i], pSharedHandle);
968 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
969 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
970 *ppVolumeTexture = NULL;
974 /* Set its container to this object */
975 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
977 /* calculate the next mipmap level */
978 tmpW = max(1, tmpW >> 1);
979 tmpH = max(1, tmpH >> 1);
980 tmpD = max(1, tmpD >> 1);
982 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
984 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
985 TRACE("(%p) : Created volume texture %p\n", This, object);
989 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
990 UINT Width, UINT Height, UINT Depth,
992 WINED3DFORMAT Format, WINED3DPOOL Pool,
993 IWineD3DVolume** ppVolume,
994 HANDLE* pSharedHandle, IUnknown *parent) {
996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
997 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
998 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1000 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1001 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1002 return WINED3DERR_INVALIDCALL;
1005 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1007 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1008 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1010 object->currentDesc.Width = Width;
1011 object->currentDesc.Height = Height;
1012 object->currentDesc.Depth = Depth;
1013 object->bytesPerPixel = formatDesc->bpp;
1015 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1016 object->lockable = TRUE;
1017 object->locked = FALSE;
1018 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1019 object->dirty = TRUE;
1021 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1024 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1025 UINT Levels, DWORD Usage,
1026 WINED3DFORMAT Format, WINED3DPOOL Pool,
1027 IWineD3DCubeTexture **ppCubeTexture,
1028 HANDLE *pSharedHandle, IUnknown *parent,
1029 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1032 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1036 unsigned int pow2EdgeLength;
1037 const struct GlPixelFormatDesc *glDesc;
1038 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1040 /* TODO: It should only be possible to create textures for formats
1041 that are reported as supported */
1042 if (WINED3DFMT_UNKNOWN >= Format) {
1043 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1044 return WINED3DERR_INVALIDCALL;
1047 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1048 WARN("(%p) : Tried to create not supported cube texture\n", This);
1049 return WINED3DERR_INVALIDCALL;
1052 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1053 basetexture_init(&object->baseTexture, Levels, Usage);
1055 TRACE("(%p) Create Cube Texture\n", This);
1057 /* Find the nearest pow2 match */
1059 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1061 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1062 /* Precalculated scaling for 'faked' non power of two texture coords */
1063 object->baseTexture.pow2Matrix[ 0] = 1.0;
1064 object->baseTexture.pow2Matrix[ 5] = 1.0;
1065 object->baseTexture.pow2Matrix[10] = 1.0;
1066 object->baseTexture.pow2Matrix[15] = 1.0;
1068 /* Precalculated scaling for 'faked' non power of two texture coords */
1069 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1070 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1071 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1072 object->baseTexture.pow2Matrix[15] = 1.0;
1075 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1076 object->baseTexture.minMipLookup = minMipLookup;
1077 object->baseTexture.magLookup = magLookup;
1079 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1080 object->baseTexture.magLookup = magLookup_noFilter;
1083 /* Calculate levels for mip mapping */
1084 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1085 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1086 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1087 HeapFree(GetProcessHeap(), 0, object);
1088 *ppCubeTexture = NULL;
1090 return WINED3DERR_INVALIDCALL;
1093 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1094 HeapFree(GetProcessHeap(), 0, object);
1095 *ppCubeTexture = NULL;
1097 return WINED3DERR_INVALIDCALL;
1099 object->baseTexture.levels = 1;
1100 } else if (Levels == 0) {
1101 object->baseTexture.levels = wined3d_log2i(EdgeLength) + 1;
1102 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1105 /* Generate all the surfaces */
1107 for (i = 0; i < object->baseTexture.levels; i++) {
1109 /* Create the 6 faces */
1110 for (j = 0; j < 6; j++) {
1111 static const GLenum cube_targets[6] = {
1112 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1113 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1114 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1115 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1116 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1117 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1120 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1121 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1123 if(hr!= WINED3D_OK) {
1127 for (l = 0; l < j; l++) {
1128 IWineD3DSurface_Release(object->surfaces[l][i]);
1130 for (k = 0; k < i; k++) {
1131 for (l = 0; l < 6; l++) {
1132 IWineD3DSurface_Release(object->surfaces[l][k]);
1136 FIXME("(%p) Failed to create surface\n",object);
1137 HeapFree(GetProcessHeap(),0,object);
1138 *ppCubeTexture = NULL;
1141 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1142 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1143 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1145 tmpW = max(1, tmpW >> 1);
1147 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1149 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1150 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1154 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1156 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1157 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1158 const IWineD3DQueryVtbl *vtable;
1160 /* Just a check to see if we support this type of query */
1162 case WINED3DQUERYTYPE_OCCLUSION:
1163 TRACE("(%p) occlusion query\n", This);
1164 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1167 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1169 vtable = &IWineD3DOcclusionQuery_Vtbl;
1172 case WINED3DQUERYTYPE_EVENT:
1173 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1174 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1175 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1177 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1179 vtable = &IWineD3DEventQuery_Vtbl;
1183 case WINED3DQUERYTYPE_VCACHE:
1184 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1185 case WINED3DQUERYTYPE_VERTEXSTATS:
1186 case WINED3DQUERYTYPE_TIMESTAMP:
1187 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1188 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1189 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1190 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1191 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1192 case WINED3DQUERYTYPE_PIXELTIMINGS:
1193 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1194 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1196 /* Use the base Query vtable until we have a special one for each query */
1197 vtable = &IWineD3DQuery_Vtbl;
1198 FIXME("(%p) Unhandled query type %d\n", This, Type);
1200 if(NULL == ppQuery || hr != WINED3D_OK) {
1204 D3DCREATEOBJECTINSTANCE(object, Query)
1205 object->lpVtbl = vtable;
1206 object->type = Type;
1207 object->state = QUERY_CREATED;
1208 /* allocated the 'extended' data based on the type of query requested */
1210 case WINED3DQUERYTYPE_OCCLUSION:
1211 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1212 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1214 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1215 TRACE("(%p) Allocating data for an occlusion query\n", This);
1217 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1219 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1223 case WINED3DQUERYTYPE_EVENT:
1224 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1225 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1227 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1229 if(GL_SUPPORT(APPLE_FENCE)) {
1230 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1231 checkGLcall("glGenFencesAPPLE");
1232 } else if(GL_SUPPORT(NV_FENCE)) {
1233 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1234 checkGLcall("glGenFencesNV");
1239 case WINED3DQUERYTYPE_VCACHE:
1240 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1241 case WINED3DQUERYTYPE_VERTEXSTATS:
1242 case WINED3DQUERYTYPE_TIMESTAMP:
1243 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1244 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1245 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1246 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1247 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1248 case WINED3DQUERYTYPE_PIXELTIMINGS:
1249 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1250 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1252 object->extendedData = 0;
1253 FIXME("(%p) Unhandled query type %d\n",This , Type);
1255 TRACE("(%p) : Created Query %p\n", This, object);
1259 /*****************************************************************************
1260 * IWineD3DDeviceImpl_SetupFullscreenWindow
1262 * Helper function that modifies a HWND's Style and ExStyle for proper
1266 * iface: Pointer to the IWineD3DDevice interface
1267 * window: Window to setup
1269 *****************************************************************************/
1270 static LONG fullscreen_style(LONG orig_style) {
1271 LONG style = orig_style;
1272 style &= ~WS_CAPTION;
1273 style &= ~WS_THICKFRAME;
1275 /* Make sure the window is managed, otherwise we won't get keyboard input */
1276 style |= WS_POPUP | WS_SYSMENU;
1281 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1282 LONG exStyle = orig_exStyle;
1284 /* Filter out window decorations */
1285 exStyle &= ~WS_EX_WINDOWEDGE;
1286 exStyle &= ~WS_EX_CLIENTEDGE;
1291 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1294 LONG style, exStyle;
1295 /* Don't do anything if an original style is stored.
1296 * That shouldn't happen
1298 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1299 if (This->style || This->exStyle) {
1300 ERR("(%p): Want to change the window parameters of HWND %p, but "
1301 "another style is stored for restoration afterwards\n", This, window);
1304 /* Get the parameters and save them */
1305 style = GetWindowLongW(window, GWL_STYLE);
1306 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1307 This->style = style;
1308 This->exStyle = exStyle;
1310 style = fullscreen_style(style);
1311 exStyle = fullscreen_exStyle(exStyle);
1313 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1314 This->style, This->exStyle, style, exStyle);
1316 SetWindowLongW(window, GWL_STYLE, style);
1317 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1319 /* Inform the window about the update. */
1320 SetWindowPos(window, HWND_TOP, 0, 0,
1321 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1324 /*****************************************************************************
1325 * IWineD3DDeviceImpl_RestoreWindow
1327 * Helper function that restores a windows' properties when taking it out
1328 * of fullscreen mode
1331 * iface: Pointer to the IWineD3DDevice interface
1332 * window: Window to setup
1334 *****************************************************************************/
1335 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1337 LONG style, exStyle;
1339 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1340 * switch, do nothing
1342 if (!This->style && !This->exStyle) return;
1344 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1345 This, window, This->style, This->exStyle);
1347 style = GetWindowLongW(window, GWL_STYLE);
1348 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1350 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1351 * Some applications change it before calling Reset() when switching between windowed and
1352 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1354 if(style == fullscreen_style(This->style) &&
1355 exStyle == fullscreen_style(This->exStyle)) {
1356 SetWindowLongW(window, GWL_STYLE, This->style);
1357 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1360 /* Delete the old values */
1364 /* Inform the window about the update */
1365 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1366 0, 0, 0, 0, /* Pos, Size, ignored */
1367 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1370 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1371 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1372 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1373 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1374 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1379 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1381 IUnknown *bufferParent;
1382 BOOL displaymode_set = FALSE;
1383 WINED3DDISPLAYMODE Mode;
1384 const StaticPixelFormatDesc *formatDesc;
1386 TRACE("(%p) : Created Additional Swap Chain\n", This);
1388 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1389 * does a device hold a reference to a swap chain giving them a lifetime of the device
1390 * or does the swap chain notify the device of its destruction.
1391 *******************************/
1393 /* Check the params */
1394 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1395 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1396 return WINED3DERR_INVALIDCALL;
1397 } else if (pPresentationParameters->BackBufferCount > 1) {
1398 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");
1401 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1402 switch(surface_type) {
1404 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1406 case SURFACE_OPENGL:
1407 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1409 case SURFACE_UNKNOWN:
1410 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1411 return WINED3DERR_INVALIDCALL;
1414 /*********************
1415 * Lookup the window Handle and the relating X window handle
1416 ********************/
1418 /* Setup hwnd we are using, plus which display this equates to */
1419 object->win_handle = pPresentationParameters->hDeviceWindow;
1420 if (!object->win_handle) {
1421 object->win_handle = This->createParms.hFocusWindow;
1423 if(!pPresentationParameters->Windowed && object->win_handle) {
1424 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1425 pPresentationParameters->BackBufferWidth,
1426 pPresentationParameters->BackBufferHeight);
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 (SUCCEEDED(hr)) {
1487 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1488 if(surface_type == SURFACE_OPENGL) {
1489 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1492 ERR("Failed to create the front buffer\n");
1496 /*********************
1497 * Windowed / Fullscreen
1498 *******************/
1501 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1502 * so we should really check to see if there is a fullscreen swapchain already
1503 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1504 **************************************/
1506 if (!pPresentationParameters->Windowed) {
1507 WINED3DDISPLAYMODE mode;
1510 /* Change the display settings */
1511 mode.Width = pPresentationParameters->BackBufferWidth;
1512 mode.Height = pPresentationParameters->BackBufferHeight;
1513 mode.Format = pPresentationParameters->BackBufferFormat;
1514 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1516 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1517 displaymode_set = TRUE;
1521 * Create an opengl context for the display visual
1522 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1523 * use different properties after that point in time. FIXME: How to handle when requested format
1524 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1525 * it chooses is identical to the one already being used!
1526 **********************************/
1527 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1529 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1530 if(!object->context) {
1531 ERR("Failed to create the context array\n");
1535 object->num_contexts = 1;
1537 if(surface_type == SURFACE_OPENGL) {
1538 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1539 if (!object->context[0]) {
1540 ERR("Failed to create a new context\n");
1541 hr = WINED3DERR_NOTAVAILABLE;
1544 TRACE("Context created (HWND=%p, glContext=%p)\n",
1545 object->win_handle, object->context[0]->glCtx);
1549 /*********************
1550 * Create the back, front and stencil buffers
1551 *******************/
1552 if(object->presentParms.BackBufferCount > 0) {
1555 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1556 if(!object->backBuffer) {
1557 ERR("Out of memory\n");
1562 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1563 TRACE("calling rendertarget CB\n");
1564 hr = D3DCB_CreateRenderTarget(This->parent,
1566 object->presentParms.BackBufferWidth,
1567 object->presentParms.BackBufferHeight,
1568 object->presentParms.BackBufferFormat,
1569 object->presentParms.MultiSampleType,
1570 object->presentParms.MultiSampleQuality,
1571 TRUE /* Lockable */,
1572 &object->backBuffer[i],
1573 NULL /* pShared (always null)*/);
1575 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1577 ERR("Cannot create new back buffer\n");
1580 if(surface_type == SURFACE_OPENGL) {
1582 glDrawBuffer(GL_BACK);
1583 checkGLcall("glDrawBuffer(GL_BACK)");
1588 object->backBuffer = NULL;
1590 /* Single buffering - draw to front buffer */
1591 if(surface_type == SURFACE_OPENGL) {
1593 glDrawBuffer(GL_FRONT);
1594 checkGLcall("glDrawBuffer(GL_FRONT)");
1599 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1600 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1601 TRACE("Creating depth stencil buffer\n");
1602 if (This->auto_depth_stencil_buffer == NULL ) {
1603 hr = D3DCB_CreateDepthStencil(This->parent,
1605 object->presentParms.BackBufferWidth,
1606 object->presentParms.BackBufferHeight,
1607 object->presentParms.AutoDepthStencilFormat,
1608 object->presentParms.MultiSampleType,
1609 object->presentParms.MultiSampleQuality,
1610 FALSE /* FIXME: Discard */,
1611 &This->auto_depth_stencil_buffer,
1612 NULL /* pShared (always null)*/ );
1613 if (SUCCEEDED(hr)) {
1614 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1616 ERR("Failed to create the auto depth stencil\n");
1622 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1624 TRACE("Created swapchain %p\n", object);
1625 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1629 if (displaymode_set) {
1633 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1636 /* Change the display settings */
1637 memset(&devmode, 0, sizeof(devmode));
1638 devmode.dmSize = sizeof(devmode);
1639 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1640 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1641 devmode.dmPelsWidth = object->orig_width;
1642 devmode.dmPelsHeight = object->orig_height;
1643 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1646 if (object->backBuffer) {
1648 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1649 if(object->backBuffer[i]) {
1650 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1651 IUnknown_Release(bufferParent); /* once for the get parent */
1652 if (IUnknown_Release(bufferParent) > 0) {
1653 FIXME("(%p) Something's still holding the back buffer\n",This);
1657 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1658 object->backBuffer = NULL;
1660 if(object->context && object->context[0])
1661 DestroyContext(This, object->context[0]);
1662 if(object->frontBuffer) {
1663 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1664 IUnknown_Release(bufferParent); /* once for the get parent */
1665 if (IUnknown_Release(bufferParent) > 0) {
1666 FIXME("(%p) Something's still holding the front buffer\n",This);
1669 HeapFree(GetProcessHeap(), 0, object);
1673 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1674 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1676 TRACE("(%p)\n", This);
1678 return This->NumberOfSwapChains;
1681 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1683 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1685 if(iSwapChain < This->NumberOfSwapChains) {
1686 *pSwapChain = This->swapchains[iSwapChain];
1687 IWineD3DSwapChain_AddRef(*pSwapChain);
1688 TRACE("(%p) returning %p\n", This, *pSwapChain);
1691 TRACE("Swapchain out of range\n");
1693 return WINED3DERR_INVALIDCALL;
1698 * Vertex Declaration
1700 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1701 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1703 IWineD3DVertexDeclarationImpl *object = NULL;
1704 HRESULT hr = WINED3D_OK;
1706 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1707 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1709 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1711 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1713 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1714 *ppVertexDeclaration = NULL;
1720 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1721 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1723 unsigned int idx, idx2;
1724 unsigned int offset;
1725 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1726 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1727 BOOL has_blend_idx = has_blend &&
1728 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1729 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1730 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1731 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1732 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1733 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1734 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1736 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1737 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1739 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1740 WINED3DVERTEXELEMENT *elements = NULL;
1743 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1744 if (has_blend_idx) num_blends--;
1746 /* Compute declaration size */
1747 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1748 has_psize + has_diffuse + has_specular + num_textures + 1;
1750 /* convert the declaration */
1751 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1755 elements[size-1] = end_element;
1758 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1759 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1760 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1762 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1764 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1767 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1768 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1770 elements[idx].UsageIndex = 0;
1773 if (has_blend && (num_blends > 0)) {
1774 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1775 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1777 switch(num_blends) {
1778 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1779 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1780 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1781 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1783 ERR("Unexpected amount of blend values: %u\n", num_blends);
1786 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1787 elements[idx].UsageIndex = 0;
1790 if (has_blend_idx) {
1791 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1792 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1793 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1794 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1795 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1797 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1798 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1799 elements[idx].UsageIndex = 0;
1803 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1804 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1805 elements[idx].UsageIndex = 0;
1809 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1810 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1811 elements[idx].UsageIndex = 0;
1815 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1816 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1817 elements[idx].UsageIndex = 0;
1821 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1822 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1823 elements[idx].UsageIndex = 1;
1826 for (idx2 = 0; idx2 < num_textures; idx2++) {
1827 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1828 switch (numcoords) {
1829 case WINED3DFVF_TEXTUREFORMAT1:
1830 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1832 case WINED3DFVF_TEXTUREFORMAT2:
1833 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1835 case WINED3DFVF_TEXTUREFORMAT3:
1836 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1838 case WINED3DFVF_TEXTUREFORMAT4:
1839 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1842 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1843 elements[idx].UsageIndex = idx2;
1847 /* Now compute offsets, and initialize the rest of the fields */
1848 for (idx = 0, offset = 0; idx < size-1; idx++) {
1849 elements[idx].Stream = 0;
1850 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1851 elements[idx].Offset = offset;
1852 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1855 *ppVertexElements = elements;
1859 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1860 WINED3DVERTEXELEMENT* elements = NULL;
1861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1865 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1866 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1868 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1869 HeapFree(GetProcessHeap(), 0, elements);
1870 if (hr != S_OK) return hr;
1875 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1877 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1878 HRESULT hr = WINED3D_OK;
1880 if (!pFunction) return WINED3DERR_INVALIDCALL;
1882 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1885 ERR("Out of memory\n");
1886 *ppVertexShader = NULL;
1887 return WINED3DERR_OUTOFVIDEOMEMORY;
1890 object->lpVtbl = &IWineD3DVertexShader_Vtbl;
1891 object->parent = parent;
1892 shader_init(&object->baseShader, iface, IWineD3DVertexShaderImpl_shader_ins);
1893 *ppVertexShader = (IWineD3DVertexShader *)object;
1895 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1897 if (vertex_declaration) {
1898 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1901 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1903 if (WINED3D_OK != hr) {
1904 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1905 IWineD3DVertexShader_Release(*ppVertexShader);
1906 return WINED3DERR_INVALIDCALL;
1908 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1913 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1915 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1916 HRESULT hr = WINED3D_OK;
1918 if (!pFunction) return WINED3DERR_INVALIDCALL;
1920 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1923 ERR("Out of memory\n");
1924 *ppPixelShader = NULL;
1925 return WINED3DERR_OUTOFVIDEOMEMORY;
1928 object->lpVtbl = &IWineD3DPixelShader_Vtbl;
1929 object->parent = parent;
1930 shader_init(&object->baseShader, iface, IWineD3DPixelShaderImpl_shader_ins);
1931 *ppPixelShader = (IWineD3DPixelShader *)object;
1933 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1934 if (WINED3D_OK == hr) {
1935 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1936 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1938 WARN("(%p) : Failed to create pixel shader\n", This);
1944 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1945 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1948 IWineD3DPaletteImpl *object;
1950 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1952 /* Create the new object */
1953 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1955 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1956 return E_OUTOFMEMORY;
1959 object->lpVtbl = &IWineD3DPalette_Vtbl;
1961 object->Flags = Flags;
1962 object->parent = Parent;
1963 object->wineD3DDevice = This;
1964 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1965 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1968 HeapFree( GetProcessHeap(), 0, object);
1969 return E_OUTOFMEMORY;
1972 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1974 IWineD3DPalette_Release((IWineD3DPalette *) object);
1978 *Palette = (IWineD3DPalette *) object;
1983 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1987 HDC dcb = NULL, dcs = NULL;
1988 WINEDDCOLORKEY colorkey;
1990 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1993 GetObjectA(hbm, sizeof(BITMAP), &bm);
1994 dcb = CreateCompatibleDC(NULL);
1996 SelectObject(dcb, hbm);
2000 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
2001 * couldn't be loaded
2003 memset(&bm, 0, sizeof(bm));
2008 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2009 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2010 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2012 ERR("Wine logo requested, but failed to create surface\n");
2017 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2018 if(FAILED(hr)) goto out;
2019 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2020 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2022 colorkey.dwColorSpaceLowValue = 0;
2023 colorkey.dwColorSpaceHighValue = 0;
2024 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2026 /* Fill the surface with a white color to show that wined3d is there */
2027 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2040 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2042 /* Under DirectX you can have texture stage operations even if no texture is
2043 bound, whereas opengl will only do texture operations when a valid texture is
2044 bound. We emulate this by creating dummy textures and binding them to each
2045 texture stage, but disable all stages by default. Hence if a stage is enabled
2046 then the default texture will kick in until replaced by a SetTexture call */
2049 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2050 /* The dummy texture does not have client storage backing */
2051 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2052 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2054 for (i = 0; i < GL_LIMITS(textures); i++) {
2055 GLubyte white = 255;
2057 /* Make appropriate texture active */
2058 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2059 checkGLcall("glActiveTextureARB");
2061 /* Generate an opengl texture name */
2062 glGenTextures(1, &This->dummyTextureName[i]);
2063 checkGLcall("glGenTextures");
2064 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2066 /* Generate a dummy 2d texture (not using 1d because they cause many
2067 * DRI drivers fall back to sw) */
2068 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2069 checkGLcall("glBindTexture");
2071 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2072 checkGLcall("glTexImage2D");
2074 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2075 /* Reenable because if supported it is enabled by default */
2076 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2077 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2083 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2085 IWineD3DSwapChainImpl *swapchain = NULL;
2090 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2091 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2092 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2094 /* TODO: Test if OpenGL is compiled in and loaded */
2096 TRACE("(%p) : Creating stateblock\n", This);
2097 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2098 hr = IWineD3DDevice_CreateStateBlock(iface,
2100 (IWineD3DStateBlock **)&This->stateBlock,
2102 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2103 WARN("Failed to create stateblock\n");
2106 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2107 This->updateStateBlock = This->stateBlock;
2108 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2110 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2111 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2113 This->NumberOfPalettes = 1;
2114 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2115 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2116 ERR("Out of memory!\n");
2119 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2120 if(!This->palettes[0]) {
2121 ERR("Out of memory!\n");
2124 for (i = 0; i < 256; ++i) {
2125 This->palettes[0][i].peRed = 0xFF;
2126 This->palettes[0][i].peGreen = 0xFF;
2127 This->palettes[0][i].peBlue = 0xFF;
2128 This->palettes[0][i].peFlags = 0xFF;
2130 This->currentPalette = 0;
2132 /* Initialize the texture unit mapping to a 1:1 mapping */
2133 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2134 if (state < GL_LIMITS(fragment_samplers)) {
2135 This->texUnitMap[state] = state;
2136 This->rev_tex_unit_map[state] = state;
2138 This->texUnitMap[state] = -1;
2139 This->rev_tex_unit_map[state] = -1;
2143 /* Setup the implicit swapchain */
2144 TRACE("Creating implicit swapchain\n");
2145 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2146 if (FAILED(hr) || !swapchain) {
2147 WARN("Failed to create implicit swapchain\n");
2151 This->NumberOfSwapChains = 1;
2152 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2153 if(!This->swapchains) {
2154 ERR("Out of memory!\n");
2157 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2159 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2160 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2161 This->render_targets[0] = swapchain->backBuffer[0];
2162 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2165 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2166 This->render_targets[0] = swapchain->frontBuffer;
2167 This->lastActiveRenderTarget = swapchain->frontBuffer;
2169 IWineD3DSurface_AddRef(This->render_targets[0]);
2170 This->activeContext = swapchain->context[0];
2171 This->lastThread = GetCurrentThreadId();
2173 /* Depth Stencil support */
2174 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2175 if (NULL != This->stencilBufferTarget) {
2176 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2179 hr = This->shader_backend->shader_alloc_private(iface);
2181 TRACE("Shader private data couldn't be allocated\n");
2184 hr = This->frag_pipe->alloc_private(iface);
2186 TRACE("Fragment pipeline private data couldn't be allocated\n");
2189 hr = This->blitter->alloc_private(iface);
2191 TRACE("Blitter private data couldn't be allocated\n");
2195 /* Set up some starting GL setup */
2197 /* Setup all the devices defaults */
2198 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2199 create_dummy_textures(This);
2203 /* Initialize the current view state */
2204 This->view_ident = 1;
2205 This->contexts[0]->last_was_rhw = 0;
2206 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2207 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2209 switch(wined3d_settings.offscreen_rendering_mode) {
2212 This->offscreenBuffer = GL_BACK;
2215 case ORM_BACKBUFFER:
2217 if(This->activeContext->aux_buffers > 0) {
2218 TRACE("Using auxilliary buffer for offscreen rendering\n");
2219 This->offscreenBuffer = GL_AUX0;
2221 TRACE("Using back buffer for offscreen rendering\n");
2222 This->offscreenBuffer = GL_BACK;
2227 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2230 /* Clear the screen */
2231 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2232 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2235 This->d3d_initialized = TRUE;
2237 if(wined3d_settings.logo) {
2238 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2240 This->highest_dirty_ps_const = 0;
2241 This->highest_dirty_vs_const = 0;
2245 HeapFree(GetProcessHeap(), 0, This->render_targets);
2246 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2247 HeapFree(GetProcessHeap(), 0, This->swapchains);
2248 This->NumberOfSwapChains = 0;
2249 if(This->palettes) {
2250 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2251 HeapFree(GetProcessHeap(), 0, This->palettes);
2253 This->NumberOfPalettes = 0;
2255 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2257 if(This->stateBlock) {
2258 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2259 This->stateBlock = NULL;
2261 if (This->blit_priv) {
2262 This->blitter->free_private(iface);
2264 if (This->fragment_priv) {
2265 This->frag_pipe->free_private(iface);
2267 if (This->shader_priv) {
2268 This->shader_backend->shader_free_private(iface);
2273 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2275 IWineD3DSwapChainImpl *swapchain = NULL;
2278 /* Setup the implicit swapchain */
2279 TRACE("Creating implicit swapchain\n");
2280 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2281 if (FAILED(hr) || !swapchain) {
2282 WARN("Failed to create implicit swapchain\n");
2286 This->NumberOfSwapChains = 1;
2287 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2288 if(!This->swapchains) {
2289 ERR("Out of memory!\n");
2292 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2296 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2300 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2304 TRACE("(%p)\n", This);
2306 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2308 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2309 * it was created. Thus make sure a context is active for the glDelete* calls
2311 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2313 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2315 TRACE("Deleting high order patches\n");
2316 for(i = 0; i < PATCHMAP_SIZE; i++) {
2317 struct list *e1, *e2;
2318 struct WineD3DRectPatch *patch;
2319 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2320 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2321 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2325 /* Delete the palette conversion shader if it is around */
2326 if(This->paletteConversionShader) {
2328 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2330 This->paletteConversionShader = 0;
2333 /* Delete the pbuffer context if there is any */
2334 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2336 /* Delete the mouse cursor texture */
2337 if(This->cursorTexture) {
2339 glDeleteTextures(1, &This->cursorTexture);
2341 This->cursorTexture = 0;
2344 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2345 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2347 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2348 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2351 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2352 * private data, it might contain opengl pointers
2354 if(This->depth_blt_texture) {
2355 glDeleteTextures(1, &This->depth_blt_texture);
2356 This->depth_blt_texture = 0;
2358 if (This->depth_blt_rb) {
2359 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2360 This->depth_blt_rb = 0;
2361 This->depth_blt_rb_w = 0;
2362 This->depth_blt_rb_h = 0;
2365 /* Release the update stateblock */
2366 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2367 if(This->updateStateBlock != This->stateBlock)
2368 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2370 This->updateStateBlock = NULL;
2372 { /* because were not doing proper internal refcounts releasing the primary state block
2373 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2374 to set this->stateBlock = NULL; first */
2375 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2376 This->stateBlock = NULL;
2378 /* Release the stateblock */
2379 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2380 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2384 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2385 This->blitter->free_private(iface);
2386 This->frag_pipe->free_private(iface);
2387 This->shader_backend->shader_free_private(iface);
2389 /* Release the buffers (with sanity checks)*/
2390 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2391 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2392 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2393 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2395 This->stencilBufferTarget = NULL;
2397 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2398 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2399 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2401 TRACE("Setting rendertarget to NULL\n");
2402 This->render_targets[0] = NULL;
2404 if (This->auto_depth_stencil_buffer) {
2405 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2406 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2408 This->auto_depth_stencil_buffer = NULL;
2411 for(i=0; i < This->NumberOfSwapChains; i++) {
2412 TRACE("Releasing the implicit swapchain %d\n", i);
2413 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2414 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2418 HeapFree(GetProcessHeap(), 0, This->swapchains);
2419 This->swapchains = NULL;
2420 This->NumberOfSwapChains = 0;
2422 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2423 HeapFree(GetProcessHeap(), 0, This->palettes);
2424 This->palettes = NULL;
2425 This->NumberOfPalettes = 0;
2427 HeapFree(GetProcessHeap(), 0, This->render_targets);
2428 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2429 This->render_targets = NULL;
2430 This->draw_buffers = NULL;
2432 This->d3d_initialized = FALSE;
2436 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2440 for(i=0; i < This->NumberOfSwapChains; i++) {
2441 TRACE("Releasing the implicit swapchain %d\n", i);
2442 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2443 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2447 HeapFree(GetProcessHeap(), 0, This->swapchains);
2448 This->swapchains = NULL;
2449 This->NumberOfSwapChains = 0;
2453 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2454 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2455 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2457 * There is no way to deactivate thread safety once it is enabled.
2459 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2462 /*For now just store the flag(needed in case of ddraw) */
2463 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2468 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2469 const WINED3DDISPLAYMODE* pMode) {
2471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2473 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2476 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2478 /* Resize the screen even without a window:
2479 * The app could have unset it with SetCooperativeLevel, but not called
2480 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2481 * but we don't have any hwnd
2484 memset(&devmode, 0, sizeof(devmode));
2485 devmode.dmSize = sizeof(devmode);
2486 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2487 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2488 devmode.dmPelsWidth = pMode->Width;
2489 devmode.dmPelsHeight = pMode->Height;
2491 devmode.dmDisplayFrequency = pMode->RefreshRate;
2492 if (pMode->RefreshRate != 0) {
2493 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2496 /* Only change the mode if necessary */
2497 if( (This->ddraw_width == pMode->Width) &&
2498 (This->ddraw_height == pMode->Height) &&
2499 (This->ddraw_format == pMode->Format) &&
2500 (pMode->RefreshRate == 0) ) {
2504 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2505 if (ret != DISP_CHANGE_SUCCESSFUL) {
2506 if(devmode.dmDisplayFrequency != 0) {
2507 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2508 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2509 devmode.dmDisplayFrequency = 0;
2510 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2512 if(ret != DISP_CHANGE_SUCCESSFUL) {
2513 return WINED3DERR_NOTAVAILABLE;
2517 /* Store the new values */
2518 This->ddraw_width = pMode->Width;
2519 This->ddraw_height = pMode->Height;
2520 This->ddraw_format = pMode->Format;
2522 /* And finally clip mouse to our screen */
2523 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2524 ClipCursor(&clip_rc);
2529 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2531 *ppD3D= This->wineD3D;
2532 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2533 IWineD3D_AddRef(*ppD3D);
2537 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2541 (This->adapter->TextureRam/(1024*1024)),
2542 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2543 /* return simulated texture memory left */
2544 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2548 * Get / Set Stream Source
2550 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2552 IWineD3DVertexBuffer *oldSrc;
2554 if (StreamNumber >= MAX_STREAMS) {
2555 WARN("Stream out of range %d\n", StreamNumber);
2556 return WINED3DERR_INVALIDCALL;
2557 } else if(OffsetInBytes & 0x3) {
2558 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2559 return WINED3DERR_INVALIDCALL;
2562 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2563 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2565 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2567 if(oldSrc == pStreamData &&
2568 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2569 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2570 TRACE("Application is setting the old values over, nothing to do\n");
2574 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2576 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2577 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2580 /* Handle recording of state blocks */
2581 if (This->isRecordingState) {
2582 TRACE("Recording... not performing anything\n");
2583 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2584 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2588 /* Need to do a getParent and pass the references up */
2589 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2590 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2591 so for now, just count internally */
2592 if (pStreamData != NULL) {
2593 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2594 InterlockedIncrement(&vbImpl->bindCount);
2595 IWineD3DVertexBuffer_AddRef(pStreamData);
2597 if (oldSrc != NULL) {
2598 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2599 IWineD3DVertexBuffer_Release(oldSrc);
2602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2607 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2610 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2611 This->stateBlock->streamSource[StreamNumber],
2612 This->stateBlock->streamOffset[StreamNumber],
2613 This->stateBlock->streamStride[StreamNumber]);
2615 if (StreamNumber >= MAX_STREAMS) {
2616 WARN("Stream out of range %d\n", StreamNumber);
2617 return WINED3DERR_INVALIDCALL;
2619 *pStream = This->stateBlock->streamSource[StreamNumber];
2620 *pStride = This->stateBlock->streamStride[StreamNumber];
2622 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2625 if (*pStream != NULL) {
2626 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2631 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2633 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2634 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2636 /* Verify input at least in d3d9 this is invalid*/
2637 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2638 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2639 return WINED3DERR_INVALIDCALL;
2641 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2642 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2643 return WINED3DERR_INVALIDCALL;
2646 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2647 return WINED3DERR_INVALIDCALL;
2650 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2651 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2653 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2654 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2656 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2657 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2664 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2667 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2668 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2670 TRACE("(%p) : returning %d\n", This, *Divider);
2676 * Get / Set & Multiply Transform
2678 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2681 /* Most of this routine, comments included copied from ddraw tree initially: */
2682 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2684 /* Handle recording of state blocks */
2685 if (This->isRecordingState) {
2686 TRACE("Recording... not performing anything\n");
2687 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2688 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2693 * If the new matrix is the same as the current one,
2694 * we cut off any further processing. this seems to be a reasonable
2695 * optimization because as was noticed, some apps (warcraft3 for example)
2696 * tend towards setting the same matrix repeatedly for some reason.
2698 * From here on we assume that the new matrix is different, wherever it matters.
2700 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2701 TRACE("The app is setting the same matrix over again\n");
2704 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2708 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2709 where ViewMat = Camera space, WorldMat = world space.
2711 In OpenGL, camera and world space is combined into GL_MODELVIEW
2712 matrix. The Projection matrix stay projection matrix.
2715 /* Capture the times we can just ignore the change for now */
2716 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2717 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2718 /* Handled by the state manager */
2721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2725 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2728 *pMatrix = This->stateBlock->transforms[State];
2732 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2733 const WINED3DMATRIX *mat = NULL;
2736 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2737 * below means it will be recorded in a state block change, but it
2738 * works regardless where it is recorded.
2739 * If this is found to be wrong, change to StateBlock.
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2742 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2744 if (State <= HIGHEST_TRANSFORMSTATE)
2746 mat = &This->updateStateBlock->transforms[State];
2748 FIXME("Unhandled transform state!!\n");
2751 multiply_matrix(&temp, mat, pMatrix);
2753 /* Apply change via set transform - will reapply to eg. lights this way */
2754 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2760 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2761 you can reference any indexes you want as long as that number max are enabled at any
2762 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2763 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2764 but when recording, just build a chain pretty much of commands to be replayed. */
2766 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2768 PLIGHTINFOEL *object = NULL;
2769 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2775 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2779 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2780 return WINED3DERR_INVALIDCALL;
2783 switch(pLight->Type) {
2784 case WINED3DLIGHT_POINT:
2785 case WINED3DLIGHT_SPOT:
2786 case WINED3DLIGHT_PARALLELPOINT:
2787 case WINED3DLIGHT_GLSPOT:
2788 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2791 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2792 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2793 return WINED3DERR_INVALIDCALL;
2797 case WINED3DLIGHT_DIRECTIONAL:
2798 /* Ignores attenuation */
2802 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2803 return WINED3DERR_INVALIDCALL;
2806 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2807 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2808 if(object->OriginalIndex == Index) break;
2813 TRACE("Adding new light\n");
2814 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2816 ERR("Out of memory error when allocating a light\n");
2817 return E_OUTOFMEMORY;
2819 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2820 object->glIndex = -1;
2821 object->OriginalIndex = Index;
2822 object->changed = TRUE;
2825 /* Initialize the object */
2826 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,
2827 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2828 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2829 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2830 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2831 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2832 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2834 /* Save away the information */
2835 object->OriginalParms = *pLight;
2837 switch (pLight->Type) {
2838 case WINED3DLIGHT_POINT:
2840 object->lightPosn[0] = pLight->Position.x;
2841 object->lightPosn[1] = pLight->Position.y;
2842 object->lightPosn[2] = pLight->Position.z;
2843 object->lightPosn[3] = 1.0f;
2844 object->cutoff = 180.0f;
2848 case WINED3DLIGHT_DIRECTIONAL:
2850 object->lightPosn[0] = -pLight->Direction.x;
2851 object->lightPosn[1] = -pLight->Direction.y;
2852 object->lightPosn[2] = -pLight->Direction.z;
2853 object->lightPosn[3] = 0.0;
2854 object->exponent = 0.0f;
2855 object->cutoff = 180.0f;
2858 case WINED3DLIGHT_SPOT:
2860 object->lightPosn[0] = pLight->Position.x;
2861 object->lightPosn[1] = pLight->Position.y;
2862 object->lightPosn[2] = pLight->Position.z;
2863 object->lightPosn[3] = 1.0;
2866 object->lightDirn[0] = pLight->Direction.x;
2867 object->lightDirn[1] = pLight->Direction.y;
2868 object->lightDirn[2] = pLight->Direction.z;
2869 object->lightDirn[3] = 1.0;
2872 * opengl-ish and d3d-ish spot lights use too different models for the
2873 * light "intensity" as a function of the angle towards the main light direction,
2874 * so we only can approximate very roughly.
2875 * however spot lights are rather rarely used in games (if ever used at all).
2876 * furthermore if still used, probably nobody pays attention to such details.
2878 if (pLight->Falloff == 0) {
2879 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2880 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2881 * will always be 1.0 for both of them, and we don't have to care for the
2882 * rest of the rather complex calculation
2884 object->exponent = 0;
2886 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2887 if (rho < 0.0001) rho = 0.0001f;
2888 object->exponent = -0.3/log(cos(rho/2));
2890 if (object->exponent > 128.0) {
2891 object->exponent = 128.0;
2893 object->cutoff = pLight->Phi*90/M_PI;
2899 FIXME("Unrecognized light type %d\n", pLight->Type);
2902 /* Update the live definitions if the light is currently assigned a glIndex */
2903 if (object->glIndex != -1 && !This->isRecordingState) {
2904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2909 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2910 PLIGHTINFOEL *lightInfo = NULL;
2911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2914 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2916 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2917 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2918 if(lightInfo->OriginalIndex == Index) break;
2922 if (lightInfo == NULL) {
2923 TRACE("Light information requested but light not defined\n");
2924 return WINED3DERR_INVALIDCALL;
2927 *pLight = lightInfo->OriginalParms;
2932 * Get / Set Light Enable
2933 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2935 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2936 PLIGHTINFOEL *lightInfo = NULL;
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2938 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2940 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2942 /* Tests show true = 128...not clear why */
2943 Enable = Enable? 128: 0;
2945 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2946 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2947 if(lightInfo->OriginalIndex == Index) break;
2950 TRACE("Found light: %p\n", lightInfo);
2952 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2953 if (lightInfo == NULL) {
2955 TRACE("Light enabled requested but light not defined, so defining one!\n");
2956 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2958 /* Search for it again! Should be fairly quick as near head of list */
2959 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2960 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2961 if(lightInfo->OriginalIndex == Index) break;
2964 if (lightInfo == NULL) {
2965 FIXME("Adding default lights has failed dismally\n");
2966 return WINED3DERR_INVALIDCALL;
2970 lightInfo->enabledChanged = TRUE;
2972 if(lightInfo->glIndex != -1) {
2973 if(!This->isRecordingState) {
2974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2977 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2978 lightInfo->glIndex = -1;
2980 TRACE("Light already disabled, nothing to do\n");
2982 lightInfo->enabled = FALSE;
2984 lightInfo->enabled = TRUE;
2985 if (lightInfo->glIndex != -1) {
2987 TRACE("Nothing to do as light was enabled\n");
2990 /* Find a free gl light */
2991 for(i = 0; i < This->maxConcurrentLights; i++) {
2992 if(This->updateStateBlock->activeLights[i] == NULL) {
2993 This->updateStateBlock->activeLights[i] = lightInfo;
2994 lightInfo->glIndex = i;
2998 if(lightInfo->glIndex == -1) {
2999 /* Our tests show that Windows returns D3D_OK in this situation, even with
3000 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3001 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3002 * as well for those lights.
3004 * TODO: Test how this affects rendering
3006 WARN("Too many concurrently active lights\n");
3010 /* i == lightInfo->glIndex */
3011 if(!This->isRecordingState) {
3012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3020 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3022 PLIGHTINFOEL *lightInfo = NULL;
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3025 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3026 TRACE("(%p) : for idx(%d)\n", This, Index);
3028 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3029 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3030 if(lightInfo->OriginalIndex == Index) break;
3034 if (lightInfo == NULL) {
3035 TRACE("Light enabled state requested but light not defined\n");
3036 return WINED3DERR_INVALIDCALL;
3038 /* true is 128 according to SetLightEnable */
3039 *pEnable = lightInfo->enabled ? 128 : 0;
3044 * Get / Set Clip Planes
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3048 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3050 /* Validate Index */
3051 if (Index >= GL_LIMITS(clipplanes)) {
3052 TRACE("Application has requested clipplane this device doesn't support\n");
3053 return WINED3DERR_INVALIDCALL;
3056 This->updateStateBlock->changed.clipplane |= 1 << Index;
3058 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3059 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3060 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3061 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3062 TRACE("Application is setting old values over, nothing to do\n");
3066 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3067 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3068 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3069 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3071 /* Handle recording of state blocks */
3072 if (This->isRecordingState) {
3073 TRACE("Recording... not performing anything\n");
3077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3082 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 TRACE("(%p) : for idx %d\n", This, Index);
3086 /* Validate Index */
3087 if (Index >= GL_LIMITS(clipplanes)) {
3088 TRACE("Application has requested clipplane this device doesn't support\n");
3089 return WINED3DERR_INVALIDCALL;
3092 pPlane[0] = This->stateBlock->clipplane[Index][0];
3093 pPlane[1] = This->stateBlock->clipplane[Index][1];
3094 pPlane[2] = This->stateBlock->clipplane[Index][2];
3095 pPlane[3] = This->stateBlock->clipplane[Index][3];
3100 * Get / Set Clip Plane Status
3101 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3103 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 FIXME("(%p) : stub\n", This);
3106 if (NULL == pClipStatus) {
3107 return WINED3DERR_INVALIDCALL;
3109 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3110 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3114 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3116 FIXME("(%p) : stub\n", This);
3117 if (NULL == pClipStatus) {
3118 return WINED3DERR_INVALIDCALL;
3120 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3121 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3126 * Get / Set Material
3128 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 This->updateStateBlock->changed.material = TRUE;
3132 This->updateStateBlock->material = *pMaterial;
3134 /* Handle recording of state blocks */
3135 if (This->isRecordingState) {
3136 TRACE("Recording... not performing anything\n");
3140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3144 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 *pMaterial = This->updateStateBlock->material;
3147 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3148 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3149 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3150 pMaterial->Ambient.b, pMaterial->Ambient.a);
3151 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3152 pMaterial->Specular.b, pMaterial->Specular.a);
3153 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3154 pMaterial->Emissive.b, pMaterial->Emissive.a);
3155 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3163 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3165 IWineD3DIndexBuffer *oldIdxs;
3167 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3168 oldIdxs = This->updateStateBlock->pIndexData;
3170 This->updateStateBlock->changed.indices = TRUE;
3171 This->updateStateBlock->pIndexData = pIndexData;
3173 /* Handle recording of state blocks */
3174 if (This->isRecordingState) {
3175 TRACE("Recording... not performing anything\n");
3176 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3177 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3181 if(oldIdxs != pIndexData) {
3182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3183 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3184 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3189 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 *ppIndexData = This->stateBlock->pIndexData;
3194 /* up ref count on ppindexdata */
3196 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3197 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3199 TRACE("(%p) No index data set\n", This);
3201 TRACE("Returning %p\n", *ppIndexData);
3206 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3207 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 TRACE("(%p)->(%d)\n", This, BaseIndex);
3211 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3212 TRACE("Application is setting the old value over, nothing to do\n");
3216 This->updateStateBlock->baseVertexIndex = BaseIndex;
3218 if (This->isRecordingState) {
3219 TRACE("Recording... not performing anything\n");
3222 /* The base vertex index affects the stream sources */
3223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3227 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p) : base_index %p\n", This, base_index);
3231 *base_index = This->stateBlock->baseVertexIndex;
3233 TRACE("Returning %u\n", *base_index);
3239 * Get / Set Viewports
3241 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3244 TRACE("(%p)\n", This);
3245 This->updateStateBlock->changed.viewport = TRUE;
3246 This->updateStateBlock->viewport = *pViewport;
3248 /* Handle recording of state blocks */
3249 if (This->isRecordingState) {
3250 TRACE("Recording... not performing anything\n");
3254 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3255 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3262 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3264 TRACE("(%p)\n", This);
3265 *pViewport = This->stateBlock->viewport;
3270 * Get / Set Render States
3271 * TODO: Verify against dx9 definitions
3273 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 DWORD oldValue = This->stateBlock->renderState[State];
3278 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3280 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3281 This->updateStateBlock->renderState[State] = Value;
3283 /* Handle recording of state blocks */
3284 if (This->isRecordingState) {
3285 TRACE("Recording... not performing anything\n");
3289 /* Compared here and not before the assignment to allow proper stateblock recording */
3290 if(Value == oldValue) {
3291 TRACE("Application is setting the old value over, nothing to do\n");
3293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3299 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3302 *pValue = This->stateBlock->renderState[State];
3307 * Get / Set Sampler States
3308 * TODO: Verify against dx9 definitions
3311 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3315 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3316 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3318 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3319 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3322 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3323 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3324 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3327 * SetSampler is designed to allow for more than the standard up to 8 textures
3328 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3329 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3331 * http://developer.nvidia.com/object/General_FAQ.html#t6
3333 * There are two new settings for GForce
3335 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3336 * and the texture one:
3337 * GL_MAX_TEXTURE_COORDS_ARB.
3338 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3341 oldValue = This->stateBlock->samplerState[Sampler][Type];
3342 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3343 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3345 /* Handle recording of state blocks */
3346 if (This->isRecordingState) {
3347 TRACE("Recording... not performing anything\n");
3351 if(oldValue == Value) {
3352 TRACE("Application is setting the old value over, nothing to do\n");
3356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3365 This, Sampler, debug_d3dsamplerstate(Type), Type);
3367 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3368 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3371 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3372 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3373 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3375 *Value = This->stateBlock->samplerState[Sampler][Type];
3376 TRACE("(%p) : Returning %#x\n", This, *Value);
3381 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3384 This->updateStateBlock->changed.scissorRect = TRUE;
3385 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3386 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3389 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3391 if(This->isRecordingState) {
3392 TRACE("Recording... not performing anything\n");
3396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3401 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3404 *pRect = This->updateStateBlock->scissorRect;
3405 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3409 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3411 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3413 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3415 This->updateStateBlock->vertexDecl = pDecl;
3416 This->updateStateBlock->changed.vertexDecl = TRUE;
3418 if (This->isRecordingState) {
3419 TRACE("Recording... not performing anything\n");
3421 } else if(pDecl == oldDecl) {
3422 /* Checked after the assignment to allow proper stateblock recording */
3423 TRACE("Application is setting the old declaration over, nothing to do\n");
3427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3431 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3434 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3436 *ppDecl = This->stateBlock->vertexDecl;
3437 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3441 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3443 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3445 This->updateStateBlock->vertexShader = pShader;
3446 This->updateStateBlock->changed.vertexShader = TRUE;
3448 if (This->isRecordingState) {
3449 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3450 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3451 TRACE("Recording... not performing anything\n");
3453 } else if(oldShader == pShader) {
3454 /* Checked here to allow proper stateblock recording */
3455 TRACE("App is setting the old shader over, nothing to do\n");
3459 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3460 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3461 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3468 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3471 if (NULL == ppShader) {
3472 return WINED3DERR_INVALIDCALL;
3474 *ppShader = This->stateBlock->vertexShader;
3475 if( NULL != *ppShader)
3476 IWineD3DVertexShader_AddRef(*ppShader);
3478 TRACE("(%p) : returning %p\n", This, *ppShader);
3482 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3483 IWineD3DDevice *iface,
3485 CONST BOOL *srcData,
3488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3489 int i, cnt = min(count, MAX_CONST_B - start);
3491 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3492 iface, srcData, start, count);
3494 if (srcData == NULL || cnt < 0)
3495 return WINED3DERR_INVALIDCALL;
3497 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3498 for (i = 0; i < cnt; i++)
3499 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3501 for (i = start; i < cnt + start; ++i) {
3502 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3505 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3510 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3511 IWineD3DDevice *iface,
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 int cnt = min(count, MAX_CONST_B - start);
3519 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3520 iface, dstData, start, count);
3522 if (dstData == NULL || cnt < 0)
3523 return WINED3DERR_INVALIDCALL;
3525 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3529 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3530 IWineD3DDevice *iface,
3535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3536 int i, cnt = min(count, MAX_CONST_I - start);
3538 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3539 iface, srcData, start, count);
3541 if (srcData == NULL || cnt < 0)
3542 return WINED3DERR_INVALIDCALL;
3544 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3545 for (i = 0; i < cnt; i++)
3546 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3547 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3549 for (i = start; i < cnt + start; ++i) {
3550 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3553 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3558 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3559 IWineD3DDevice *iface,
3564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3565 int cnt = min(count, MAX_CONST_I - start);
3567 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3568 iface, dstData, start, count);
3570 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3571 return WINED3DERR_INVALIDCALL;
3573 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3577 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3578 IWineD3DDevice *iface,
3580 CONST float *srcData,
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3586 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3587 iface, srcData, start, count);
3589 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3590 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3591 return WINED3DERR_INVALIDCALL;
3593 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3595 for (i = 0; i < count; i++)
3596 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3597 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3600 if (!This->isRecordingState)
3602 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3606 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3607 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3612 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3613 IWineD3DDevice *iface,
3618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3619 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3621 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3622 iface, dstData, start, count);
3624 if (dstData == NULL || cnt < 0)
3625 return WINED3DERR_INVALIDCALL;
3627 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3631 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3633 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3639 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3640 int i = This->rev_tex_unit_map[unit];
3641 int j = This->texUnitMap[stage];
3643 This->texUnitMap[stage] = unit;
3644 if (i != -1 && i != stage) {
3645 This->texUnitMap[i] = -1;
3648 This->rev_tex_unit_map[unit] = stage;
3649 if (j != -1 && j != unit) {
3650 This->rev_tex_unit_map[j] = -1;
3654 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3657 This->fixed_function_usage_map = 0;
3658 for (i = 0; i < MAX_TEXTURES; ++i) {
3659 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3660 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3661 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3662 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3663 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3664 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3665 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3666 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3668 if (color_op == WINED3DTOP_DISABLE) {
3669 /* Not used, and disable higher stages */
3673 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3674 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3675 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3676 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3677 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3678 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3679 This->fixed_function_usage_map |= (1 << i);
3682 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3683 This->fixed_function_usage_map |= (1 << (i + 1));
3688 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3692 device_update_fixed_function_usage_map(This);
3693 ffu_map = This->fixed_function_usage_map;
3695 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3696 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3697 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3699 if (!(ffu_map & 1)) continue;
3701 if (This->texUnitMap[i] != i) {
3702 device_map_stage(This, i, i);
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3704 markTextureStagesDirty(This, i);
3710 /* Now work out the mapping */
3712 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3714 if (!(ffu_map & 1)) continue;
3716 if (This->texUnitMap[i] != tex) {
3717 device_map_stage(This, i, tex);
3718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3719 markTextureStagesDirty(This, i);
3726 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3727 const DWORD *sampler_tokens =
3728 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3731 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3732 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3733 device_map_stage(This, i, i);
3734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3735 if (i < MAX_TEXTURES) {
3736 markTextureStagesDirty(This, i);
3742 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3743 const DWORD *vshader_sampler_tokens, int unit)
3745 int current_mapping = This->rev_tex_unit_map[unit];
3747 if (current_mapping == -1) {
3748 /* Not currently used */
3752 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3753 /* Used by a fragment sampler */
3755 if (!pshader_sampler_tokens) {
3756 /* No pixel shader, check fixed function */
3757 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3760 /* Pixel shader, check the shader's sampler map */
3761 return !pshader_sampler_tokens[current_mapping];
3764 /* Used by a vertex sampler */
3765 return !vshader_sampler_tokens[current_mapping];
3768 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3769 const DWORD *vshader_sampler_tokens =
3770 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3771 const DWORD *pshader_sampler_tokens = NULL;
3772 int start = GL_LIMITS(combined_samplers) - 1;
3776 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3778 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3779 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3780 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3783 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3784 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3785 if (vshader_sampler_tokens[i]) {
3786 if (This->texUnitMap[vsampler_idx] != -1) {
3787 /* Already mapped somewhere */
3791 while (start >= 0) {
3792 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3793 device_map_stage(This, vsampler_idx, start);
3794 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3806 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3807 BOOL vs = use_vs(This->stateBlock);
3808 BOOL ps = use_ps(This->stateBlock);
3811 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3812 * that would be really messy and require shader recompilation
3813 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3814 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3817 device_map_psamplers(This);
3819 device_map_fixed_function_samplers(This);
3823 device_map_vsamplers(This, ps);
3827 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3829 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3830 This->updateStateBlock->pixelShader = pShader;
3831 This->updateStateBlock->changed.pixelShader = TRUE;
3833 /* Handle recording of state blocks */
3834 if (This->isRecordingState) {
3835 TRACE("Recording... not performing anything\n");
3838 if (This->isRecordingState) {
3839 TRACE("Recording... not performing anything\n");
3840 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3841 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3845 if(pShader == oldShader) {
3846 TRACE("App is setting the old pixel shader over, nothing to do\n");
3850 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3851 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3853 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3859 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3862 if (NULL == ppShader) {
3863 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3864 return WINED3DERR_INVALIDCALL;
3867 *ppShader = This->stateBlock->pixelShader;
3868 if (NULL != *ppShader) {
3869 IWineD3DPixelShader_AddRef(*ppShader);
3871 TRACE("(%p) : returning %p\n", This, *ppShader);
3875 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3876 IWineD3DDevice *iface,
3878 CONST BOOL *srcData,
3881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3882 int i, cnt = min(count, MAX_CONST_B - start);
3884 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3885 iface, srcData, start, count);
3887 if (srcData == NULL || cnt < 0)
3888 return WINED3DERR_INVALIDCALL;
3890 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3891 for (i = 0; i < cnt; i++)
3892 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3894 for (i = start; i < cnt + start; ++i) {
3895 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3898 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3903 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3904 IWineD3DDevice *iface,
3909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3910 int cnt = min(count, MAX_CONST_B - start);
3912 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3913 iface, dstData, start, count);
3915 if (dstData == NULL || cnt < 0)
3916 return WINED3DERR_INVALIDCALL;
3918 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3922 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3923 IWineD3DDevice *iface,
3928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3929 int i, cnt = min(count, MAX_CONST_I - start);
3931 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3932 iface, srcData, start, count);
3934 if (srcData == NULL || cnt < 0)
3935 return WINED3DERR_INVALIDCALL;
3937 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3938 for (i = 0; i < cnt; i++)
3939 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3940 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3942 for (i = start; i < cnt + start; ++i) {
3943 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3946 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3951 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3952 IWineD3DDevice *iface,
3957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3958 int cnt = min(count, MAX_CONST_I - start);
3960 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3961 iface, dstData, start, count);
3963 if (dstData == NULL || cnt < 0)
3964 return WINED3DERR_INVALIDCALL;
3966 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3970 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3971 IWineD3DDevice *iface,
3973 CONST float *srcData,
3976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3979 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3980 iface, srcData, start, count);
3982 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3983 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3984 return WINED3DERR_INVALIDCALL;
3986 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3988 for (i = 0; i < count; i++)
3989 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3990 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3993 if (!This->isRecordingState)
3995 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3999 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
4000 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
4005 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4006 IWineD3DDevice *iface,
4011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4012 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4014 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4015 iface, dstData, start, count);
4017 if (dstData == NULL || cnt < 0)
4018 return WINED3DERR_INVALIDCALL;
4020 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4024 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4025 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4026 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4028 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4030 DWORD DestFVF = dest->fvf;
4032 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4036 if (lpStrideData->u.s.normal.lpData) {
4037 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4040 if (lpStrideData->u.s.position.lpData == NULL) {
4041 ERR("Source has no position mask\n");
4042 return WINED3DERR_INVALIDCALL;
4045 /* We might access VBOs from this code, so hold the lock */
4048 if (dest->resource.allocatedMemory == NULL) {
4049 /* This may happen if we do direct locking into a vbo. Unlikely,
4050 * but theoretically possible(ddraw processvertices test)
4052 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4053 if(!dest->resource.allocatedMemory) {
4055 ERR("Out of memory\n");
4056 return E_OUTOFMEMORY;
4060 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4061 checkGLcall("glBindBufferARB");
4062 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4064 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4066 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4067 checkGLcall("glUnmapBufferARB");
4071 /* Get a pointer into the destination vbo(create one if none exists) and
4072 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4074 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4075 dest->Flags |= VBFLAG_CREATEVBO;
4076 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4080 unsigned char extrabytes = 0;
4081 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4082 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4083 * this may write 4 extra bytes beyond the area that should be written
4085 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4086 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4087 if(!dest_conv_addr) {
4088 ERR("Out of memory\n");
4089 /* Continue without storing converted vertices */
4091 dest_conv = dest_conv_addr;
4095 * a) WINED3DRS_CLIPPING is enabled
4096 * b) WINED3DVOP_CLIP is passed
4098 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4099 static BOOL warned = FALSE;
4101 * The clipping code is not quite correct. Some things need
4102 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4103 * so disable clipping for now.
4104 * (The graphics in Half-Life are broken, and my processvertices
4105 * test crashes with IDirect3DDevice3)
4111 FIXME("Clipping is broken and disabled for now\n");
4113 } else doClip = FALSE;
4114 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4116 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4119 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4120 WINED3DTS_PROJECTION,
4122 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4123 WINED3DTS_WORLDMATRIX(0),
4126 TRACE("View mat:\n");
4127 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);
4128 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);
4129 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);
4130 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);
4132 TRACE("Proj mat:\n");
4133 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);
4134 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);
4135 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);
4136 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);
4138 TRACE("World mat:\n");
4139 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);
4140 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);
4141 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);
4142 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);
4144 /* Get the viewport */
4145 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4146 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4147 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4149 multiply_matrix(&mat,&view_mat,&world_mat);
4150 multiply_matrix(&mat,&proj_mat,&mat);
4152 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4154 for (i = 0; i < dwCount; i+= 1) {
4155 unsigned int tex_index;
4157 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4158 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4159 /* The position first */
4161 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4163 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4165 /* Multiplication with world, view and projection matrix */
4166 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);
4167 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);
4168 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);
4169 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);
4171 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4173 /* WARNING: The following things are taken from d3d7 and were not yet checked
4174 * against d3d8 or d3d9!
4177 /* Clipping conditions: From msdn
4179 * A vertex is clipped if it does not match the following requirements
4183 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4185 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4186 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4191 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4192 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4195 /* "Normal" viewport transformation (not clipped)
4196 * 1) The values are divided by rhw
4197 * 2) The y axis is negative, so multiply it with -1
4198 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4199 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4200 * 4) Multiply x with Width/2 and add Width/2
4201 * 5) The same for the height
4202 * 6) Add the viewpoint X and Y to the 2D coordinates and
4203 * The minimum Z value to z
4204 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4206 * Well, basically it's simply a linear transformation into viewport
4218 z *= vp.MaxZ - vp.MinZ;
4220 x += vp.Width / 2 + vp.X;
4221 y += vp.Height / 2 + vp.Y;
4226 /* That vertex got clipped
4227 * Contrary to OpenGL it is not dropped completely, it just
4228 * undergoes a different calculation.
4230 TRACE("Vertex got clipped\n");
4237 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4238 * outside of the main vertex buffer memory. That needs some more
4243 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4246 ( (float *) dest_ptr)[0] = x;
4247 ( (float *) dest_ptr)[1] = y;
4248 ( (float *) dest_ptr)[2] = z;
4249 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4251 dest_ptr += 3 * sizeof(float);
4253 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4254 dest_ptr += sizeof(float);
4259 ( (float *) dest_conv)[0] = x * w;
4260 ( (float *) dest_conv)[1] = y * w;
4261 ( (float *) dest_conv)[2] = z * w;
4262 ( (float *) dest_conv)[3] = w;
4264 dest_conv += 3 * sizeof(float);
4266 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4267 dest_conv += sizeof(float);
4271 if (DestFVF & WINED3DFVF_PSIZE) {
4272 dest_ptr += sizeof(DWORD);
4273 if(dest_conv) dest_conv += sizeof(DWORD);
4275 if (DestFVF & WINED3DFVF_NORMAL) {
4276 const float *normal =
4277 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4278 /* AFAIK this should go into the lighting information */
4279 FIXME("Didn't expect the destination to have a normal\n");
4280 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4282 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4286 if (DestFVF & WINED3DFVF_DIFFUSE) {
4287 const DWORD *color_d =
4288 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4290 static BOOL warned = FALSE;
4293 ERR("No diffuse color in source, but destination has one\n");
4297 *( (DWORD *) dest_ptr) = 0xffffffff;
4298 dest_ptr += sizeof(DWORD);
4301 *( (DWORD *) dest_conv) = 0xffffffff;
4302 dest_conv += sizeof(DWORD);
4306 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4308 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4309 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4310 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4311 dest_conv += sizeof(DWORD);
4316 if (DestFVF & WINED3DFVF_SPECULAR) {
4317 /* What's the color value in the feedback buffer? */
4318 const DWORD *color_s =
4319 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4321 static BOOL warned = FALSE;
4324 ERR("No specular color in source, but destination has one\n");
4328 *( (DWORD *) dest_ptr) = 0xFF000000;
4329 dest_ptr += sizeof(DWORD);
4332 *( (DWORD *) dest_conv) = 0xFF000000;
4333 dest_conv += sizeof(DWORD);
4337 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4339 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4340 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4341 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4342 dest_conv += sizeof(DWORD);
4347 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4348 const float *tex_coord =
4349 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4350 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4352 ERR("No source texture, but destination requests one\n");
4353 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4354 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4357 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4359 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4366 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4367 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4368 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4369 dwCount * get_flexible_vertex_size(DestFVF),
4371 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4372 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4379 #undef copy_and_next
4381 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 WineDirect3DVertexStridedData strided;
4384 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4385 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4388 ERR("Output vertex declaration not implemented yet\n");
4391 /* Need any context to write to the vbo. */
4392 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4394 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4395 * control the streamIsUP flag, thus restore it afterwards.
4397 This->stateBlock->streamIsUP = FALSE;
4398 memset(&strided, 0, sizeof(strided));
4399 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4400 This->stateBlock->streamIsUP = streamWasUP;
4402 if(vbo || SrcStartIndex) {
4404 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4405 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4407 * Also get the start index in, but only loop over all elements if there's something to add at all.
4409 #define FIXSRC(type) \
4410 if(strided.u.s.type.VBO) { \
4411 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4412 strided.u.s.type.VBO = 0; \
4413 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4415 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4419 if(strided.u.s.type.lpData) { \
4420 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4423 FIXSRC(blendWeights);
4424 FIXSRC(blendMatrixIndices);
4429 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4430 FIXSRC(texCoords[i]);
4443 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4447 * Get / Set Texture Stage States
4448 * TODO: Verify against dx9 definitions
4450 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4452 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4454 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4456 if (Stage >= MAX_TEXTURES) {
4457 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4461 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4462 This->updateStateBlock->textureState[Stage][Type] = Value;
4464 if (This->isRecordingState) {
4465 TRACE("Recording... not performing anything\n");
4469 /* Checked after the assignments to allow proper stateblock recording */
4470 if(oldValue == Value) {
4471 TRACE("App is setting the old value over, nothing to do\n");
4475 if(Stage > This->stateBlock->lowest_disabled_stage &&
4476 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4477 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4478 * Changes in other states are important on disabled stages too
4483 if(Type == WINED3DTSS_COLOROP) {
4486 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4487 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4488 * they have to be disabled
4490 * The current stage is dirtified below.
4492 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4493 TRACE("Additionally dirtifying stage %d\n", i);
4494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4496 This->stateBlock->lowest_disabled_stage = Stage;
4497 TRACE("New lowest disabled: %d\n", Stage);
4498 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4499 /* Previously disabled stage enabled. Stages above it may need enabling
4500 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4501 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4503 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4506 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4507 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4510 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4513 This->stateBlock->lowest_disabled_stage = i;
4514 TRACE("New lowest disabled: %d\n", i);
4518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4523 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4526 *pValue = This->updateStateBlock->textureState[Stage][Type];
4533 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4535 IWineD3DBaseTexture *oldTexture;
4537 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4539 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4540 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4543 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4544 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4545 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4548 oldTexture = This->updateStateBlock->textures[Stage];
4550 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4551 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4553 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4554 return WINED3DERR_INVALIDCALL;
4557 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4558 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4560 This->updateStateBlock->changed.textures |= 1 << Stage;
4561 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4562 This->updateStateBlock->textures[Stage] = pTexture;
4564 /* Handle recording of state blocks */
4565 if (This->isRecordingState) {
4566 TRACE("Recording... not performing anything\n");
4570 if(oldTexture == pTexture) {
4571 TRACE("App is setting the same texture again, nothing to do\n");
4575 /** NOTE: MSDN says that setTexture increases the reference count,
4576 * and that the application must set the texture back to null (or have a leaky application),
4577 * This means we should pass the refcount up to the parent
4578 *******************************/
4579 if (NULL != This->updateStateBlock->textures[Stage]) {
4580 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4581 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4582 UINT dimensions = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4584 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4586 if (!oldTexture || dimensions != IWineD3DBaseTexture_GetTextureDimensions(oldTexture))
4588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
4591 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4592 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4593 * so the COLOROP and ALPHAOP have to be dirtified.
4595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4598 if(bindCount == 1) {
4599 new->baseTexture.sampler = Stage;
4601 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4605 if (NULL != oldTexture) {
4606 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4607 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4609 IWineD3DBaseTexture_Release(oldTexture);
4610 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4615 if(bindCount && old->baseTexture.sampler == Stage) {
4617 /* Have to do a search for the other sampler(s) where the texture is bound to
4618 * Shouldn't happen as long as apps bind a texture only to one stage
4620 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4621 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4622 if(This->updateStateBlock->textures[i] == oldTexture) {
4623 old->baseTexture.sampler = i;
4630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4635 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4640 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4641 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4644 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4645 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4646 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4649 *ppTexture=This->stateBlock->textures[Stage];
4651 IWineD3DBaseTexture_AddRef(*ppTexture);
4653 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4661 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4662 IWineD3DSurface **ppBackBuffer) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 IWineD3DSwapChain *swapChain;
4667 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4669 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4670 if (hr == WINED3D_OK) {
4671 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4672 IWineD3DSwapChain_Release(swapChain);
4674 *ppBackBuffer = NULL;
4679 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4681 WARN("(%p) : stub, calling idirect3d for now\n", This);
4682 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4685 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4687 IWineD3DSwapChain *swapChain;
4690 if(iSwapChain > 0) {
4691 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4692 if (hr == WINED3D_OK) {
4693 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4694 IWineD3DSwapChain_Release(swapChain);
4696 FIXME("(%p) Error getting display mode\n", This);
4699 /* Don't read the real display mode,
4700 but return the stored mode instead. X11 can't change the color
4701 depth, and some apps are pretty angry if they SetDisplayMode from
4702 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4704 Also don't relay to the swapchain because with ddraw it's possible
4705 that there isn't a swapchain at all */
4706 pMode->Width = This->ddraw_width;
4707 pMode->Height = This->ddraw_height;
4708 pMode->Format = This->ddraw_format;
4709 pMode->RefreshRate = 0;
4717 * Stateblock related functions
4720 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 IWineD3DStateBlock *stateblock;
4725 TRACE("(%p)\n", This);
4727 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4729 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4730 if (FAILED(hr)) return hr;
4732 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4733 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4734 This->isRecordingState = TRUE;
4736 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4741 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4744 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4746 if (!This->isRecordingState) {
4747 WARN("(%p) not recording! returning error\n", This);
4748 *ppStateBlock = NULL;
4749 return WINED3DERR_INVALIDCALL;
4752 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4754 DWORD map = object->changed.renderState[i];
4755 for (j = 0; map; map >>= 1, ++j)
4757 if (!(map & 1)) continue;
4759 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4763 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4765 DWORD map = object->changed.transform[i];
4766 for (j = 0; map; map >>= 1, ++j)
4768 if (!(map & 1)) continue;
4770 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4773 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4774 if(object->changed.vertexShaderConstantsF[i]) {
4775 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4776 object->num_contained_vs_consts_f++;
4779 for(i = 0; i < MAX_CONST_I; i++) {
4780 if (object->changed.vertexShaderConstantsI & (1 << i))
4782 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4783 object->num_contained_vs_consts_i++;
4786 for(i = 0; i < MAX_CONST_B; i++) {
4787 if (object->changed.vertexShaderConstantsB & (1 << i))
4789 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4790 object->num_contained_vs_consts_b++;
4793 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4795 if (object->changed.pixelShaderConstantsF[i])
4797 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4798 ++object->num_contained_ps_consts_f;
4801 for(i = 0; i < MAX_CONST_I; i++) {
4802 if (object->changed.pixelShaderConstantsI & (1 << i))
4804 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4805 object->num_contained_ps_consts_i++;
4808 for(i = 0; i < MAX_CONST_B; i++) {
4809 if (object->changed.pixelShaderConstantsB & (1 << i))
4811 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4812 object->num_contained_ps_consts_b++;
4815 for(i = 0; i < MAX_TEXTURES; i++) {
4816 DWORD map = object->changed.textureState[i];
4818 for(j = 0; map; map >>= 1, ++j)
4820 if (!(map & 1)) continue;
4822 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4823 object->contained_tss_states[object->num_contained_tss_states].state = j;
4824 ++object->num_contained_tss_states;
4827 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4828 DWORD map = object->changed.samplerState[i];
4830 for (j = 0; map; map >>= 1, ++j)
4832 if (!(map & 1)) continue;
4834 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4835 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4836 ++object->num_contained_sampler_states;
4840 *ppStateBlock = (IWineD3DStateBlock*) object;
4841 This->isRecordingState = FALSE;
4842 This->updateStateBlock = This->stateBlock;
4843 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4844 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4845 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4850 * Scene related functions
4852 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4853 /* At the moment we have no need for any functionality at the beginning
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 TRACE("(%p)\n", This);
4859 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4860 return WINED3DERR_INVALIDCALL;
4862 This->inScene = TRUE;
4866 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4868 TRACE("(%p)\n", This);
4870 if(!This->inScene) {
4871 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4872 return WINED3DERR_INVALIDCALL;
4875 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4876 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4878 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4882 This->inScene = FALSE;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4887 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4888 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4890 IWineD3DSwapChain *swapChain = NULL;
4892 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4894 TRACE("(%p) Presenting the frame\n", This);
4896 for(i = 0 ; i < swapchains ; i ++) {
4898 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4899 TRACE("presentinng chain %d, %p\n", i, swapChain);
4900 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4901 IWineD3DSwapChain_Release(swapChain);
4907 /* Not called from the VTable (internal subroutine) */
4908 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4909 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4910 float Z, DWORD Stencil) {
4911 GLbitfield glMask = 0;
4913 WINED3DRECT curRect;
4915 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4916 UINT drawable_width, drawable_height;
4917 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4918 IWineD3DSwapChainImpl *swapchain = NULL;
4920 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4921 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4922 * for the cleared parts, and the untouched parts.
4924 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4925 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4926 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4927 * checking all this if the dest surface is in the drawable anyway.
4929 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4931 if(vp->X != 0 || vp->Y != 0 ||
4932 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4933 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4936 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4937 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4938 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4939 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4940 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4943 if(Count > 0 && pRects && (
4944 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4945 pRects[0].x2 < target->currentDesc.Width ||
4946 pRects[0].y2 < target->currentDesc.Height)) {
4947 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4954 target->get_drawable_size(target, &drawable_width, &drawable_height);
4956 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4959 /* Only set the values up once, as they are not changing */
4960 if (Flags & WINED3DCLEAR_STENCIL) {
4961 glClearStencil(Stencil);
4962 checkGLcall("glClearStencil");
4963 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4964 glStencilMask(0xFFFFFFFF);
4967 if (Flags & WINED3DCLEAR_ZBUFFER) {
4968 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4969 glDepthMask(GL_TRUE);
4971 checkGLcall("glClearDepth");
4972 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4975 if (vp->X != 0 || vp->Y != 0 ||
4976 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4977 surface_load_ds_location(This->stencilBufferTarget, location);
4979 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4980 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4981 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4982 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4983 surface_load_ds_location(This->stencilBufferTarget, location);
4985 else if (Count > 0 && pRects && (
4986 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4987 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4988 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4989 surface_load_ds_location(This->stencilBufferTarget, location);
4993 if (Flags & WINED3DCLEAR_TARGET) {
4994 TRACE("Clearing screen with glClear to color %x\n", Color);
4995 glClearColor(D3DCOLOR_R(Color),
4999 checkGLcall("glClearColor");
5001 /* Clear ALL colors! */
5002 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5003 glMask = glMask | GL_COLOR_BUFFER_BIT;
5006 vp_rect.left = vp->X;
5007 vp_rect.top = vp->Y;
5008 vp_rect.right = vp->X + vp->Width;
5009 vp_rect.bottom = vp->Y + vp->Height;
5010 if (!(Count > 0 && pRects)) {
5011 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5012 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5014 if(This->render_offscreen) {
5015 glScissor(vp_rect.left, vp_rect.top,
5016 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5018 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5019 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5021 checkGLcall("glScissor");
5023 checkGLcall("glClear");
5025 /* Now process each rect in turn */
5026 for (i = 0; i < Count; i++) {
5027 /* Note gl uses lower left, width/height */
5028 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5029 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5030 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5032 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5033 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5034 curRect.x1, (target->currentDesc.Height - curRect.y2),
5035 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5037 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5038 * The rectangle is not cleared, no error is returned, but further rectanlges are
5039 * still cleared if they are valid
5041 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5042 TRACE("Rectangle with negative dimensions, ignoring\n");
5046 if(This->render_offscreen) {
5047 glScissor(curRect.x1, curRect.y1,
5048 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5050 glScissor(curRect.x1, drawable_height - curRect.y2,
5051 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5053 checkGLcall("glScissor");
5056 checkGLcall("glClear");
5060 /* Restore the old values (why..?) */
5061 if (Flags & WINED3DCLEAR_STENCIL) {
5062 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5064 if (Flags & WINED3DCLEAR_TARGET) {
5065 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5066 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5067 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5068 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5069 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5071 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5072 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5074 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5076 if (Flags & WINED3DCLEAR_ZBUFFER) {
5077 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5078 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5079 surface_modify_ds_location(This->stencilBufferTarget, location);
5084 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5085 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5088 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5094 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5095 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5097 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5099 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5100 Count, pRects, Flags, Color, Z, Stencil);
5102 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5103 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5104 /* TODO: What about depth stencil buffers without stencil bits? */
5105 return WINED3DERR_INVALIDCALL;
5108 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5114 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5115 UINT PrimitiveCount) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5119 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5120 debug_d3dprimitivetype(PrimitiveType),
5121 StartVertex, PrimitiveCount);
5123 if(!This->stateBlock->vertexDecl) {
5124 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5125 return WINED3DERR_INVALIDCALL;
5128 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5129 if(This->stateBlock->streamIsUP) {
5130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5131 This->stateBlock->streamIsUP = FALSE;
5134 if(This->stateBlock->loadBaseVertexIndex != 0) {
5135 This->stateBlock->loadBaseVertexIndex = 0;
5136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5138 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5139 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0/* NumVertices */, StartVertex /* start_idx */,
5140 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5144 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5145 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5146 WINED3DPRIMITIVETYPE PrimitiveType,
5147 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 IWineD3DIndexBuffer *pIB;
5152 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5155 pIB = This->stateBlock->pIndexData;
5157 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5158 * without an index buffer set. (The first time at least...)
5159 * D3D8 simply dies, but I doubt it can do much harm to return
5160 * D3DERR_INVALIDCALL there as well. */
5161 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5162 return WINED3DERR_INVALIDCALL;
5165 if(!This->stateBlock->vertexDecl) {
5166 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5167 return WINED3DERR_INVALIDCALL;
5170 if(This->stateBlock->streamIsUP) {
5171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5172 This->stateBlock->streamIsUP = FALSE;
5174 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5176 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5177 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5178 minIndex, NumVertices, startIndex, primCount);
5180 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5181 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5187 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5188 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5192 drawPrimitive(iface, PrimitiveType, primCount, NumVertices, startIndex,
5193 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5198 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5199 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5200 UINT VertexStreamZeroStride) {
5201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5202 IWineD3DVertexBuffer *vb;
5204 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5205 debug_d3dprimitivetype(PrimitiveType),
5206 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5208 if(!This->stateBlock->vertexDecl) {
5209 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5210 return WINED3DERR_INVALIDCALL;
5213 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5214 vb = This->stateBlock->streamSource[0];
5215 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5216 if(vb) IWineD3DVertexBuffer_Release(vb);
5217 This->stateBlock->streamOffset[0] = 0;
5218 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5219 This->stateBlock->streamIsUP = TRUE;
5220 This->stateBlock->loadBaseVertexIndex = 0;
5222 /* TODO: Only mark dirty if drawing from a different UP address */
5223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5225 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* NumVertices */,
5226 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5228 /* MSDN specifies stream zero settings must be set to NULL */
5229 This->stateBlock->streamStride[0] = 0;
5230 This->stateBlock->streamSource[0] = NULL;
5232 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5233 * the new stream sources or use UP drawing again
5238 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5239 UINT MinVertexIndex, UINT NumVertices,
5240 UINT PrimitiveCount, CONST void* pIndexData,
5241 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5242 UINT VertexStreamZeroStride) {
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5245 IWineD3DVertexBuffer *vb;
5246 IWineD3DIndexBuffer *ib;
5248 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5249 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5250 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5251 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5253 if(!This->stateBlock->vertexDecl) {
5254 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5255 return WINED3DERR_INVALIDCALL;
5258 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5264 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5265 vb = This->stateBlock->streamSource[0];
5266 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5267 if(vb) IWineD3DVertexBuffer_Release(vb);
5268 This->stateBlock->streamIsUP = TRUE;
5269 This->stateBlock->streamOffset[0] = 0;
5270 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5272 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5273 This->stateBlock->baseVertexIndex = 0;
5274 This->stateBlock->loadBaseVertexIndex = 0;
5275 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5277 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5279 drawPrimitive(iface, PrimitiveType, PrimitiveCount, NumVertices, 0 /* start_idx */, idxStride, pIndexData, MinVertexIndex);
5281 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5282 This->stateBlock->streamSource[0] = NULL;
5283 This->stateBlock->streamStride[0] = 0;
5284 ib = This->stateBlock->pIndexData;
5286 IWineD3DIndexBuffer_Release(ib);
5287 This->stateBlock->pIndexData = NULL;
5289 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5290 * SetStreamSource to specify a vertex buffer
5296 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5297 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5298 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5302 /* Mark the state dirty until we have nicer tracking
5303 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5308 This->stateBlock->baseVertexIndex = 0;
5309 This->up_strided = DrawPrimStrideData;
5310 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0);
5311 This->up_strided = NULL;
5315 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5316 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5317 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5318 WINED3DFORMAT IndexDataFormat)
5320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5321 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5323 /* Mark the state dirty until we have nicer tracking
5324 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5329 This->stateBlock->streamIsUP = TRUE;
5330 This->stateBlock->baseVertexIndex = 0;
5331 This->up_strided = DrawPrimStrideData;
5332 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5333 This->up_strided = NULL;
5337 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5338 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5339 * not callable by the app directly no parameter validation checks are needed here.
5341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5342 WINED3DLOCKED_BOX src;
5343 WINED3DLOCKED_BOX dst;
5345 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5347 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5348 * dirtification to improve loading performance.
5350 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5351 if(FAILED(hr)) return hr;
5352 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5354 IWineD3DVolume_UnlockBox(pSourceVolume);
5358 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5360 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5362 IWineD3DVolume_UnlockBox(pSourceVolume);
5364 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5369 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5370 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5372 HRESULT hr = WINED3D_OK;
5373 WINED3DRESOURCETYPE sourceType;
5374 WINED3DRESOURCETYPE destinationType;
5377 /* TODO: think about moving the code into IWineD3DBaseTexture */
5379 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5381 /* verify that the source and destination textures aren't NULL */
5382 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5383 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5384 This, pSourceTexture, pDestinationTexture);
5385 hr = WINED3DERR_INVALIDCALL;
5388 if (pSourceTexture == pDestinationTexture) {
5389 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5390 This, pSourceTexture, pDestinationTexture);
5391 hr = WINED3DERR_INVALIDCALL;
5393 /* Verify that the source and destination textures are the same type */
5394 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5395 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5397 if (sourceType != destinationType) {
5398 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5400 hr = WINED3DERR_INVALIDCALL;
5403 /* check that both textures have the identical numbers of levels */
5404 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5405 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5406 hr = WINED3DERR_INVALIDCALL;
5409 if (WINED3D_OK == hr) {
5411 /* Make sure that the destination texture is loaded */
5412 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5414 /* Update every surface level of the texture */
5415 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5417 switch (sourceType) {
5418 case WINED3DRTYPE_TEXTURE:
5420 IWineD3DSurface *srcSurface;
5421 IWineD3DSurface *destSurface;
5423 for (i = 0 ; i < levels ; ++i) {
5424 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5425 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5426 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5427 IWineD3DSurface_Release(srcSurface);
5428 IWineD3DSurface_Release(destSurface);
5429 if (WINED3D_OK != hr) {
5430 WARN("(%p) : Call to update surface failed\n", This);
5436 case WINED3DRTYPE_CUBETEXTURE:
5438 IWineD3DSurface *srcSurface;
5439 IWineD3DSurface *destSurface;
5440 WINED3DCUBEMAP_FACES faceType;
5442 for (i = 0 ; i < levels ; ++i) {
5443 /* Update each cube face */
5444 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5445 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5446 if (WINED3D_OK != hr) {
5447 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5449 TRACE("Got srcSurface %p\n", srcSurface);
5451 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5452 if (WINED3D_OK != hr) {
5453 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5455 TRACE("Got desrSurface %p\n", destSurface);
5457 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5458 IWineD3DSurface_Release(srcSurface);
5459 IWineD3DSurface_Release(destSurface);
5460 if (WINED3D_OK != hr) {
5461 WARN("(%p) : Call to update surface failed\n", This);
5469 case WINED3DRTYPE_VOLUMETEXTURE:
5471 IWineD3DVolume *srcVolume = NULL;
5472 IWineD3DVolume *destVolume = NULL;
5474 for (i = 0 ; i < levels ; ++i) {
5475 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5476 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5477 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5478 IWineD3DVolume_Release(srcVolume);
5479 IWineD3DVolume_Release(destVolume);
5480 if (WINED3D_OK != hr) {
5481 WARN("(%p) : Call to update volume failed\n", This);
5489 FIXME("(%p) : Unsupported source and destination type\n", This);
5490 hr = WINED3DERR_INVALIDCALL;
5497 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5498 IWineD3DSwapChain *swapChain;
5500 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5501 if(hr == WINED3D_OK) {
5502 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5503 IWineD3DSwapChain_Release(swapChain);
5508 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5510 IWineD3DBaseTextureImpl *texture;
5511 const struct GlPixelFormatDesc *gl_info;
5514 TRACE("(%p) : %p\n", This, pNumPasses);
5516 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5517 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5518 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5519 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5521 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5522 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5523 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5526 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5527 if(!texture) continue;
5528 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5529 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5531 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5532 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5535 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5536 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5539 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5540 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5541 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5546 /* return a sensible default */
5549 TRACE("returning D3D_OK\n");
5553 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5557 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5558 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5559 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5560 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5565 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5569 PALETTEENTRY **palettes;
5571 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5573 if (PaletteNumber >= MAX_PALETTES) {
5574 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5575 return WINED3DERR_INVALIDCALL;
5578 if (PaletteNumber >= This->NumberOfPalettes) {
5579 NewSize = This->NumberOfPalettes;
5582 } while(PaletteNumber >= NewSize);
5583 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5585 ERR("Out of memory!\n");
5586 return E_OUTOFMEMORY;
5588 This->palettes = palettes;
5589 This->NumberOfPalettes = NewSize;
5592 if (!This->palettes[PaletteNumber]) {
5593 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5594 if (!This->palettes[PaletteNumber]) {
5595 ERR("Out of memory!\n");
5596 return E_OUTOFMEMORY;
5600 for (j = 0; j < 256; ++j) {
5601 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5602 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5603 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5604 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5606 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5607 TRACE("(%p) : returning\n", This);
5611 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5614 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5615 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5616 /* What happens in such situation isn't documented; Native seems to silently abort
5617 on such conditions. Return Invalid Call. */
5618 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5619 return WINED3DERR_INVALIDCALL;
5621 for (j = 0; j < 256; ++j) {
5622 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5623 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5624 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5625 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5627 TRACE("(%p) : returning\n", This);
5631 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5633 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5634 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5635 (tested with reference rasterizer). Return Invalid Call. */
5636 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5637 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5638 return WINED3DERR_INVALIDCALL;
5640 /*TODO: stateblocks */
5641 if (This->currentPalette != PaletteNumber) {
5642 This->currentPalette = PaletteNumber;
5643 dirtify_p8_texture_samplers(This);
5645 TRACE("(%p) : returning\n", This);
5649 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5651 if (PaletteNumber == NULL) {
5652 WARN("(%p) : returning Invalid Call\n", This);
5653 return WINED3DERR_INVALIDCALL;
5655 /*TODO: stateblocks */
5656 *PaletteNumber = This->currentPalette;
5657 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5661 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5666 FIXME("(%p) : stub\n", This);
5670 This->softwareVertexProcessing = bSoftware;
5675 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5680 FIXME("(%p) : stub\n", This);
5683 return This->softwareVertexProcessing;
5687 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 IWineD3DSwapChain *swapChain;
5692 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5694 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5695 if(hr == WINED3D_OK){
5696 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5697 IWineD3DSwapChain_Release(swapChain);
5699 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5705 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5708 if(nSegments != 0.0f) {
5711 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5718 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5723 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5729 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5731 /** TODO: remove casts to IWineD3DSurfaceImpl
5732 * NOTE: move code to surface to accomplish this
5733 ****************************************/
5734 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5735 int srcWidth, srcHeight;
5736 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5737 WINED3DFORMAT destFormat, srcFormat;
5739 int srcLeft, destLeft, destTop;
5740 WINED3DPOOL srcPool, destPool;
5742 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5743 glDescriptor *glDescription = NULL;
5747 CONVERT_TYPES convert = NO_CONVERSION;
5749 WINED3DSURFACE_DESC winedesc;
5751 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5752 memset(&winedesc, 0, sizeof(winedesc));
5753 winedesc.Width = &srcSurfaceWidth;
5754 winedesc.Height = &srcSurfaceHeight;
5755 winedesc.Pool = &srcPool;
5756 winedesc.Format = &srcFormat;
5758 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5760 winedesc.Width = &destSurfaceWidth;
5761 winedesc.Height = &destSurfaceHeight;
5762 winedesc.Pool = &destPool;
5763 winedesc.Format = &destFormat;
5764 winedesc.Size = &destSize;
5766 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5768 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5769 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5770 return WINED3DERR_INVALIDCALL;
5773 /* This call loads the opengl surface directly, instead of copying the surface to the
5774 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5775 * copy in sysmem and use regular surface loading.
5777 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5778 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5779 if(convert != NO_CONVERSION) {
5780 return IWineD3DSurface_BltFast(pDestinationSurface,
5781 pDestPoint ? pDestPoint->x : 0,
5782 pDestPoint ? pDestPoint->y : 0,
5783 pSourceSurface, pSourceRect, 0);
5786 if (destFormat == WINED3DFMT_UNKNOWN) {
5787 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5788 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5790 /* Get the update surface description */
5791 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5794 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5797 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5798 checkGLcall("glActiveTextureARB");
5801 /* Make sure the surface is loaded and up to date */
5802 IWineD3DSurface_PreLoad(pDestinationSurface);
5803 IWineD3DSurface_BindTexture(pDestinationSurface);
5805 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5807 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5808 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5809 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5810 srcLeft = pSourceRect ? pSourceRect->left : 0;
5811 destLeft = pDestPoint ? pDestPoint->x : 0;
5812 destTop = pDestPoint ? pDestPoint->y : 0;
5815 /* This function doesn't support compressed textures
5816 the pitch is just bytesPerPixel * width */
5817 if(srcWidth != srcSurfaceWidth || srcLeft ){
5818 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5819 offset += srcLeft * pSrcSurface->bytesPerPixel;
5820 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5822 /* TODO DXT formats */
5824 if(pSourceRect != NULL && pSourceRect->top != 0){
5825 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5827 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5828 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5829 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5832 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5834 /* need to lock the surface to get the data */
5835 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5840 /* TODO: Cube and volume support */
5842 /* not a whole row so we have to do it a line at a time */
5845 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5846 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5848 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5850 glTexSubImage2D(glDescription->target
5851 ,glDescription->level
5856 ,glDescription->glFormat
5857 ,glDescription->glType
5858 ,data /* could be quicker using */
5863 } else { /* Full width, so just write out the whole texture */
5864 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5866 if (WINED3DFMT_DXT1 == destFormat ||
5867 WINED3DFMT_DXT2 == destFormat ||
5868 WINED3DFMT_DXT3 == destFormat ||
5869 WINED3DFMT_DXT4 == destFormat ||
5870 WINED3DFMT_DXT5 == destFormat) {
5871 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5872 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5873 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5874 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5875 } if (destFormat != srcFormat) {
5876 FIXME("Updating mixed format compressed texture is not curretly support\n");
5878 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5879 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5882 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5887 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5888 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5891 checkGLcall("glTexSubImage2D");
5895 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5896 sampler = This->rev_tex_unit_map[0];
5897 if (sampler != -1) {
5898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5904 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5906 struct WineD3DRectPatch *patch;
5910 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5912 if(!(Handle || pRectPatchInfo)) {
5913 /* TODO: Write a test for the return value, thus the FIXME */
5914 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5915 return WINED3DERR_INVALIDCALL;
5919 i = PATCHMAP_HASHFUNC(Handle);
5921 LIST_FOR_EACH(e, &This->patches[i]) {
5922 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5923 if(patch->Handle == Handle) {
5930 TRACE("Patch does not exist. Creating a new one\n");
5931 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5932 patch->Handle = Handle;
5933 list_add_head(&This->patches[i], &patch->entry);
5935 TRACE("Found existing patch %p\n", patch);
5938 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5939 * attributes we have to tesselate, read back, and draw. This needs a patch
5940 * management structure instance. Create one.
5942 * A possible improvement is to check if a vertex shader is used, and if not directly
5945 FIXME("Drawing an uncached patch. This is slow\n");
5946 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5949 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5950 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5951 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5953 TRACE("Tesselation density or patch info changed, retesselating\n");
5955 if(pRectPatchInfo) {
5956 patch->RectPatchInfo = *pRectPatchInfo;
5958 patch->numSegs[0] = pNumSegs[0];
5959 patch->numSegs[1] = pNumSegs[1];
5960 patch->numSegs[2] = pNumSegs[2];
5961 patch->numSegs[3] = pNumSegs[3];
5963 hr = tesselate_rectpatch(This, patch);
5965 WARN("Patch tesselation failed\n");
5967 /* Do not release the handle to store the params of the patch */
5969 HeapFree(GetProcessHeap(), 0, patch);
5975 This->currentPatch = patch;
5976 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5977 This->currentPatch = NULL;
5979 /* Destroy uncached patches */
5981 HeapFree(GetProcessHeap(), 0, patch->mem);
5982 HeapFree(GetProcessHeap(), 0, patch);
5987 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5989 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5990 FIXME("(%p) : Stub\n", This);
5994 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 struct WineD3DRectPatch *patch;
5999 TRACE("(%p) Handle(%d)\n", This, Handle);
6001 i = PATCHMAP_HASHFUNC(Handle);
6002 LIST_FOR_EACH(e, &This->patches[i]) {
6003 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6004 if(patch->Handle == Handle) {
6005 TRACE("Deleting patch %p\n", patch);
6006 list_remove(&patch->entry);
6007 HeapFree(GetProcessHeap(), 0, patch->mem);
6008 HeapFree(GetProcessHeap(), 0, patch);
6013 /* TODO: Write a test for the return value */
6014 FIXME("Attempt to destroy nonexistent patch\n");
6015 return WINED3DERR_INVALIDCALL;
6018 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6020 IWineD3DSwapChain *swapchain;
6022 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6023 if (SUCCEEDED(hr)) {
6024 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6031 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6033 IWineD3DSwapChain *swapchain;
6035 swapchain = get_swapchain(surface);
6039 TRACE("Surface %p is onscreen\n", surface);
6041 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6043 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6044 buffer = surface_get_gl_buffer(surface, swapchain);
6045 glDrawBuffer(buffer);
6046 checkGLcall("glDrawBuffer()");
6048 TRACE("Surface %p is offscreen\n", surface);
6050 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6052 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6053 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6054 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6055 checkGLcall("glFramebufferRenderbufferEXT");
6059 glEnable(GL_SCISSOR_TEST);
6061 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6063 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6064 rect->x2 - rect->x1, rect->y2 - rect->y1);
6066 checkGLcall("glScissor");
6067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6069 glDisable(GL_SCISSOR_TEST);
6071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6073 glDisable(GL_BLEND);
6074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6076 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6079 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6080 glClear(GL_COLOR_BUFFER_BIT);
6081 checkGLcall("glClear");
6083 if (This->activeContext->current_fbo) {
6084 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6086 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6087 checkGLcall("glBindFramebuffer()");
6090 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6091 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6092 glDrawBuffer(GL_BACK);
6093 checkGLcall("glDrawBuffer()");
6099 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6100 unsigned int r, g, b, a;
6103 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6104 destfmt == WINED3DFMT_R8G8B8)
6107 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6109 a = (color & 0xff000000) >> 24;
6110 r = (color & 0x00ff0000) >> 16;
6111 g = (color & 0x0000ff00) >> 8;
6112 b = (color & 0x000000ff) >> 0;
6116 case WINED3DFMT_R5G6B5:
6117 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6124 TRACE("Returning %08x\n", ret);
6127 case WINED3DFMT_X1R5G5B5:
6128 case WINED3DFMT_A1R5G5B5:
6137 TRACE("Returning %08x\n", ret);
6141 TRACE("Returning %08x\n", a);
6144 case WINED3DFMT_X4R4G4B4:
6145 case WINED3DFMT_A4R4G4B4:
6154 TRACE("Returning %08x\n", ret);
6157 case WINED3DFMT_R3G3B2:
6164 TRACE("Returning %08x\n", ret);
6167 case WINED3DFMT_X8B8G8R8:
6168 case WINED3DFMT_A8B8G8R8:
6173 TRACE("Returning %08x\n", ret);
6176 case WINED3DFMT_A2R10G10B10:
6178 r = (r * 1024) / 256;
6179 g = (g * 1024) / 256;
6180 b = (b * 1024) / 256;
6185 TRACE("Returning %08x\n", ret);
6188 case WINED3DFMT_A2B10G10R10:
6190 r = (r * 1024) / 256;
6191 g = (g * 1024) / 256;
6192 b = (b * 1024) / 256;
6197 TRACE("Returning %08x\n", ret);
6201 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6206 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6208 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6210 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6212 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6213 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6214 return WINED3DERR_INVALIDCALL;
6217 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6218 color_fill_fbo(iface, pSurface, pRect, color);
6221 /* Just forward this to the DirectDraw blitting engine */
6222 memset(&BltFx, 0, sizeof(BltFx));
6223 BltFx.dwSize = sizeof(BltFx);
6224 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6225 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6226 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6230 /* rendertarget and depth stencil functions */
6231 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6234 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6235 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6236 return WINED3DERR_INVALIDCALL;
6239 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6240 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6241 /* Note inc ref on returned surface */
6242 if(*ppRenderTarget != NULL)
6243 IWineD3DSurface_AddRef(*ppRenderTarget);
6247 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6249 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6250 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6251 IWineD3DSwapChainImpl *Swapchain;
6254 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6256 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6257 if(hr != WINED3D_OK) {
6258 ERR("Can't get the swapchain\n");
6262 /* Make sure to release the swapchain */
6263 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6265 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6266 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6267 return WINED3DERR_INVALIDCALL;
6269 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6270 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6271 return WINED3DERR_INVALIDCALL;
6274 if(Swapchain->frontBuffer != Front) {
6275 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6277 if(Swapchain->frontBuffer)
6278 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6279 Swapchain->frontBuffer = Front;
6281 if(Swapchain->frontBuffer) {
6282 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6286 if(Back && !Swapchain->backBuffer) {
6287 /* We need memory for the back buffer array - only one back buffer this way */
6288 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6289 if(!Swapchain->backBuffer) {
6290 ERR("Out of memory\n");
6291 return E_OUTOFMEMORY;
6295 if(Swapchain->backBuffer[0] != Back) {
6296 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6298 /* What to do about the context here in the case of multithreading? Not sure.
6299 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6302 if(!Swapchain->backBuffer[0]) {
6303 /* GL was told to draw to the front buffer at creation,
6306 glDrawBuffer(GL_BACK);
6307 checkGLcall("glDrawBuffer(GL_BACK)");
6308 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6309 Swapchain->presentParms.BackBufferCount = 1;
6311 /* That makes problems - disable for now */
6312 /* glDrawBuffer(GL_FRONT); */
6313 checkGLcall("glDrawBuffer(GL_FRONT)");
6314 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6315 Swapchain->presentParms.BackBufferCount = 0;
6319 if(Swapchain->backBuffer[0])
6320 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6321 Swapchain->backBuffer[0] = Back;
6323 if(Swapchain->backBuffer[0]) {
6324 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6326 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6327 Swapchain->backBuffer = NULL;
6335 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6337 *ppZStencilSurface = This->stencilBufferTarget;
6338 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6340 if(*ppZStencilSurface != NULL) {
6341 /* Note inc ref on returned surface */
6342 IWineD3DSurface_AddRef(*ppZStencilSurface);
6345 return WINED3DERR_NOTFOUND;
6349 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6350 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6353 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6354 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6356 POINT offset = {0, 0};
6358 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6359 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6360 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6361 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6364 case WINED3DTEXF_LINEAR:
6365 gl_filter = GL_LINEAR;
6369 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6370 case WINED3DTEXF_NONE:
6371 case WINED3DTEXF_POINT:
6372 gl_filter = GL_NEAREST;
6376 /* Attach src surface to src fbo */
6377 src_swapchain = get_swapchain(src_surface);
6378 if (src_swapchain) {
6379 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6381 TRACE("Source surface %p is onscreen\n", src_surface);
6382 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6383 /* Make sure the drawable is up to date. In the offscreen case
6384 * attach_surface_fbo() implicitly takes care of this. */
6385 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6387 if(buffer == GL_FRONT) {
6390 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6391 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6392 h = windowsize.bottom - windowsize.top;
6393 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6394 src_rect->y1 = offset.y + h - src_rect->y1;
6395 src_rect->y2 = offset.y + h - src_rect->y2;
6397 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6398 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6402 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6403 glReadBuffer(buffer);
6404 checkGLcall("glReadBuffer()");
6406 TRACE("Source surface %p is offscreen\n", src_surface);
6408 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6409 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6410 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6411 checkGLcall("glReadBuffer()");
6412 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6413 checkGLcall("glFramebufferRenderbufferEXT");
6417 /* Attach dst surface to dst fbo */
6418 dst_swapchain = get_swapchain(dst_surface);
6419 if (dst_swapchain) {
6420 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6422 TRACE("Destination surface %p is onscreen\n", dst_surface);
6423 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6424 /* Make sure the drawable is up to date. In the offscreen case
6425 * attach_surface_fbo() implicitly takes care of this. */
6426 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6428 if(buffer == GL_FRONT) {
6431 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6432 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6433 h = windowsize.bottom - windowsize.top;
6434 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6435 dst_rect->y1 = offset.y + h - dst_rect->y1;
6436 dst_rect->y2 = offset.y + h - dst_rect->y2;
6438 /* Screen coords = window coords, surface height = window height */
6439 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6440 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6444 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6445 glDrawBuffer(buffer);
6446 checkGLcall("glDrawBuffer()");
6448 TRACE("Destination surface %p is offscreen\n", dst_surface);
6450 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6451 if(!src_swapchain) {
6452 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6456 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6457 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6458 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6459 checkGLcall("glDrawBuffer()");
6460 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6461 checkGLcall("glFramebufferRenderbufferEXT");
6463 glDisable(GL_SCISSOR_TEST);
6464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6467 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6468 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6469 checkGLcall("glBlitFramebuffer()");
6471 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6472 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6473 checkGLcall("glBlitFramebuffer()");
6476 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6478 if (This->activeContext->current_fbo) {
6479 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6481 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6482 checkGLcall("glBindFramebuffer()");
6485 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6486 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6487 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6488 glDrawBuffer(GL_BACK);
6489 checkGLcall("glDrawBuffer()");
6494 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6496 WINED3DVIEWPORT viewport;
6498 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6500 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6501 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6502 This, RenderTargetIndex, GL_LIMITS(buffers));
6503 return WINED3DERR_INVALIDCALL;
6506 /* MSDN says that null disables the render target
6507 but a device must always be associated with a render target
6508 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6510 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6511 FIXME("Trying to set render target 0 to NULL\n");
6512 return WINED3DERR_INVALIDCALL;
6514 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6515 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);
6516 return WINED3DERR_INVALIDCALL;
6519 /* If we are trying to set what we already have, don't bother */
6520 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6521 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6524 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6525 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6526 This->render_targets[RenderTargetIndex] = pRenderTarget;
6528 /* Render target 0 is special */
6529 if(RenderTargetIndex == 0) {
6530 /* Finally, reset the viewport as the MSDN states. */
6531 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6532 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6535 viewport.MaxZ = 1.0f;
6536 viewport.MinZ = 0.0f;
6537 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6538 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6539 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6546 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6548 HRESULT hr = WINED3D_OK;
6549 IWineD3DSurface *tmp;
6551 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6553 if (pNewZStencil == This->stencilBufferTarget) {
6554 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6556 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6557 * depending on the renter target implementation being used.
6558 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6559 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6560 * stencil buffer and incur an extra memory overhead
6561 ******************************************************/
6563 if (This->stencilBufferTarget) {
6564 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6565 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6566 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6568 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6569 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6570 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6574 tmp = This->stencilBufferTarget;
6575 This->stencilBufferTarget = pNewZStencil;
6576 /* should we be calling the parent or the wined3d surface? */
6577 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6578 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6581 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6582 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6592 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6593 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6595 /* TODO: the use of Impl is deprecated. */
6596 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6597 WINED3DLOCKED_RECT lockedRect;
6599 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6601 /* some basic validation checks */
6602 if(This->cursorTexture) {
6603 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6605 glDeleteTextures(1, &This->cursorTexture);
6607 This->cursorTexture = 0;
6610 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6611 This->haveHardwareCursor = TRUE;
6613 This->haveHardwareCursor = FALSE;
6616 WINED3DLOCKED_RECT rect;
6618 /* MSDN: Cursor must be A8R8G8B8 */
6619 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6620 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6621 return WINED3DERR_INVALIDCALL;
6624 /* MSDN: Cursor must be smaller than the display mode */
6625 if(pSur->currentDesc.Width > This->ddraw_width ||
6626 pSur->currentDesc.Height > This->ddraw_height) {
6627 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);
6628 return WINED3DERR_INVALIDCALL;
6631 if (!This->haveHardwareCursor) {
6632 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6634 /* Do not store the surface's pointer because the application may
6635 * release it after setting the cursor image. Windows doesn't
6636 * addref the set surface, so we can't do this either without
6637 * creating circular refcount dependencies. Copy out the gl texture
6640 This->cursorWidth = pSur->currentDesc.Width;
6641 This->cursorHeight = pSur->currentDesc.Height;
6642 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6644 const struct GlPixelFormatDesc *glDesc;
6645 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6646 char *mem, *bits = (char *)rect.pBits;
6647 GLint intfmt = glDesc->glInternal;
6648 GLint format = glDesc->glFormat;
6649 GLint type = glDesc->glType;
6650 INT height = This->cursorHeight;
6651 INT width = This->cursorWidth;
6652 INT bpp = tableEntry->bpp;
6655 /* Reformat the texture memory (pitch and width can be
6657 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6658 for(i = 0; i < height; i++)
6659 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6660 IWineD3DSurface_UnlockRect(pCursorBitmap);
6663 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6664 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6665 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6668 /* Make sure that a proper texture unit is selected */
6669 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6670 checkGLcall("glActiveTextureARB");
6671 sampler = This->rev_tex_unit_map[0];
6672 if (sampler != -1) {
6673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6675 /* Create a new cursor texture */
6676 glGenTextures(1, &This->cursorTexture);
6677 checkGLcall("glGenTextures");
6678 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6679 checkGLcall("glBindTexture");
6680 /* Copy the bitmap memory into the cursor texture */
6681 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6682 HeapFree(GetProcessHeap(), 0, mem);
6683 checkGLcall("glTexImage2D");
6685 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6686 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6687 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6694 FIXME("A cursor texture was not returned.\n");
6695 This->cursorTexture = 0;
6700 /* Draw a hardware cursor */
6701 ICONINFO cursorInfo;
6703 /* Create and clear maskBits because it is not needed for
6704 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6706 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6707 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6708 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6709 WINED3DLOCK_NO_DIRTY_UPDATE |
6710 WINED3DLOCK_READONLY
6712 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6713 pSur->currentDesc.Height);
6715 cursorInfo.fIcon = FALSE;
6716 cursorInfo.xHotspot = XHotSpot;
6717 cursorInfo.yHotspot = YHotSpot;
6718 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6719 pSur->currentDesc.Height, 1,
6721 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6722 pSur->currentDesc.Height, 1,
6723 32, lockedRect.pBits);
6724 IWineD3DSurface_UnlockRect(pCursorBitmap);
6725 /* Create our cursor and clean up. */
6726 cursor = CreateIconIndirect(&cursorInfo);
6728 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6729 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6730 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6731 This->hardwareCursor = cursor;
6732 HeapFree(GetProcessHeap(), 0, maskBits);
6736 This->xHotSpot = XHotSpot;
6737 This->yHotSpot = YHotSpot;
6741 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6743 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6745 This->xScreenSpace = XScreenSpace;
6746 This->yScreenSpace = YScreenSpace;
6752 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6754 BOOL oldVisible = This->bCursorVisible;
6757 TRACE("(%p) : visible(%d)\n", This, bShow);
6760 * When ShowCursor is first called it should make the cursor appear at the OS's last
6761 * known cursor position. Because of this, some applications just repetitively call
6762 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6765 This->xScreenSpace = pt.x;
6766 This->yScreenSpace = pt.y;
6768 if (This->haveHardwareCursor) {
6769 This->bCursorVisible = bShow;
6771 SetCursor(This->hardwareCursor);
6777 if (This->cursorTexture)
6778 This->bCursorVisible = bShow;
6784 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6786 IWineD3DResourceImpl *resource;
6787 TRACE("(%p) : state (%u)\n", This, This->state);
6789 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6790 switch (This->state) {
6793 case WINED3DERR_DEVICELOST:
6795 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6796 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6797 return WINED3DERR_DEVICENOTRESET;
6799 return WINED3DERR_DEVICELOST;
6801 case WINED3DERR_DRIVERINTERNALERROR:
6802 return WINED3DERR_DRIVERINTERNALERROR;
6806 return WINED3DERR_DRIVERINTERNALERROR;
6810 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6812 /** FIXME: Resource tracking needs to be done,
6813 * The closes we can do to this is set the priorities of all managed textures low
6814 * and then reset them.
6815 ***********************************************************/
6816 FIXME("(%p) : stub\n", This);
6820 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6822 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6824 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6825 if(surface->Flags & SFLAG_DIBSECTION) {
6826 /* Release the DC */
6827 SelectObject(surface->hDC, surface->dib.holdbitmap);
6828 DeleteDC(surface->hDC);
6829 /* Release the DIB section */
6830 DeleteObject(surface->dib.DIBsection);
6831 surface->dib.bitmap_data = NULL;
6832 surface->resource.allocatedMemory = NULL;
6833 surface->Flags &= ~SFLAG_DIBSECTION;
6835 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6836 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6837 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6838 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6839 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6840 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6842 surface->pow2Width = surface->pow2Height = 1;
6843 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6844 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6846 surface->glRect.left = 0;
6847 surface->glRect.top = 0;
6848 surface->glRect.right = surface->pow2Width;
6849 surface->glRect.bottom = surface->pow2Height;
6851 if(surface->glDescription.textureName) {
6852 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6854 glDeleteTextures(1, &surface->glDescription.textureName);
6856 surface->glDescription.textureName = 0;
6857 surface->Flags &= ~SFLAG_CLIENT;
6859 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6860 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6861 surface->Flags |= SFLAG_NONPOW2;
6863 surface->Flags &= ~SFLAG_NONPOW2;
6865 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6866 surface->resource.allocatedMemory = NULL;
6867 surface->resource.heapMemory = NULL;
6868 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6869 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6870 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6871 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6873 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6877 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6878 TRACE("Unloading resource %p\n", resource);
6879 IWineD3DResource_UnLoad(resource);
6880 IWineD3DResource_Release(resource);
6884 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6887 WINED3DDISPLAYMODE m;
6890 /* All Windowed modes are supported, as is leaving the current mode */
6891 if(pp->Windowed) return TRUE;
6892 if(!pp->BackBufferWidth) return TRUE;
6893 if(!pp->BackBufferHeight) return TRUE;
6895 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6896 for(i = 0; i < count; i++) {
6897 memset(&m, 0, sizeof(m));
6898 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6900 ERR("EnumAdapterModes failed\n");
6902 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6903 /* Mode found, it is supported */
6907 /* Mode not found -> not supported */
6911 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6913 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6915 IWineD3DBaseShaderImpl *shader;
6917 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6918 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6919 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6923 if(This->depth_blt_texture) {
6924 glDeleteTextures(1, &This->depth_blt_texture);
6925 This->depth_blt_texture = 0;
6927 if (This->depth_blt_rb) {
6928 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6929 This->depth_blt_rb = 0;
6930 This->depth_blt_rb_w = 0;
6931 This->depth_blt_rb_h = 0;
6935 This->blitter->free_private(iface);
6936 This->frag_pipe->free_private(iface);
6937 This->shader_backend->shader_free_private(iface);
6940 for (i = 0; i < GL_LIMITS(textures); i++) {
6941 /* Textures are recreated below */
6942 glDeleteTextures(1, &This->dummyTextureName[i]);
6943 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6944 This->dummyTextureName[i] = 0;
6948 while(This->numContexts) {
6949 DestroyContext(This, This->contexts[0]);
6951 This->activeContext = NULL;
6952 HeapFree(GetProcessHeap(), 0, swapchain->context);
6953 swapchain->context = NULL;
6954 swapchain->num_contexts = 0;
6957 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6959 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6961 IWineD3DSurfaceImpl *target;
6963 /* Recreate the primary swapchain's context */
6964 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6965 if(swapchain->backBuffer) {
6966 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6968 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6970 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6971 &swapchain->presentParms);
6972 swapchain->num_contexts = 1;
6973 This->activeContext = swapchain->context[0];
6975 create_dummy_textures(This);
6977 hr = This->shader_backend->shader_alloc_private(iface);
6979 ERR("Failed to recreate shader private data\n");
6982 hr = This->frag_pipe->alloc_private(iface);
6984 TRACE("Fragment pipeline private data couldn't be allocated\n");
6987 hr = This->blitter->alloc_private(iface);
6989 TRACE("Blitter private data couldn't be allocated\n");
6996 This->blitter->free_private(iface);
6997 This->frag_pipe->free_private(iface);
6998 This->shader_backend->shader_free_private(iface);
7002 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7004 IWineD3DSwapChainImpl *swapchain;
7006 BOOL DisplayModeChanged = FALSE;
7007 WINED3DDISPLAYMODE mode;
7008 TRACE("(%p)\n", This);
7010 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7012 ERR("Failed to get the first implicit swapchain\n");
7016 if(!is_display_mode_supported(This, pPresentationParameters)) {
7017 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7018 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7019 pPresentationParameters->BackBufferHeight);
7020 return WINED3DERR_INVALIDCALL;
7023 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7024 * on an existing gl context, so there's no real need for recreation.
7026 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7028 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7030 TRACE("New params:\n");
7031 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7032 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7033 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7034 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7035 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7036 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7037 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7038 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7039 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7040 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7041 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7042 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7043 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7045 /* No special treatment of these parameters. Just store them */
7046 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7047 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7048 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7049 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7051 /* What to do about these? */
7052 if(pPresentationParameters->BackBufferCount != 0 &&
7053 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7054 ERR("Cannot change the back buffer count yet\n");
7056 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7057 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7058 ERR("Cannot change the back buffer format yet\n");
7060 if(pPresentationParameters->hDeviceWindow != NULL &&
7061 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7062 ERR("Cannot change the device window yet\n");
7064 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7065 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7066 return WINED3DERR_INVALIDCALL;
7069 /* Reset the depth stencil */
7070 if (pPresentationParameters->EnableAutoDepthStencil)
7071 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7073 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7075 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7077 if(pPresentationParameters->Windowed) {
7078 mode.Width = swapchain->orig_width;
7079 mode.Height = swapchain->orig_height;
7080 mode.RefreshRate = 0;
7081 mode.Format = swapchain->presentParms.BackBufferFormat;
7083 mode.Width = pPresentationParameters->BackBufferWidth;
7084 mode.Height = pPresentationParameters->BackBufferHeight;
7085 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7086 mode.Format = swapchain->presentParms.BackBufferFormat;
7089 /* Should Width == 800 && Height == 0 set 800x600? */
7090 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7091 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7092 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7096 if(!pPresentationParameters->Windowed) {
7097 DisplayModeChanged = TRUE;
7099 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7100 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7102 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7103 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7104 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7106 if(This->auto_depth_stencil_buffer) {
7107 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7111 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7112 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7113 DisplayModeChanged) {
7115 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7117 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7118 if(swapchain->presentParms.Windowed) {
7119 /* switch from windowed to fs */
7120 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7121 pPresentationParameters->BackBufferWidth,
7122 pPresentationParameters->BackBufferHeight);
7124 /* Fullscreen -> fullscreen mode change */
7125 MoveWindow(swapchain->win_handle, 0, 0,
7126 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7129 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7130 /* Fullscreen -> windowed switch */
7131 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7133 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7134 } else if(!pPresentationParameters->Windowed) {
7135 DWORD style = This->style, exStyle = This->exStyle;
7136 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7137 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7138 * Reset to clear up their mess. Guild Wars also loses the device during that.
7142 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7143 pPresentationParameters->BackBufferWidth,
7144 pPresentationParameters->BackBufferHeight);
7145 This->style = style;
7146 This->exStyle = exStyle;
7149 TRACE("Resetting stateblock\n");
7150 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7151 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7153 /* Note: No parent needed for initial internal stateblock */
7154 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7155 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7156 else TRACE("Created stateblock %p\n", This->stateBlock);
7157 This->updateStateBlock = This->stateBlock;
7158 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7160 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7162 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7165 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7166 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7168 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7174 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7176 /** FIXME: always true at the moment **/
7177 if(!bEnableDialogs) {
7178 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7184 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7186 TRACE("(%p) : pParameters %p\n", This, pParameters);
7188 *pParameters = This->createParms;
7192 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7193 IWineD3DSwapChain *swapchain;
7195 TRACE("Relaying to swapchain\n");
7197 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7198 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7199 IWineD3DSwapChain_Release(swapchain);
7204 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7205 IWineD3DSwapChain *swapchain;
7207 TRACE("Relaying to swapchain\n");
7209 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7210 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7211 IWineD3DSwapChain_Release(swapchain);
7217 /** ********************************************************
7218 * Notification functions
7219 ** ********************************************************/
7220 /** This function must be called in the release of a resource when ref == 0,
7221 * the contents of resource must still be correct,
7222 * any handles to other resource held by the caller must be closed
7223 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7224 *****************************************************/
7225 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7228 TRACE("(%p) : Adding Resource %p\n", This, resource);
7229 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7232 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7235 TRACE("(%p) : Removing resource %p\n", This, resource);
7237 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7241 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7243 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7246 TRACE("(%p) : resource %p\n", This, resource);
7248 context_resource_released(iface, resource, type);
7251 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7252 case WINED3DRTYPE_SURFACE: {
7255 /* Cleanup any FBO attachments if d3d is enabled */
7256 if(This->d3d_initialized) {
7257 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7258 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7260 TRACE("Last active render target destroyed\n");
7261 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7262 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7263 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7264 * and the lastActiveRenderTarget member shouldn't matter
7267 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7268 TRACE("Activating primary back buffer\n");
7269 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7270 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7271 /* Single buffering environment */
7272 TRACE("Activating primary front buffer\n");
7273 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7275 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7276 /* Implicit render target destroyed, that means the device is being destroyed
7277 * whatever we set here, it shouldn't matter
7279 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7282 /* May happen during ddraw uninitialization */
7283 TRACE("Render target set, but swapchain does not exist!\n");
7284 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7288 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7289 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7290 This->render_targets[i] = NULL;
7293 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7294 This->stencilBufferTarget = NULL;
7300 case WINED3DRTYPE_TEXTURE:
7301 case WINED3DRTYPE_CUBETEXTURE:
7302 case WINED3DRTYPE_VOLUMETEXTURE:
7303 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7304 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7305 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7306 This->stateBlock->textures[counter] = NULL;
7308 if (This->updateStateBlock != This->stateBlock ){
7309 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7310 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7311 This->updateStateBlock->textures[counter] = NULL;
7316 case WINED3DRTYPE_VOLUME:
7317 /* TODO: nothing really? */
7319 case WINED3DRTYPE_VERTEXBUFFER:
7320 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7323 TRACE("Cleaning up stream pointers\n");
7325 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7326 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7327 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7329 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7330 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7331 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7332 This->updateStateBlock->streamSource[streamNumber] = 0;
7333 /* Set changed flag? */
7336 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) */
7337 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7338 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7339 This->stateBlock->streamSource[streamNumber] = 0;
7345 case WINED3DRTYPE_INDEXBUFFER:
7346 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7347 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7348 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7349 This->updateStateBlock->pIndexData = NULL;
7352 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7353 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7354 This->stateBlock->pIndexData = NULL;
7360 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7365 /* Remove the resource from the resourceStore */
7366 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7368 TRACE("Resource released\n");
7372 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7374 IWineD3DResourceImpl *resource, *cursor;
7376 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7378 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7379 TRACE("enumerating resource %p\n", resource);
7380 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7381 ret = pCallback((IWineD3DResource *) resource, pData);
7382 if(ret == S_FALSE) {
7383 TRACE("Canceling enumeration\n");
7390 /**********************************************************
7391 * IWineD3DDevice VTbl follows
7392 **********************************************************/
7394 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7396 /*** IUnknown methods ***/
7397 IWineD3DDeviceImpl_QueryInterface,
7398 IWineD3DDeviceImpl_AddRef,
7399 IWineD3DDeviceImpl_Release,
7400 /*** IWineD3DDevice methods ***/
7401 IWineD3DDeviceImpl_GetParent,
7402 /*** Creation methods**/
7403 IWineD3DDeviceImpl_CreateVertexBuffer,
7404 IWineD3DDeviceImpl_CreateIndexBuffer,
7405 IWineD3DDeviceImpl_CreateStateBlock,
7406 IWineD3DDeviceImpl_CreateSurface,
7407 IWineD3DDeviceImpl_CreateTexture,
7408 IWineD3DDeviceImpl_CreateVolumeTexture,
7409 IWineD3DDeviceImpl_CreateVolume,
7410 IWineD3DDeviceImpl_CreateCubeTexture,
7411 IWineD3DDeviceImpl_CreateQuery,
7412 IWineD3DDeviceImpl_CreateSwapChain,
7413 IWineD3DDeviceImpl_CreateVertexDeclaration,
7414 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7415 IWineD3DDeviceImpl_CreateVertexShader,
7416 IWineD3DDeviceImpl_CreatePixelShader,
7417 IWineD3DDeviceImpl_CreatePalette,
7418 /*** Odd functions **/
7419 IWineD3DDeviceImpl_Init3D,
7420 IWineD3DDeviceImpl_InitGDI,
7421 IWineD3DDeviceImpl_Uninit3D,
7422 IWineD3DDeviceImpl_UninitGDI,
7423 IWineD3DDeviceImpl_SetMultithreaded,
7424 IWineD3DDeviceImpl_EvictManagedResources,
7425 IWineD3DDeviceImpl_GetAvailableTextureMem,
7426 IWineD3DDeviceImpl_GetBackBuffer,
7427 IWineD3DDeviceImpl_GetCreationParameters,
7428 IWineD3DDeviceImpl_GetDeviceCaps,
7429 IWineD3DDeviceImpl_GetDirect3D,
7430 IWineD3DDeviceImpl_GetDisplayMode,
7431 IWineD3DDeviceImpl_SetDisplayMode,
7432 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7433 IWineD3DDeviceImpl_GetRasterStatus,
7434 IWineD3DDeviceImpl_GetSwapChain,
7435 IWineD3DDeviceImpl_Reset,
7436 IWineD3DDeviceImpl_SetDialogBoxMode,
7437 IWineD3DDeviceImpl_SetCursorProperties,
7438 IWineD3DDeviceImpl_SetCursorPosition,
7439 IWineD3DDeviceImpl_ShowCursor,
7440 IWineD3DDeviceImpl_TestCooperativeLevel,
7441 /*** Getters and setters **/
7442 IWineD3DDeviceImpl_SetClipPlane,
7443 IWineD3DDeviceImpl_GetClipPlane,
7444 IWineD3DDeviceImpl_SetClipStatus,
7445 IWineD3DDeviceImpl_GetClipStatus,
7446 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7447 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7448 IWineD3DDeviceImpl_SetDepthStencilSurface,
7449 IWineD3DDeviceImpl_GetDepthStencilSurface,
7450 IWineD3DDeviceImpl_SetGammaRamp,
7451 IWineD3DDeviceImpl_GetGammaRamp,
7452 IWineD3DDeviceImpl_SetIndices,
7453 IWineD3DDeviceImpl_GetIndices,
7454 IWineD3DDeviceImpl_SetBaseVertexIndex,
7455 IWineD3DDeviceImpl_GetBaseVertexIndex,
7456 IWineD3DDeviceImpl_SetLight,
7457 IWineD3DDeviceImpl_GetLight,
7458 IWineD3DDeviceImpl_SetLightEnable,
7459 IWineD3DDeviceImpl_GetLightEnable,
7460 IWineD3DDeviceImpl_SetMaterial,
7461 IWineD3DDeviceImpl_GetMaterial,
7462 IWineD3DDeviceImpl_SetNPatchMode,
7463 IWineD3DDeviceImpl_GetNPatchMode,
7464 IWineD3DDeviceImpl_SetPaletteEntries,
7465 IWineD3DDeviceImpl_GetPaletteEntries,
7466 IWineD3DDeviceImpl_SetPixelShader,
7467 IWineD3DDeviceImpl_GetPixelShader,
7468 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7469 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7470 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7471 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7472 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7473 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7474 IWineD3DDeviceImpl_SetRenderState,
7475 IWineD3DDeviceImpl_GetRenderState,
7476 IWineD3DDeviceImpl_SetRenderTarget,
7477 IWineD3DDeviceImpl_GetRenderTarget,
7478 IWineD3DDeviceImpl_SetFrontBackBuffers,
7479 IWineD3DDeviceImpl_SetSamplerState,
7480 IWineD3DDeviceImpl_GetSamplerState,
7481 IWineD3DDeviceImpl_SetScissorRect,
7482 IWineD3DDeviceImpl_GetScissorRect,
7483 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7484 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7485 IWineD3DDeviceImpl_SetStreamSource,
7486 IWineD3DDeviceImpl_GetStreamSource,
7487 IWineD3DDeviceImpl_SetStreamSourceFreq,
7488 IWineD3DDeviceImpl_GetStreamSourceFreq,
7489 IWineD3DDeviceImpl_SetTexture,
7490 IWineD3DDeviceImpl_GetTexture,
7491 IWineD3DDeviceImpl_SetTextureStageState,
7492 IWineD3DDeviceImpl_GetTextureStageState,
7493 IWineD3DDeviceImpl_SetTransform,
7494 IWineD3DDeviceImpl_GetTransform,
7495 IWineD3DDeviceImpl_SetVertexDeclaration,
7496 IWineD3DDeviceImpl_GetVertexDeclaration,
7497 IWineD3DDeviceImpl_SetVertexShader,
7498 IWineD3DDeviceImpl_GetVertexShader,
7499 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7500 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7501 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7502 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7503 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7504 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7505 IWineD3DDeviceImpl_SetViewport,
7506 IWineD3DDeviceImpl_GetViewport,
7507 IWineD3DDeviceImpl_MultiplyTransform,
7508 IWineD3DDeviceImpl_ValidateDevice,
7509 IWineD3DDeviceImpl_ProcessVertices,
7510 /*** State block ***/
7511 IWineD3DDeviceImpl_BeginStateBlock,
7512 IWineD3DDeviceImpl_EndStateBlock,
7513 /*** Scene management ***/
7514 IWineD3DDeviceImpl_BeginScene,
7515 IWineD3DDeviceImpl_EndScene,
7516 IWineD3DDeviceImpl_Present,
7517 IWineD3DDeviceImpl_Clear,
7519 IWineD3DDeviceImpl_DrawPrimitive,
7520 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7521 IWineD3DDeviceImpl_DrawPrimitiveUP,
7522 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7523 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7524 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7525 IWineD3DDeviceImpl_DrawRectPatch,
7526 IWineD3DDeviceImpl_DrawTriPatch,
7527 IWineD3DDeviceImpl_DeletePatch,
7528 IWineD3DDeviceImpl_ColorFill,
7529 IWineD3DDeviceImpl_UpdateTexture,
7530 IWineD3DDeviceImpl_UpdateSurface,
7531 IWineD3DDeviceImpl_GetFrontBufferData,
7532 /*** object tracking ***/
7533 IWineD3DDeviceImpl_ResourceReleased,
7534 IWineD3DDeviceImpl_EnumResources
7537 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7538 WINED3DRS_ALPHABLENDENABLE ,
7539 WINED3DRS_ALPHAFUNC ,
7540 WINED3DRS_ALPHAREF ,
7541 WINED3DRS_ALPHATESTENABLE ,
7543 WINED3DRS_COLORWRITEENABLE ,
7544 WINED3DRS_DESTBLEND ,
7545 WINED3DRS_DITHERENABLE ,
7546 WINED3DRS_FILLMODE ,
7547 WINED3DRS_FOGDENSITY ,
7549 WINED3DRS_FOGSTART ,
7550 WINED3DRS_LASTPIXEL ,
7551 WINED3DRS_SHADEMODE ,
7552 WINED3DRS_SRCBLEND ,
7553 WINED3DRS_STENCILENABLE ,
7554 WINED3DRS_STENCILFAIL ,
7555 WINED3DRS_STENCILFUNC ,
7556 WINED3DRS_STENCILMASK ,
7557 WINED3DRS_STENCILPASS ,
7558 WINED3DRS_STENCILREF ,
7559 WINED3DRS_STENCILWRITEMASK ,
7560 WINED3DRS_STENCILZFAIL ,
7561 WINED3DRS_TEXTUREFACTOR ,
7572 WINED3DRS_ZWRITEENABLE
7575 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7576 WINED3DTSS_ALPHAARG0 ,
7577 WINED3DTSS_ALPHAARG1 ,
7578 WINED3DTSS_ALPHAARG2 ,
7579 WINED3DTSS_ALPHAOP ,
7580 WINED3DTSS_BUMPENVLOFFSET ,
7581 WINED3DTSS_BUMPENVLSCALE ,
7582 WINED3DTSS_BUMPENVMAT00 ,
7583 WINED3DTSS_BUMPENVMAT01 ,
7584 WINED3DTSS_BUMPENVMAT10 ,
7585 WINED3DTSS_BUMPENVMAT11 ,
7586 WINED3DTSS_COLORARG0 ,
7587 WINED3DTSS_COLORARG1 ,
7588 WINED3DTSS_COLORARG2 ,
7589 WINED3DTSS_COLOROP ,
7590 WINED3DTSS_RESULTARG ,
7591 WINED3DTSS_TEXCOORDINDEX ,
7592 WINED3DTSS_TEXTURETRANSFORMFLAGS
7595 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7596 WINED3DSAMP_ADDRESSU ,
7597 WINED3DSAMP_ADDRESSV ,
7598 WINED3DSAMP_ADDRESSW ,
7599 WINED3DSAMP_BORDERCOLOR ,
7600 WINED3DSAMP_MAGFILTER ,
7601 WINED3DSAMP_MINFILTER ,
7602 WINED3DSAMP_MIPFILTER ,
7603 WINED3DSAMP_MIPMAPLODBIAS ,
7604 WINED3DSAMP_MAXMIPLEVEL ,
7605 WINED3DSAMP_MAXANISOTROPY ,
7606 WINED3DSAMP_SRGBTEXTURE ,
7607 WINED3DSAMP_ELEMENTINDEX
7610 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7612 WINED3DRS_AMBIENTMATERIALSOURCE ,
7613 WINED3DRS_CLIPPING ,
7614 WINED3DRS_CLIPPLANEENABLE ,
7615 WINED3DRS_COLORVERTEX ,
7616 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7617 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7618 WINED3DRS_FOGDENSITY ,
7620 WINED3DRS_FOGSTART ,
7621 WINED3DRS_FOGTABLEMODE ,
7622 WINED3DRS_FOGVERTEXMODE ,
7623 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7624 WINED3DRS_LIGHTING ,
7625 WINED3DRS_LOCALVIEWER ,
7626 WINED3DRS_MULTISAMPLEANTIALIAS ,
7627 WINED3DRS_MULTISAMPLEMASK ,
7628 WINED3DRS_NORMALIZENORMALS ,
7629 WINED3DRS_PATCHEDGESTYLE ,
7630 WINED3DRS_POINTSCALE_A ,
7631 WINED3DRS_POINTSCALE_B ,
7632 WINED3DRS_POINTSCALE_C ,
7633 WINED3DRS_POINTSCALEENABLE ,
7634 WINED3DRS_POINTSIZE ,
7635 WINED3DRS_POINTSIZE_MAX ,
7636 WINED3DRS_POINTSIZE_MIN ,
7637 WINED3DRS_POINTSPRITEENABLE ,
7638 WINED3DRS_RANGEFOGENABLE ,
7639 WINED3DRS_SPECULARMATERIALSOURCE ,
7640 WINED3DRS_TWEENFACTOR ,
7641 WINED3DRS_VERTEXBLEND ,
7642 WINED3DRS_CULLMODE ,
7646 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7647 WINED3DTSS_TEXCOORDINDEX ,
7648 WINED3DTSS_TEXTURETRANSFORMFLAGS
7651 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7652 WINED3DSAMP_DMAPOFFSET
7655 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7656 DWORD rep = This->StateTable[state].representative;
7660 WineD3DContext *context;
7663 for(i = 0; i < This->numContexts; i++) {
7664 context = This->contexts[i];
7665 if(isStateDirty(context, rep)) continue;
7667 context->dirtyArray[context->numDirtyEntries++] = rep;
7670 context->isStateDirty[idx] |= (1 << shift);
7674 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7675 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7676 /* The drawable size of a pbuffer render target is the current pbuffer size
7678 *width = dev->pbufferWidth;
7679 *height = dev->pbufferHeight;
7682 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7683 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7685 *width = This->pow2Width;
7686 *height = This->pow2Height;
7689 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7690 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7691 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7692 * current context's drawable, which is the size of the back buffer of the swapchain
7693 * the active context belongs to. The back buffer of the swapchain is stored as the
7694 * surface the context belongs to.
7696 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7697 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;