2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This->resources)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
182 dumpResources(&This->resources);
185 if(This->contexts) ERR("Context array not freed!\n");
186 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
187 This->haveHardwareCursor = FALSE;
189 IWineD3D_Release(This->wineD3D);
190 This->wineD3D = NULL;
191 HeapFree(GetProcessHeap(), 0, This);
192 TRACE("Freed device %p\n", This);
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 *pParent = This->parent;
204 IUnknown_AddRef(This->parent);
208 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
209 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
212 IWineD3DVertexBufferImpl *object;
213 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
214 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer = NULL;
220 return WINED3DERR_INVALIDCALL;
221 } else if(Pool == WINED3DPOOL_SCRATCH) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer = NULL;
227 return WINED3DERR_INVALIDCALL;
230 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
232 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
233 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion <= 7 && conv) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
262 object->Flags |= VBFLAG_CREATEVBO;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
268 GLenum error, glUsage;
269 TRACE("Creating VBO for Index Buffer %p\n", object);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR || object->vbo == 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage = GL_STATIC_DRAW_ARB;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
301 error = glGetError();
302 if(error != GL_NO_ERROR) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
307 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
317 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
318 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
319 HANDLE *sharedHandle, IUnknown *parent) {
320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
321 IWineD3DIndexBufferImpl *object;
322 TRACE("(%p) Creating index buffer\n", This);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
327 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 CreateIndexBufferVBO(This, object);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
332 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
333 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
338 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DStateBlockImpl *object;
345 D3DCREATEOBJECTINSTANCE(object, StateBlock)
346 object->blockType = Type;
348 for(i = 0; i < LIGHTMAP_SIZE; i++) {
349 list_init(&object->lightMap[i]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type == WINED3DSBT_INIT) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
360 temp_result = allocate_shader_constants(object);
361 if (WINED3D_OK != temp_result)
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This->stateBlock != NULL)
366 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
368 memset(object->streamFreq, 1, sizeof(object->streamFreq));
370 /* Reset the ref and type after kludging it */
371 object->wineD3DDevice = This;
373 object->blockType = Type;
375 TRACE("Updating changed flags appropriate for type %d\n", Type);
377 if (Type == WINED3DSBT_ALL) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
382 /* Lights are not part of the changed / set structure */
383 for(j = 0; j < LIGHTMAP_SIZE; j++) {
385 LIST_FOR_EACH(e, &object->lightMap[j]) {
386 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
387 light->changed = TRUE;
388 light->enabledChanged = TRUE;
391 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
392 object->contained_render_states[j - 1] = j;
394 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
397 object->contained_transform_states[j - 1] = j;
399 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
400 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
401 object->contained_vs_consts_f[j] = j;
403 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_vs_consts_i[j] = j;
407 object->num_contained_vs_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_vs_consts_b[j] = j;
411 object->num_contained_vs_consts_b = MAX_CONST_B;
412 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
413 object->contained_ps_consts_f[j] = j;
415 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
416 for(j = 0; j < MAX_CONST_I; j++) {
417 object->contained_ps_consts_i[j] = j;
419 object->num_contained_ps_consts_i = MAX_CONST_I;
420 for(j = 0; j < MAX_CONST_B; j++) {
421 object->contained_ps_consts_b[j] = j;
423 object->num_contained_ps_consts_b = MAX_CONST_B;
424 for(i = 0; i < MAX_TEXTURES; i++) {
425 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
426 object->contained_tss_states[object->num_contained_tss_states].stage = i;
427 object->contained_tss_states[object->num_contained_tss_states].state = j;
428 object->num_contained_tss_states++;
431 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
432 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
433 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
434 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
435 object->num_contained_sampler_states++;
439 for(i = 0; i < MAX_STREAMS; i++) {
440 if(object->streamSource[i]) {
441 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
444 if(object->pIndexData) {
445 IWineD3DIndexBuffer_AddRef(object->pIndexData);
447 if(object->vertexShader) {
448 IWineD3DVertexShader_AddRef(object->vertexShader);
450 if(object->pixelShader) {
451 IWineD3DPixelShader_AddRef(object->pixelShader);
454 } else if (Type == WINED3DSBT_PIXELSTATE) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
459 object->changed.pixelShader = TRUE;
461 /* Pixel Shader Constants */
462 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
463 object->contained_ps_consts_f[i] = i;
464 object->changed.pixelShaderConstantsF[i] = TRUE;
466 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
467 for (i = 0; i < MAX_CONST_B; ++i) {
468 object->contained_ps_consts_b[i] = i;
469 object->changed.pixelShaderConstantsB[i] = TRUE;
471 object->num_contained_ps_consts_b = MAX_CONST_B;
472 for (i = 0; i < MAX_CONST_I; ++i) {
473 object->contained_ps_consts_i[i] = i;
474 object->changed.pixelShaderConstantsI[i] = TRUE;
476 object->num_contained_ps_consts_i = MAX_CONST_I;
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
479 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
480 object->contained_render_states[i] = SavedPixelStates_R[i];
482 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
483 for (j = 0; j < MAX_TEXTURES; j++) {
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
485 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
486 object->contained_tss_states[object->num_contained_tss_states].stage = j;
487 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
488 object->num_contained_tss_states++;
491 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
492 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
493 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
494 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
495 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
496 object->num_contained_sampler_states++;
499 if(object->pixelShader) {
500 IWineD3DPixelShader_AddRef(object->pixelShader);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i = 0; i < MAX_STREAMS; i++) {
507 object->streamSource[i] = NULL;
509 object->pIndexData = NULL;
510 object->vertexShader = NULL;
512 } else if (Type == WINED3DSBT_VERTEXSTATE) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
517 object->changed.vertexShader = TRUE;
519 /* Vertex Shader Constants */
520 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
521 object->changed.vertexShaderConstantsF[i] = TRUE;
522 object->contained_vs_consts_f[i] = i;
524 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
525 for (i = 0; i < MAX_CONST_B; ++i) {
526 object->changed.vertexShaderConstantsB[i] = TRUE;
527 object->contained_vs_consts_b[i] = i;
529 object->num_contained_vs_consts_b = MAX_CONST_B;
530 for (i = 0; i < MAX_CONST_I; ++i) {
531 object->changed.vertexShaderConstantsI[i] = TRUE;
532 object->contained_vs_consts_i[i] = i;
534 object->num_contained_vs_consts_i = MAX_CONST_I;
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
536 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 object->contained_render_states[i] = SavedVertexStates_R[i];
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
545 object->num_contained_tss_states++;
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
551 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
552 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
553 object->num_contained_sampler_states++;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 for(i = 0; i < MAX_STREAMS; i++) {
567 if(object->streamSource[i]) {
568 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
571 if(object->vertexShader) {
572 IWineD3DVertexShader_AddRef(object->vertexShader);
574 object->pIndexData = NULL;
575 object->pixelShader = NULL;
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
584 /* ************************************
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
593 ******************************** */
595 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size = 1;
599 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
600 TRACE("(%p) Create surface\n",This);
602 /** FIXME: Check ranges on the inputs are valid
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
610 *******************************/
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality > 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
626 MultisampleQuality=0;
629 /** FIXME: Check that the format is supported
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
636 *********************************/
637 if (WINED3DFMT_UNKNOWN == Format) {
639 } else if (Format == WINED3DFMT_DXT1) {
640 /* DXT1 is half byte per pixel */
641 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
643 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
644 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
645 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
647 /* The pitch is a multiple of 4 bytes */
648 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
652 /** Create and initialise the surface resource **/
653 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
654 /* "Standalone" surface */
655 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
657 object->currentDesc.Width = Width;
658 object->currentDesc.Height = Height;
659 object->currentDesc.MultiSampleType = MultiSample;
660 object->currentDesc.MultiSampleQuality = MultisampleQuality;
661 object->glDescription.level = Level;
664 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
665 object->Flags |= Discard ? SFLAG_DISCARD : 0;
666 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
667 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
670 if (WINED3DFMT_UNKNOWN != Format) {
671 object->bytesPerPixel = tableEntry->bpp;
673 object->bytesPerPixel = 0;
676 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
678 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
680 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
681 * this function is too deep to need to care about things like this.
682 * Levels need to be checked too, and possibly Type since they all affect what can be done.
683 * ****************************************/
685 case WINED3DPOOL_SCRATCH:
687 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
688 "which are mutually exclusive, setting lockable to TRUE\n");
691 case WINED3DPOOL_SYSTEMMEM:
692 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
693 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
694 case WINED3DPOOL_MANAGED:
695 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
696 "Usage of DYNAMIC which are mutually exclusive, not doing "
697 "anything just telling you.\n");
699 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
700 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
701 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
702 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 FIXME("(%p) Unknown pool %d\n", This, Pool);
709 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
710 FIXME("Trying to create a render target that isn't in the default pool\n");
713 /* mark the texture as dirty so that it gets loaded first time around*/
714 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
715 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
716 This, Width, Height, Format, debug_d3dformat(Format),
717 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
719 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
720 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
721 This->ddraw_primary = (IWineD3DSurface *) object;
723 /* Look at the implementation and set the correct Vtable */
726 /* Check if a 3D adapter is available when creating gl surfaces */
728 ERR("OpenGL surfaces are not available without opengl\n");
729 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
730 HeapFree(GetProcessHeap(), 0, object);
731 return WINED3DERR_NOTAVAILABLE;
736 object->lpVtbl = &IWineGDISurface_Vtbl;
740 /* To be sure to catch this */
741 ERR("Unknown requested surface implementation %d!\n", Impl);
742 IWineD3DSurface_Release((IWineD3DSurface *) object);
743 return WINED3DERR_INVALIDCALL;
746 list_init(&object->renderbuffers);
748 /* Call the private setup routine */
749 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
753 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
754 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
755 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
756 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
759 IWineD3DTextureImpl *object;
764 unsigned int pow2Width;
765 unsigned int pow2Height;
766 const GlPixelFormatDesc *glDesc;
767 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
769 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
770 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
771 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
773 /* TODO: It should only be possible to create textures for formats
774 that are reported as supported */
775 if (WINED3DFMT_UNKNOWN >= Format) {
776 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
777 return WINED3DERR_INVALIDCALL;
780 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
781 D3DINITIALIZEBASETEXTURE(object->baseTexture);
782 object->width = Width;
783 object->height = Height;
785 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
786 object->baseTexture.minMipLookup = &minMipLookup;
787 object->baseTexture.magLookup = &magLookup;
789 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
790 object->baseTexture.magLookup = &magLookup_noFilter;
793 /** Non-power2 support **/
794 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
798 /* Find the nearest pow2 match */
799 pow2Width = pow2Height = 1;
800 while (pow2Width < Width) pow2Width <<= 1;
801 while (pow2Height < Height) pow2Height <<= 1;
803 if(pow2Width != Width || pow2Height != Height) {
805 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
806 HeapFree(GetProcessHeap(), 0, object);
808 return WINED3DERR_INVALIDCALL;
815 /** FIXME: add support for real non-power-two if it's provided by the video card **/
816 /* Precalculated scaling for 'faked' non power of two texture coords.
817 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
818 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
819 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
821 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
822 (Width != pow2Width || Height != pow2Height) &&
823 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
825 object->baseTexture.pow2Matrix[0] = (float)Width;
826 object->baseTexture.pow2Matrix[5] = (float)Height;
827 object->baseTexture.pow2Matrix[10] = 1.0;
828 object->baseTexture.pow2Matrix[15] = 1.0;
829 object->target = GL_TEXTURE_RECTANGLE_ARB;
831 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
832 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
833 object->baseTexture.pow2Matrix[10] = 1.0;
834 object->baseTexture.pow2Matrix[15] = 1.0;
835 object->target = GL_TEXTURE_2D;
837 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
839 /* Calculate levels for mip mapping */
840 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
841 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
842 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
843 return WINED3DERR_INVALIDCALL;
846 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
847 return WINED3DERR_INVALIDCALL;
849 object->baseTexture.levels = 1;
850 } else if (Levels == 0) {
851 TRACE("calculating levels %d\n", object->baseTexture.levels);
852 object->baseTexture.levels++;
855 while (tmpW > 1 || tmpH > 1) {
856 tmpW = max(1, tmpW >> 1);
857 tmpH = max(1, tmpH >> 1);
858 object->baseTexture.levels++;
860 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
863 /* Generate all the surfaces */
866 for (i = 0; i < object->baseTexture.levels; i++)
868 /* use the callback to create the texture surface */
869 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
870 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
871 FIXME("Failed to create surface %p\n", object);
873 object->surfaces[i] = NULL;
874 IWineD3DTexture_Release((IWineD3DTexture *)object);
880 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
881 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
882 /* calculate the next mipmap level */
883 tmpW = max(1, tmpW >> 1);
884 tmpH = max(1, tmpH >> 1);
886 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
888 TRACE("(%p) : Created texture %p\n", This, object);
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
893 UINT Width, UINT Height, UINT Depth,
894 UINT Levels, DWORD Usage,
895 WINED3DFORMAT Format, WINED3DPOOL Pool,
896 IWineD3DVolumeTexture **ppVolumeTexture,
897 HANDLE *pSharedHandle, IUnknown *parent,
898 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
901 IWineD3DVolumeTextureImpl *object;
906 const GlPixelFormatDesc *glDesc;
908 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
910 /* TODO: It should only be possible to create textures for formats
911 that are reported as supported */
912 if (WINED3DFMT_UNKNOWN >= Format) {
913 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
914 return WINED3DERR_INVALIDCALL;
916 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
917 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
918 return WINED3DERR_INVALIDCALL;
921 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
922 D3DINITIALIZEBASETEXTURE(object->baseTexture);
924 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
925 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
927 object->width = Width;
928 object->height = Height;
929 object->depth = Depth;
931 /* Is NP2 support for volumes needed? */
932 object->baseTexture.pow2Matrix[ 0] = 1.0;
933 object->baseTexture.pow2Matrix[ 5] = 1.0;
934 object->baseTexture.pow2Matrix[10] = 1.0;
935 object->baseTexture.pow2Matrix[15] = 1.0;
937 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
938 object->baseTexture.minMipLookup = &minMipLookup;
939 object->baseTexture.magLookup = &magLookup;
941 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
942 object->baseTexture.magLookup = &magLookup_noFilter;
945 /* Calculate levels for mip mapping */
946 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
947 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
948 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
949 return WINED3DERR_INVALIDCALL;
952 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
953 return WINED3DERR_INVALIDCALL;
956 } else if (Levels == 0) {
957 object->baseTexture.levels++;
961 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
962 tmpW = max(1, tmpW >> 1);
963 tmpH = max(1, tmpH >> 1);
964 tmpD = max(1, tmpD >> 1);
965 object->baseTexture.levels++;
967 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
970 /* Generate all the surfaces */
975 for (i = 0; i < object->baseTexture.levels; i++)
978 /* Create the volume */
979 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
980 &object->volumes[i], pSharedHandle);
983 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
984 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
985 *ppVolumeTexture = NULL;
989 /* Set its container to this object */
990 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
992 /* calculate the next mipmap level */
993 tmpW = max(1, tmpW >> 1);
994 tmpH = max(1, tmpH >> 1);
995 tmpD = max(1, tmpD >> 1);
997 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
999 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1000 TRACE("(%p) : Created volume texture %p\n", This, object);
1004 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1005 UINT Width, UINT Height, UINT Depth,
1007 WINED3DFORMAT Format, WINED3DPOOL Pool,
1008 IWineD3DVolume** ppVolume,
1009 HANDLE* pSharedHandle, IUnknown *parent) {
1011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1012 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1013 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1015 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1016 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1017 return WINED3DERR_INVALIDCALL;
1020 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1022 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1023 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1025 object->currentDesc.Width = Width;
1026 object->currentDesc.Height = Height;
1027 object->currentDesc.Depth = Depth;
1028 object->bytesPerPixel = formatDesc->bpp;
1030 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1031 object->lockable = TRUE;
1032 object->locked = FALSE;
1033 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1034 object->dirty = TRUE;
1036 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1039 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1040 UINT Levels, DWORD Usage,
1041 WINED3DFORMAT Format, WINED3DPOOL Pool,
1042 IWineD3DCubeTexture **ppCubeTexture,
1043 HANDLE *pSharedHandle, IUnknown *parent,
1044 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1047 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1051 unsigned int pow2EdgeLength = EdgeLength;
1052 const GlPixelFormatDesc *glDesc;
1053 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1055 /* TODO: It should only be possible to create textures for formats
1056 that are reported as supported */
1057 if (WINED3DFMT_UNKNOWN >= Format) {
1058 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1059 return WINED3DERR_INVALIDCALL;
1062 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1063 WARN("(%p) : Tried to create not supported cube texture\n", This);
1064 return WINED3DERR_INVALIDCALL;
1067 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1068 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1070 TRACE("(%p) Create Cube Texture\n", This);
1072 /** Non-power2 support **/
1074 /* Find the nearest pow2 match */
1076 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1078 object->edgeLength = EdgeLength;
1079 /* TODO: support for native non-power 2 */
1080 /* Precalculated scaling for 'faked' non power of two texture coords */
1081 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1082 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1083 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[15] = 1.0;
1086 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1087 object->baseTexture.minMipLookup = &minMipLookup;
1088 object->baseTexture.magLookup = &magLookup;
1090 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1091 object->baseTexture.magLookup = &magLookup_noFilter;
1094 /* Calculate levels for mip mapping */
1095 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1096 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1097 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1098 HeapFree(GetProcessHeap(), 0, object);
1099 *ppCubeTexture = NULL;
1101 return WINED3DERR_INVALIDCALL;
1104 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1105 HeapFree(GetProcessHeap(), 0, object);
1106 *ppCubeTexture = NULL;
1108 return WINED3DERR_INVALIDCALL;
1111 } else if (Levels == 0) {
1112 object->baseTexture.levels++;
1115 tmpW = max(1, tmpW >> 1);
1116 object->baseTexture.levels++;
1118 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1121 /* Generate all the surfaces */
1123 for (i = 0; i < object->baseTexture.levels; i++) {
1125 /* Create the 6 faces */
1126 for (j = 0; j < 6; j++) {
1128 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1129 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1131 if(hr!= WINED3D_OK) {
1135 for (l = 0; l < j; l++) {
1136 IWineD3DSurface_Release(object->surfaces[l][i]);
1138 for (k = 0; k < i; k++) {
1139 for (l = 0; l < 6; l++) {
1140 IWineD3DSurface_Release(object->surfaces[l][k]);
1144 FIXME("(%p) Failed to create surface\n",object);
1145 HeapFree(GetProcessHeap(),0,object);
1146 *ppCubeTexture = NULL;
1149 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1150 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1152 tmpW = max(1, tmpW >> 1);
1154 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1156 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1157 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1161 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1163 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1164 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1165 const IWineD3DQueryVtbl *vtable;
1167 /* Just a check to see if we support this type of query */
1169 case WINED3DQUERYTYPE_OCCLUSION:
1170 TRACE("(%p) occlusion query\n", This);
1171 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1174 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1176 vtable = &IWineD3DOcclusionQuery_Vtbl;
1179 case WINED3DQUERYTYPE_EVENT:
1180 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1181 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1182 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1184 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1186 vtable = &IWineD3DEventQuery_Vtbl;
1190 case WINED3DQUERYTYPE_VCACHE:
1191 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1192 case WINED3DQUERYTYPE_VERTEXSTATS:
1193 case WINED3DQUERYTYPE_TIMESTAMP:
1194 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1195 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1196 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1197 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1198 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1199 case WINED3DQUERYTYPE_PIXELTIMINGS:
1200 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1201 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1203 /* Use the base Query vtable until we have a special one for each query */
1204 vtable = &IWineD3DQuery_Vtbl;
1205 FIXME("(%p) Unhandled query type %d\n", This, Type);
1207 if(NULL == ppQuery || hr != WINED3D_OK) {
1211 D3DCREATEOBJECTINSTANCE(object, Query)
1212 object->lpVtbl = vtable;
1213 object->type = Type;
1214 object->state = QUERY_CREATED;
1215 /* allocated the 'extended' data based on the type of query requested */
1217 case WINED3DQUERYTYPE_OCCLUSION:
1218 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1219 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1221 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1222 TRACE("(%p) Allocating data for an occlusion query\n", This);
1223 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1226 case WINED3DQUERYTYPE_EVENT:
1227 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1228 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1230 if(GL_SUPPORT(APPLE_FENCE)) {
1231 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1232 checkGLcall("glGenFencesAPPLE");
1233 } else if(GL_SUPPORT(NV_FENCE)) {
1234 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1235 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 WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
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 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1322 ShowWindow(window, SW_NORMAL);
1325 /*****************************************************************************
1326 * IWineD3DDeviceImpl_RestoreWindow
1328 * Helper function that restores a windows' properties when taking it out
1329 * of fullscreen mode
1332 * iface: Pointer to the IWineD3DDevice interface
1333 * window: Window to setup
1335 *****************************************************************************/
1336 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1338 LONG style, exStyle;
1340 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1341 * switch, do nothing
1343 if (!This->style && !This->exStyle) return;
1345 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1346 This, window, This->style, This->exStyle);
1348 style = GetWindowLongW(window, GWL_STYLE);
1349 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1351 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1352 * Some applications change it before calling Reset() when switching between windowed and
1353 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1355 if(style == fullscreen_style(This->style) &&
1356 exStyle == fullscreen_style(This->exStyle)) {
1357 SetWindowLongW(window, GWL_STYLE, This->style);
1358 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1361 /* Delete the old values */
1365 /* Inform the window about the update */
1366 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1367 0, 0, 0, 0, /* Pos, Size, ignored */
1368 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1371 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1372 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1374 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1375 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1379 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1380 HRESULT hr = WINED3D_OK;
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)
1403 /*********************
1404 * Lookup the window Handle and the relating X window handle
1405 ********************/
1407 /* Setup hwnd we are using, plus which display this equates to */
1408 object->win_handle = pPresentationParameters->hDeviceWindow;
1409 if (!object->win_handle) {
1410 object->win_handle = This->createParms.hFocusWindow;
1412 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1414 hDc = GetDC(object->win_handle);
1415 TRACE("Using hDc %p\n", hDc);
1418 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1419 return WINED3DERR_NOTAVAILABLE;
1422 /* Get info on the current display setup */
1423 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1424 object->orig_width = Mode.Width;
1425 object->orig_height = Mode.Height;
1426 object->orig_fmt = Mode.Format;
1427 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1429 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1430 * then the corresponding dimension of the client area of the hDeviceWindow
1431 * (or the focus window, if hDeviceWindow is NULL) is taken.
1432 **********************/
1434 if (pPresentationParameters->Windowed &&
1435 ((pPresentationParameters->BackBufferWidth == 0) ||
1436 (pPresentationParameters->BackBufferHeight == 0) ||
1437 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1440 GetClientRect(object->win_handle, &Rect);
1442 if (pPresentationParameters->BackBufferWidth == 0) {
1443 pPresentationParameters->BackBufferWidth = Rect.right;
1444 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1446 if (pPresentationParameters->BackBufferHeight == 0) {
1447 pPresentationParameters->BackBufferHeight = Rect.bottom;
1448 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1450 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1451 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1452 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1456 /* Put the correct figures in the presentation parameters */
1457 TRACE("Copying across presentation parameters\n");
1458 object->presentParms = *pPresentationParameters;
1460 TRACE("calling rendertarget CB\n");
1461 hr = D3DCB_CreateRenderTarget(This->parent,
1463 object->presentParms.BackBufferWidth,
1464 object->presentParms.BackBufferHeight,
1465 object->presentParms.BackBufferFormat,
1466 object->presentParms.MultiSampleType,
1467 object->presentParms.MultiSampleQuality,
1468 TRUE /* Lockable */,
1469 &object->frontBuffer,
1470 NULL /* pShared (always null)*/);
1471 if (object->frontBuffer != NULL) {
1472 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1473 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1475 ERR("Failed to create the front buffer\n");
1479 /*********************
1480 * Windowed / Fullscreen
1481 *******************/
1484 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1485 * so we should really check to see if there is a fullscreen swapchain already
1486 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1487 **************************************/
1489 if (!pPresentationParameters->Windowed) {
1490 WINED3DDISPLAYMODE mode;
1493 /* Change the display settings */
1494 mode.Width = pPresentationParameters->BackBufferWidth;
1495 mode.Height = pPresentationParameters->BackBufferHeight;
1496 mode.Format = pPresentationParameters->BackBufferFormat;
1497 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1499 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1500 displaymode_set = TRUE;
1501 IWineD3DDevice_SetFullscreen(iface, TRUE);
1505 * Create an opengl context for the display visual
1506 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1507 * use different properties after that point in time. FIXME: How to handle when requested format
1508 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1509 * it chooses is identical to the one already being used!
1510 **********************************/
1511 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1513 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1514 if(!object->context)
1515 return E_OUTOFMEMORY;
1516 object->num_contexts = 1;
1518 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1519 if (!object->context[0]) {
1520 ERR("Failed to create a new context\n");
1521 hr = WINED3DERR_NOTAVAILABLE;
1524 TRACE("Context created (HWND=%p, glContext=%p)\n",
1525 object->win_handle, object->context[0]->glCtx);
1528 /*********************
1529 * Create the back, front and stencil buffers
1530 *******************/
1531 if(object->presentParms.BackBufferCount > 0) {
1534 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1535 if(!object->backBuffer) {
1536 ERR("Out of memory\n");
1541 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1542 TRACE("calling rendertarget CB\n");
1543 hr = D3DCB_CreateRenderTarget(This->parent,
1545 object->presentParms.BackBufferWidth,
1546 object->presentParms.BackBufferHeight,
1547 object->presentParms.BackBufferFormat,
1548 object->presentParms.MultiSampleType,
1549 object->presentParms.MultiSampleQuality,
1550 TRUE /* Lockable */,
1551 &object->backBuffer[i],
1552 NULL /* pShared (always null)*/);
1553 if(hr == WINED3D_OK && object->backBuffer[i]) {
1554 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1556 ERR("Cannot create new back buffer\n");
1560 glDrawBuffer(GL_BACK);
1561 checkGLcall("glDrawBuffer(GL_BACK)");
1565 object->backBuffer = NULL;
1567 /* Single buffering - draw to front buffer */
1569 glDrawBuffer(GL_FRONT);
1570 checkGLcall("glDrawBuffer(GL_FRONT)");
1574 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1575 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1576 TRACE("Creating depth stencil buffer\n");
1577 if (This->auto_depth_stencil_buffer == NULL ) {
1578 hr = D3DCB_CreateDepthStencil(This->parent,
1580 object->presentParms.BackBufferWidth,
1581 object->presentParms.BackBufferHeight,
1582 object->presentParms.AutoDepthStencilFormat,
1583 object->presentParms.MultiSampleType,
1584 object->presentParms.MultiSampleQuality,
1585 FALSE /* FIXME: Discard */,
1586 &This->auto_depth_stencil_buffer,
1587 NULL /* pShared (always null)*/ );
1588 if (This->auto_depth_stencil_buffer != NULL)
1589 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1592 /** TODO: A check on width, height and multisample types
1593 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1594 ****************************/
1595 object->wantsDepthStencilBuffer = TRUE;
1597 object->wantsDepthStencilBuffer = FALSE;
1600 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1602 TRACE("Created swapchain %p\n", object);
1603 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1607 if (displaymode_set) {
1611 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1614 /* Change the display settings */
1615 memset(&devmode, 0, sizeof(devmode));
1616 devmode.dmSize = sizeof(devmode);
1617 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1618 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1619 devmode.dmPelsWidth = object->orig_width;
1620 devmode.dmPelsHeight = object->orig_height;
1621 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1624 if (object->backBuffer) {
1626 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1627 if(object->backBuffer[i]) {
1628 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1629 IUnknown_Release(bufferParent); /* once for the get parent */
1630 if (IUnknown_Release(bufferParent) > 0) {
1631 FIXME("(%p) Something's still holding the back buffer\n",This);
1635 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1636 object->backBuffer = NULL;
1638 if(object->context[0])
1639 DestroyContext(This, object->context[0]);
1640 if(object->frontBuffer) {
1641 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1642 IUnknown_Release(bufferParent); /* once for the get parent */
1643 if (IUnknown_Release(bufferParent) > 0) {
1644 FIXME("(%p) Something's still holding the front buffer\n",This);
1647 HeapFree(GetProcessHeap(), 0, object);
1651 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1652 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1654 TRACE("(%p)\n", This);
1656 return This->NumberOfSwapChains;
1659 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1661 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1663 if(iSwapChain < This->NumberOfSwapChains) {
1664 *pSwapChain = This->swapchains[iSwapChain];
1665 IWineD3DSwapChain_AddRef(*pSwapChain);
1666 TRACE("(%p) returning %p\n", This, *pSwapChain);
1669 TRACE("Swapchain out of range\n");
1671 return WINED3DERR_INVALIDCALL;
1676 * Vertex Declaration
1678 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1679 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1681 IWineD3DVertexDeclarationImpl *object = NULL;
1682 HRESULT hr = WINED3D_OK;
1684 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1685 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1687 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1689 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1691 *ppVertexDeclaration = NULL;
1692 HeapFree(GetProcessHeap(), 0, object);
1698 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1699 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1701 unsigned int idx, idx2;
1702 unsigned int offset;
1703 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1704 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1705 BOOL has_blend_idx = has_blend &&
1706 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1707 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1708 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1709 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1710 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1711 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1712 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1714 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1715 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1717 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1718 WINED3DVERTEXELEMENT *elements = NULL;
1721 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1722 if (has_blend_idx) num_blends--;
1724 /* Compute declaration size */
1725 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1726 has_psize + has_diffuse + has_specular + num_textures + 1;
1728 /* convert the declaration */
1729 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1733 elements[size-1] = end_element;
1736 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1737 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1738 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1741 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1742 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1744 elements[idx].UsageIndex = 0;
1747 if (has_blend && (num_blends > 0)) {
1748 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1749 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1752 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1753 elements[idx].UsageIndex = 0;
1756 if (has_blend_idx) {
1757 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1758 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1759 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1760 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1761 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1764 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1765 elements[idx].UsageIndex = 0;
1769 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1770 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1771 elements[idx].UsageIndex = 0;
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1776 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1777 elements[idx].UsageIndex = 0;
1781 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1782 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1783 elements[idx].UsageIndex = 0;
1787 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1788 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1789 elements[idx].UsageIndex = 1;
1792 for (idx2 = 0; idx2 < num_textures; idx2++) {
1793 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1794 switch (numcoords) {
1795 case WINED3DFVF_TEXTUREFORMAT1:
1796 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1798 case WINED3DFVF_TEXTUREFORMAT2:
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1801 case WINED3DFVF_TEXTUREFORMAT3:
1802 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1804 case WINED3DFVF_TEXTUREFORMAT4:
1805 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1808 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1809 elements[idx].UsageIndex = idx2;
1813 /* Now compute offsets, and initialize the rest of the fields */
1814 for (idx = 0, offset = 0; idx < size-1; idx++) {
1815 elements[idx].Stream = 0;
1816 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1817 elements[idx].Offset = offset;
1818 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1821 *ppVertexElements = elements;
1825 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1826 WINED3DVERTEXELEMENT* elements = NULL;
1827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1831 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1832 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1834 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1835 HeapFree(GetProcessHeap(), 0, elements);
1836 if (hr != S_OK) return hr;
1841 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1843 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1844 HRESULT hr = WINED3D_OK;
1845 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1846 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1848 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1850 if (vertex_declaration) {
1851 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1854 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1856 if (WINED3D_OK != hr) {
1857 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1858 IWineD3DVertexShader_Release(*ppVertexShader);
1859 return WINED3DERR_INVALIDCALL;
1861 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1866 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1868 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1869 HRESULT hr = WINED3D_OK;
1871 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1872 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1873 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1874 if (WINED3D_OK == hr) {
1875 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1876 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1878 WARN("(%p) : Failed to create pixel shader\n", This);
1884 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1886 IWineD3DPaletteImpl *object;
1888 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1890 /* Create the new object */
1891 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1893 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1894 return E_OUTOFMEMORY;
1897 object->lpVtbl = &IWineD3DPalette_Vtbl;
1899 object->Flags = Flags;
1900 object->parent = Parent;
1901 object->wineD3DDevice = This;
1902 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1904 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1907 HeapFree( GetProcessHeap(), 0, object);
1908 return E_OUTOFMEMORY;
1911 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1913 IWineD3DPalette_Release((IWineD3DPalette *) object);
1917 *Palette = (IWineD3DPalette *) object;
1922 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1926 HDC dcb = NULL, dcs = NULL;
1927 WINEDDCOLORKEY colorkey;
1929 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1932 GetObjectA(hbm, sizeof(BITMAP), &bm);
1933 dcb = CreateCompatibleDC(NULL);
1935 SelectObject(dcb, hbm);
1939 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1940 * couldn't be loaded
1942 memset(&bm, 0, sizeof(bm));
1947 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1948 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1949 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1951 ERR("Wine logo requested, but failed to create surface\n");
1956 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1957 if(FAILED(hr)) goto out;
1958 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1959 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1961 colorkey.dwColorSpaceLowValue = 0;
1962 colorkey.dwColorSpaceHighValue = 0;
1963 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1965 /* Fill the surface with a white color to show that wined3d is there */
1966 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1979 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1981 /* Under DirectX you can have texture stage operations even if no texture is
1982 bound, whereas opengl will only do texture operations when a valid texture is
1983 bound. We emulate this by creating dummy textures and binding them to each
1984 texture stage, but disable all stages by default. Hence if a stage is enabled
1985 then the default texture will kick in until replaced by a SetTexture call */
1988 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1989 /* The dummy texture does not have client storage backing */
1990 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1991 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1993 for (i = 0; i < GL_LIMITS(textures); i++) {
1994 GLubyte white = 255;
1996 /* Make appropriate texture active */
1997 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1998 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1999 checkGLcall("glActiveTextureARB");
2001 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2004 /* Generate an opengl texture name */
2005 glGenTextures(1, &This->dummyTextureName[i]);
2006 checkGLcall("glGenTextures");
2007 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2009 /* Generate a dummy 2d texture (not using 1d because they cause many
2010 * DRI drivers fall back to sw) */
2011 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2012 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2013 checkGLcall("glBindTexture");
2015 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2016 checkGLcall("glTexImage2D");
2018 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2019 /* Reenable because if supported it is enabled by default */
2020 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2021 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2027 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2029 IWineD3DSwapChainImpl *swapchain = NULL;
2034 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2035 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2036 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2038 /* TODO: Test if OpenGL is compiled in and loaded */
2040 TRACE("(%p) : Creating stateblock\n", This);
2041 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2042 hr = IWineD3DDevice_CreateStateBlock(iface,
2044 (IWineD3DStateBlock **)&This->stateBlock,
2046 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2047 WARN("Failed to create stateblock\n");
2050 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2051 This->updateStateBlock = This->stateBlock;
2052 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2054 hr = allocate_shader_constants(This->updateStateBlock);
2055 if (WINED3D_OK != hr) {
2059 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2060 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2061 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2063 This->NumberOfPalettes = 1;
2064 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2065 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2066 ERR("Out of memory!\n");
2069 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2070 if(!This->palettes[0]) {
2071 ERR("Out of memory!\n");
2074 for (i = 0; i < 256; ++i) {
2075 This->palettes[0][i].peRed = 0xFF;
2076 This->palettes[0][i].peGreen = 0xFF;
2077 This->palettes[0][i].peBlue = 0xFF;
2078 This->palettes[0][i].peFlags = 0xFF;
2080 This->currentPalette = 0;
2082 /* Initialize the texture unit mapping to a 1:1 mapping */
2083 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2084 if (state < GL_LIMITS(fragment_samplers)) {
2085 This->texUnitMap[state] = state;
2086 This->rev_tex_unit_map[state] = state;
2088 This->texUnitMap[state] = -1;
2089 This->rev_tex_unit_map[state] = -1;
2093 /* Setup the implicit swapchain */
2094 TRACE("Creating implicit swapchain\n");
2095 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2096 if (FAILED(hr) || !swapchain) {
2097 WARN("Failed to create implicit swapchain\n");
2101 This->NumberOfSwapChains = 1;
2102 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2103 if(!This->swapchains) {
2104 ERR("Out of memory!\n");
2107 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2109 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2110 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2111 This->render_targets[0] = swapchain->backBuffer[0];
2112 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2115 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2116 This->render_targets[0] = swapchain->frontBuffer;
2117 This->lastActiveRenderTarget = swapchain->frontBuffer;
2119 IWineD3DSurface_AddRef(This->render_targets[0]);
2120 This->activeContext = swapchain->context[0];
2121 This->lastThread = GetCurrentThreadId();
2123 /* Depth Stencil support */
2124 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2125 if (NULL != This->stencilBufferTarget) {
2126 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2129 hr = This->shader_backend->shader_alloc_private(iface);
2131 TRACE("Shader private data couldn't be allocated\n");
2135 /* Set up some starting GL setup */
2137 /* Setup all the devices defaults */
2138 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2139 create_dummy_textures(This);
2144 IWineD3DImpl_CheckGraphicsMemory();
2147 { /* Set a default viewport */
2151 vp.Width = pPresentationParameters->BackBufferWidth;
2152 vp.Height = pPresentationParameters->BackBufferHeight;
2155 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2158 /* Initialize the current view state */
2159 This->view_ident = 1;
2160 This->contexts[0]->last_was_rhw = 0;
2161 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2162 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2164 switch(wined3d_settings.offscreen_rendering_mode) {
2167 This->offscreenBuffer = GL_BACK;
2170 case ORM_BACKBUFFER:
2172 if(This->activeContext->aux_buffers > 0) {
2173 TRACE("Using auxilliary buffer for offscreen rendering\n");
2174 This->offscreenBuffer = GL_AUX0;
2176 TRACE("Using back buffer for offscreen rendering\n");
2177 This->offscreenBuffer = GL_BACK;
2182 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2185 /* Clear the screen */
2186 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2187 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2190 This->d3d_initialized = TRUE;
2192 if(wined3d_settings.logo) {
2193 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2195 This->highest_dirty_ps_const = 0;
2196 This->highest_dirty_vs_const = 0;
2200 This->shader_backend->shader_free_private(iface);
2201 HeapFree(GetProcessHeap(), 0, This->render_targets);
2202 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2203 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2204 HeapFree(GetProcessHeap(), 0, This->swapchains);
2205 This->NumberOfSwapChains = 0;
2206 if(This->palettes) {
2207 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2208 HeapFree(GetProcessHeap(), 0, This->palettes);
2210 This->NumberOfPalettes = 0;
2212 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2214 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2215 if(This->stateBlock) {
2216 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2217 This->stateBlock = NULL;
2222 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2226 TRACE("(%p)\n", This);
2228 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2230 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2231 * it was created. Thus make sure a context is active for the glDelete* calls
2233 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2235 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2237 TRACE("Deleting high order patches\n");
2238 for(i = 0; i < PATCHMAP_SIZE; i++) {
2239 struct list *e1, *e2;
2240 struct WineD3DRectPatch *patch;
2241 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2242 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2243 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2247 /* Delete the palette conversion shader if it is around */
2248 if(This->paletteConversionShader) {
2250 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2252 This->paletteConversionShader = 0;
2255 /* Delete the pbuffer context if there is any */
2256 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2258 /* Delete the mouse cursor texture */
2259 if(This->cursorTexture) {
2261 glDeleteTextures(1, &This->cursorTexture);
2263 This->cursorTexture = 0;
2266 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2267 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2269 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2270 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2273 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2274 * private data, it might contain opengl pointers
2276 if(This->depth_blt_texture) {
2277 glDeleteTextures(1, &This->depth_blt_texture);
2278 This->depth_blt_texture = 0;
2280 if (This->depth_blt_rb) {
2281 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2282 This->depth_blt_rb = 0;
2283 This->depth_blt_rb_w = 0;
2284 This->depth_blt_rb_h = 0;
2286 This->shader_backend->shader_free_private(iface);
2288 /* Release the update stateblock */
2289 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2290 if(This->updateStateBlock != This->stateBlock)
2291 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2293 This->updateStateBlock = NULL;
2295 { /* because were not doing proper internal refcounts releasing the primary state block
2296 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2297 to set this->stateBlock = NULL; first */
2298 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2299 This->stateBlock = NULL;
2301 /* Release the stateblock */
2302 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2303 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2307 /* Release the buffers (with sanity checks)*/
2308 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2309 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2310 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2311 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2313 This->stencilBufferTarget = NULL;
2315 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2316 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2317 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2319 TRACE("Setting rendertarget to NULL\n");
2320 This->render_targets[0] = NULL;
2322 if (This->auto_depth_stencil_buffer) {
2323 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2324 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2326 This->auto_depth_stencil_buffer = NULL;
2329 for(i=0; i < This->NumberOfSwapChains; i++) {
2330 TRACE("Releasing the implicit swapchain %d\n", i);
2331 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2332 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2336 HeapFree(GetProcessHeap(), 0, This->swapchains);
2337 This->swapchains = NULL;
2338 This->NumberOfSwapChains = 0;
2340 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2341 HeapFree(GetProcessHeap(), 0, This->palettes);
2342 This->palettes = NULL;
2343 This->NumberOfPalettes = 0;
2345 HeapFree(GetProcessHeap(), 0, This->render_targets);
2346 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2347 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2348 This->render_targets = NULL;
2349 This->fbo_color_attachments = NULL;
2350 This->draw_buffers = NULL;
2352 This->d3d_initialized = FALSE;
2356 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2358 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2360 /* Setup the window for fullscreen mode */
2361 if(fullscreen && !This->ddraw_fullscreen) {
2362 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2363 } else if(!fullscreen && This->ddraw_fullscreen) {
2364 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2367 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2368 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2369 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2372 This->ddraw_fullscreen = fullscreen;
2375 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2376 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2377 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2379 * There is no way to deactivate thread safety once it is enabled.
2381 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2384 /*For now just store the flag(needed in case of ddraw) */
2385 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2390 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2397 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2399 /* Resize the screen even without a window:
2400 * The app could have unset it with SetCooperativeLevel, but not called
2401 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2402 * but we don't have any hwnd
2405 memset(&devmode, 0, sizeof(devmode));
2406 devmode.dmSize = sizeof(devmode);
2407 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2408 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2409 devmode.dmPelsWidth = pMode->Width;
2410 devmode.dmPelsHeight = pMode->Height;
2412 devmode.dmDisplayFrequency = pMode->RefreshRate;
2413 if (pMode->RefreshRate != 0) {
2414 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2417 /* Only change the mode if necessary */
2418 if( (This->ddraw_width == pMode->Width) &&
2419 (This->ddraw_height == pMode->Height) &&
2420 (This->ddraw_format == pMode->Format) &&
2421 (pMode->RefreshRate == 0) ) {
2425 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2426 if (ret != DISP_CHANGE_SUCCESSFUL) {
2427 if(devmode.dmDisplayFrequency != 0) {
2428 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2429 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2430 devmode.dmDisplayFrequency = 0;
2431 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2433 if(ret != DISP_CHANGE_SUCCESSFUL) {
2434 return WINED3DERR_NOTAVAILABLE;
2438 /* Store the new values */
2439 This->ddraw_width = pMode->Width;
2440 This->ddraw_height = pMode->Height;
2441 This->ddraw_format = pMode->Format;
2443 /* Only do this with a window of course, and only if we're fullscreened */
2444 if(This->ddraw_window && This->ddraw_fullscreen)
2445 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2447 /* And finally clip mouse to our screen */
2448 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2449 ClipCursor(&clip_rc);
2454 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2456 *ppD3D= This->wineD3D;
2457 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2458 IWineD3D_AddRef(*ppD3D);
2462 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2466 (This->adapter->TextureRam/(1024*1024)),
2467 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2468 /* return simulated texture memory left */
2469 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2477 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2480 /* Update the current state block */
2481 This->updateStateBlock->changed.fvf = TRUE;
2483 if(This->updateStateBlock->fvf == fvf) {
2484 TRACE("Application is setting the old fvf over, nothing to do\n");
2488 This->updateStateBlock->fvf = fvf;
2489 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2495 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2497 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2498 *pfvf = This->stateBlock->fvf;
2503 * Get / Set Stream Source
2505 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2507 IWineD3DVertexBuffer *oldSrc;
2509 if (StreamNumber >= MAX_STREAMS) {
2510 WARN("Stream out of range %d\n", StreamNumber);
2511 return WINED3DERR_INVALIDCALL;
2512 } else if(OffsetInBytes & 0x3) {
2513 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2514 return WINED3DERR_INVALIDCALL;
2517 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2518 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2520 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2522 if(oldSrc == pStreamData &&
2523 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2524 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2525 TRACE("Application is setting the old values over, nothing to do\n");
2529 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2531 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2532 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2535 /* Handle recording of state blocks */
2536 if (This->isRecordingState) {
2537 TRACE("Recording... not performing anything\n");
2538 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2539 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2543 /* Need to do a getParent and pass the references up */
2544 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2545 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2546 so for now, just count internally */
2547 if (pStreamData != NULL) {
2548 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2549 InterlockedIncrement(&vbImpl->bindCount);
2550 IWineD3DVertexBuffer_AddRef(pStreamData);
2552 if (oldSrc != NULL) {
2553 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2554 IWineD3DVertexBuffer_Release(oldSrc);
2557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2562 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2565 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2566 This->stateBlock->streamSource[StreamNumber],
2567 This->stateBlock->streamOffset[StreamNumber],
2568 This->stateBlock->streamStride[StreamNumber]);
2570 if (StreamNumber >= MAX_STREAMS) {
2571 WARN("Stream out of range %d\n", StreamNumber);
2572 return WINED3DERR_INVALIDCALL;
2574 *pStream = This->stateBlock->streamSource[StreamNumber];
2575 *pStride = This->stateBlock->streamStride[StreamNumber];
2577 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2580 if (*pStream != NULL) {
2581 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2586 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2589 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2591 /* Verify input at least in d3d9 this is invalid*/
2592 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2593 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2594 return WINED3DERR_INVALIDCALL;
2596 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2597 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2598 return WINED3DERR_INVALIDCALL;
2601 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2602 return WINED3DERR_INVALIDCALL;
2605 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2606 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2608 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2609 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2611 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2612 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2619 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2622 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2623 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2625 TRACE("(%p) : returning %d\n", This, *Divider);
2631 * Get / Set & Multiply Transform
2633 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2636 /* Most of this routine, comments included copied from ddraw tree initially: */
2637 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2639 /* Handle recording of state blocks */
2640 if (This->isRecordingState) {
2641 TRACE("Recording... not performing anything\n");
2642 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2643 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2648 * If the new matrix is the same as the current one,
2649 * we cut off any further processing. this seems to be a reasonable
2650 * optimization because as was noticed, some apps (warcraft3 for example)
2651 * tend towards setting the same matrix repeatedly for some reason.
2653 * From here on we assume that the new matrix is different, wherever it matters.
2655 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2656 TRACE("The app is setting the same matrix over again\n");
2659 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2663 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2664 where ViewMat = Camera space, WorldMat = world space.
2666 In OpenGL, camera and world space is combined into GL_MODELVIEW
2667 matrix. The Projection matrix stay projection matrix.
2670 /* Capture the times we can just ignore the change for now */
2671 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2672 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2673 /* Handled by the state manager */
2676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2680 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2682 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2683 *pMatrix = This->stateBlock->transforms[State];
2687 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2688 WINED3DMATRIX *mat = NULL;
2691 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2692 * below means it will be recorded in a state block change, but it
2693 * works regardless where it is recorded.
2694 * If this is found to be wrong, change to StateBlock.
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2699 if (State < HIGHEST_TRANSFORMSTATE)
2701 mat = &This->updateStateBlock->transforms[State];
2703 FIXME("Unhandled transform state!!\n");
2706 multiply_matrix(&temp, mat, pMatrix);
2708 /* Apply change via set transform - will reapply to eg. lights this way */
2709 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2715 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2716 you can reference any indexes you want as long as that number max are enabled at any
2717 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2718 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2719 but when recording, just build a chain pretty much of commands to be replayed. */
2721 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2723 PLIGHTINFOEL *object = NULL;
2724 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2728 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2730 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2734 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2735 return WINED3DERR_INVALIDCALL;
2738 switch(pLight->Type) {
2739 case WINED3DLIGHT_POINT:
2740 case WINED3DLIGHT_SPOT:
2741 case WINED3DLIGHT_PARALLELPOINT:
2742 case WINED3DLIGHT_GLSPOT:
2743 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2746 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2747 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2748 return WINED3DERR_INVALIDCALL;
2752 case WINED3DLIGHT_DIRECTIONAL:
2753 /* Ignores attenuation */
2757 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2758 return WINED3DERR_INVALIDCALL;
2761 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2762 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2763 if(object->OriginalIndex == Index) break;
2768 TRACE("Adding new light\n");
2769 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2771 ERR("Out of memory error when allocating a light\n");
2772 return E_OUTOFMEMORY;
2774 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2775 object->glIndex = -1;
2776 object->OriginalIndex = Index;
2777 object->changed = TRUE;
2780 /* Initialize the object */
2781 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,
2782 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2783 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2784 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2785 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2786 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2787 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2789 /* Save away the information */
2790 object->OriginalParms = *pLight;
2792 switch (pLight->Type) {
2793 case WINED3DLIGHT_POINT:
2795 object->lightPosn[0] = pLight->Position.x;
2796 object->lightPosn[1] = pLight->Position.y;
2797 object->lightPosn[2] = pLight->Position.z;
2798 object->lightPosn[3] = 1.0f;
2799 object->cutoff = 180.0f;
2803 case WINED3DLIGHT_DIRECTIONAL:
2805 object->lightPosn[0] = -pLight->Direction.x;
2806 object->lightPosn[1] = -pLight->Direction.y;
2807 object->lightPosn[2] = -pLight->Direction.z;
2808 object->lightPosn[3] = 0.0;
2809 object->exponent = 0.0f;
2810 object->cutoff = 180.0f;
2813 case WINED3DLIGHT_SPOT:
2815 object->lightPosn[0] = pLight->Position.x;
2816 object->lightPosn[1] = pLight->Position.y;
2817 object->lightPosn[2] = pLight->Position.z;
2818 object->lightPosn[3] = 1.0;
2821 object->lightDirn[0] = pLight->Direction.x;
2822 object->lightDirn[1] = pLight->Direction.y;
2823 object->lightDirn[2] = pLight->Direction.z;
2824 object->lightDirn[3] = 1.0;
2827 * opengl-ish and d3d-ish spot lights use too different models for the
2828 * light "intensity" as a function of the angle towards the main light direction,
2829 * so we only can approximate very roughly.
2830 * however spot lights are rather rarely used in games (if ever used at all).
2831 * furthermore if still used, probably nobody pays attention to such details.
2833 if (pLight->Falloff == 0) {
2834 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2835 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2836 * will always be 1.0 for both of them, and we don't have to care for the
2837 * rest of the rather complex calculation
2839 object->exponent = 0;
2841 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2842 if (rho < 0.0001) rho = 0.0001f;
2843 object->exponent = -0.3/log(cos(rho/2));
2845 if (object->exponent > 128.0) {
2846 object->exponent = 128.0;
2848 object->cutoff = pLight->Phi*90/M_PI;
2854 FIXME("Unrecognized light type %d\n", pLight->Type);
2857 /* Update the live definitions if the light is currently assigned a glIndex */
2858 if (object->glIndex != -1 && !This->isRecordingState) {
2859 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2864 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2865 PLIGHTINFOEL *lightInfo = NULL;
2866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2867 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2869 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2871 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2872 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2873 if(lightInfo->OriginalIndex == Index) break;
2877 if (lightInfo == NULL) {
2878 TRACE("Light information requested but light not defined\n");
2879 return WINED3DERR_INVALIDCALL;
2882 *pLight = lightInfo->OriginalParms;
2887 * Get / Set Light Enable
2888 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2890 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2891 PLIGHTINFOEL *lightInfo = NULL;
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2895 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2897 /* Tests show true = 128...not clear why */
2898 Enable = Enable? 128: 0;
2900 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2901 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2902 if(lightInfo->OriginalIndex == Index) break;
2905 TRACE("Found light: %p\n", lightInfo);
2907 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2908 if (lightInfo == NULL) {
2910 TRACE("Light enabled requested but light not defined, so defining one!\n");
2911 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2913 /* Search for it again! Should be fairly quick as near head of list */
2914 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2915 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2916 if(lightInfo->OriginalIndex == Index) break;
2919 if (lightInfo == NULL) {
2920 FIXME("Adding default lights has failed dismally\n");
2921 return WINED3DERR_INVALIDCALL;
2925 lightInfo->enabledChanged = TRUE;
2927 if(lightInfo->glIndex != -1) {
2928 if(!This->isRecordingState) {
2929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2932 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2933 lightInfo->glIndex = -1;
2935 TRACE("Light already disabled, nothing to do\n");
2937 lightInfo->enabled = FALSE;
2939 lightInfo->enabled = TRUE;
2940 if (lightInfo->glIndex != -1) {
2942 TRACE("Nothing to do as light was enabled\n");
2945 /* Find a free gl light */
2946 for(i = 0; i < This->maxConcurrentLights; i++) {
2947 if(This->stateBlock->activeLights[i] == NULL) {
2948 This->stateBlock->activeLights[i] = lightInfo;
2949 lightInfo->glIndex = i;
2953 if(lightInfo->glIndex == -1) {
2954 /* Our tests show that Windows returns D3D_OK in this situation, even with
2955 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2956 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2957 * as well for those lights.
2959 * TODO: Test how this affects rendering
2961 FIXME("Too many concurrently active lights\n");
2965 /* i == lightInfo->glIndex */
2966 if(!This->isRecordingState) {
2967 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2975 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2977 PLIGHTINFOEL *lightInfo = NULL;
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2981 TRACE("(%p) : for idx(%d)\n", This, Index);
2983 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2984 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2985 if(lightInfo->OriginalIndex == Index) break;
2989 if (lightInfo == NULL) {
2990 TRACE("Light enabled state requested but light not defined\n");
2991 return WINED3DERR_INVALIDCALL;
2993 /* true is 128 according to SetLightEnable */
2994 *pEnable = lightInfo->enabled ? 128 : 0;
2999 * Get / Set Clip Planes
3001 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3005 /* Validate Index */
3006 if (Index >= GL_LIMITS(clipplanes)) {
3007 TRACE("Application has requested clipplane this device doesn't support\n");
3008 return WINED3DERR_INVALIDCALL;
3011 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3013 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3014 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3015 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3016 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3017 TRACE("Application is setting old values over, nothing to do\n");
3021 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3022 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3023 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3024 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3026 /* Handle recording of state blocks */
3027 if (This->isRecordingState) {
3028 TRACE("Recording... not performing anything\n");
3032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3037 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 TRACE("(%p) : for idx %d\n", This, Index);
3041 /* Validate Index */
3042 if (Index >= GL_LIMITS(clipplanes)) {
3043 TRACE("Application has requested clipplane this device doesn't support\n");
3044 return WINED3DERR_INVALIDCALL;
3047 pPlane[0] = This->stateBlock->clipplane[Index][0];
3048 pPlane[1] = This->stateBlock->clipplane[Index][1];
3049 pPlane[2] = This->stateBlock->clipplane[Index][2];
3050 pPlane[3] = This->stateBlock->clipplane[Index][3];
3055 * Get / Set Clip Plane Status
3056 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3058 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 FIXME("(%p) : stub\n", This);
3061 if (NULL == pClipStatus) {
3062 return WINED3DERR_INVALIDCALL;
3064 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3065 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3069 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 FIXME("(%p) : stub\n", This);
3072 if (NULL == pClipStatus) {
3073 return WINED3DERR_INVALIDCALL;
3075 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3076 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3081 * Get / Set Material
3083 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3088 This->updateStateBlock->changed.material = TRUE;
3089 This->updateStateBlock->material = *pMaterial;
3091 /* Handle recording of state blocks */
3092 if (This->isRecordingState) {
3093 TRACE("Recording... not performing anything\n");
3097 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3101 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 *pMaterial = This->updateStateBlock->material;
3104 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3105 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3106 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3107 pMaterial->Ambient.b, pMaterial->Ambient.a);
3108 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3109 pMaterial->Specular.b, pMaterial->Specular.a);
3110 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3111 pMaterial->Emissive.b, pMaterial->Emissive.a);
3112 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3120 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3122 IWineD3DIndexBuffer *oldIdxs;
3124 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3125 oldIdxs = This->updateStateBlock->pIndexData;
3127 This->updateStateBlock->changed.indices = TRUE;
3128 This->updateStateBlock->pIndexData = pIndexData;
3130 /* Handle recording of state blocks */
3131 if (This->isRecordingState) {
3132 TRACE("Recording... not performing anything\n");
3133 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3134 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3138 if(oldIdxs != pIndexData) {
3139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3140 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3141 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3146 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3149 *ppIndexData = This->stateBlock->pIndexData;
3151 /* up ref count on ppindexdata */
3153 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3154 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3156 TRACE("(%p) No index data set\n", This);
3158 TRACE("Returning %p\n", *ppIndexData);
3163 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3164 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3166 TRACE("(%p)->(%d)\n", This, BaseIndex);
3168 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3169 TRACE("Application is setting the old value over, nothing to do\n");
3173 This->updateStateBlock->baseVertexIndex = BaseIndex;
3175 if (This->isRecordingState) {
3176 TRACE("Recording... not performing anything\n");
3179 /* The base vertex index affects the stream sources */
3180 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3184 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3186 TRACE("(%p) : base_index %p\n", This, base_index);
3188 *base_index = This->stateBlock->baseVertexIndex;
3190 TRACE("Returning %u\n", *base_index);
3196 * Get / Set Viewports
3198 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 TRACE("(%p)\n", This);
3202 This->updateStateBlock->changed.viewport = TRUE;
3203 This->updateStateBlock->viewport = *pViewport;
3205 /* Handle recording of state blocks */
3206 if (This->isRecordingState) {
3207 TRACE("Recording... not performing anything\n");
3211 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3212 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3219 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 TRACE("(%p)\n", This);
3222 *pViewport = This->stateBlock->viewport;
3227 * Get / Set Render States
3228 * TODO: Verify against dx9 definitions
3230 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 DWORD oldValue = This->stateBlock->renderState[State];
3235 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3237 This->updateStateBlock->changed.renderState[State] = TRUE;
3238 This->updateStateBlock->renderState[State] = Value;
3240 /* Handle recording of state blocks */
3241 if (This->isRecordingState) {
3242 TRACE("Recording... not performing anything\n");
3246 /* Compared here and not before the assignment to allow proper stateblock recording */
3247 if(Value == oldValue) {
3248 TRACE("Application is setting the old value over, nothing to do\n");
3250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3256 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3258 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3259 *pValue = This->stateBlock->renderState[State];
3264 * Get / Set Sampler States
3265 * TODO: Verify against dx9 definitions
3268 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3273 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3275 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3276 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3279 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3280 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3281 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3284 * SetSampler is designed to allow for more than the standard up to 8 textures
3285 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3286 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3288 * http://developer.nvidia.com/object/General_FAQ.html#t6
3290 * There are two new settings for GForce
3292 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3293 * and the texture one:
3294 * GL_MAX_TEXTURE_COORDS_ARB.
3295 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3298 oldValue = This->stateBlock->samplerState[Sampler][Type];
3299 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3300 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3302 /* Handle recording of state blocks */
3303 if (This->isRecordingState) {
3304 TRACE("Recording... not performing anything\n");
3308 if(oldValue == Value) {
3309 TRACE("Application is setting the old value over, nothing to do\n");
3313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3318 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3321 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3322 This, Sampler, debug_d3dsamplerstate(Type), Type);
3324 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3325 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3328 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3329 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3330 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3332 *Value = This->stateBlock->samplerState[Sampler][Type];
3333 TRACE("(%p) : Returning %#x\n", This, *Value);
3338 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3341 This->updateStateBlock->changed.scissorRect = TRUE;
3342 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3343 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3346 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3348 if(This->isRecordingState) {
3349 TRACE("Recording... not performing anything\n");
3353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3358 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3361 *pRect = This->updateStateBlock->scissorRect;
3362 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3366 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3368 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3370 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3372 This->updateStateBlock->vertexDecl = pDecl;
3373 This->updateStateBlock->changed.vertexDecl = TRUE;
3375 if (This->isRecordingState) {
3376 TRACE("Recording... not performing anything\n");
3378 } else if(pDecl == oldDecl) {
3379 /* Checked after the assignment to allow proper stateblock recording */
3380 TRACE("Application is setting the old declaration over, nothing to do\n");
3384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3393 *ppDecl = This->stateBlock->vertexDecl;
3394 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3402 This->updateStateBlock->vertexShader = pShader;
3403 This->updateStateBlock->changed.vertexShader = TRUE;
3405 if (This->isRecordingState) {
3406 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3407 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3408 TRACE("Recording... not performing anything\n");
3410 } else if(oldShader == pShader) {
3411 /* Checked here to allow proper stateblock recording */
3412 TRACE("App is setting the old shader over, nothing to do\n");
3416 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3417 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3418 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3425 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3428 if (NULL == ppShader) {
3429 return WINED3DERR_INVALIDCALL;
3431 *ppShader = This->stateBlock->vertexShader;
3432 if( NULL != *ppShader)
3433 IWineD3DVertexShader_AddRef(*ppShader);
3435 TRACE("(%p) : returning %p\n", This, *ppShader);
3439 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3440 IWineD3DDevice *iface,
3442 CONST BOOL *srcData,
3445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3446 int i, cnt = min(count, MAX_CONST_B - start);
3448 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3449 iface, srcData, start, count);
3451 if (srcData == NULL || cnt < 0)
3452 return WINED3DERR_INVALIDCALL;
3454 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3455 for (i = 0; i < cnt; i++)
3456 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3458 for (i = start; i < cnt + start; ++i) {
3459 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3467 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3468 IWineD3DDevice *iface,
3473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3474 int cnt = min(count, MAX_CONST_B - start);
3476 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3477 iface, dstData, start, count);
3479 if (dstData == NULL || cnt < 0)
3480 return WINED3DERR_INVALIDCALL;
3482 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3486 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3487 IWineD3DDevice *iface,
3492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3493 int i, cnt = min(count, MAX_CONST_I - start);
3495 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3496 iface, srcData, start, count);
3498 if (srcData == NULL || cnt < 0)
3499 return WINED3DERR_INVALIDCALL;
3501 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3502 for (i = 0; i < cnt; i++)
3503 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3504 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3506 for (i = start; i < cnt + start; ++i) {
3507 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3515 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3516 IWineD3DDevice *iface,
3521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3522 int cnt = min(count, MAX_CONST_I - start);
3524 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3525 iface, dstData, start, count);
3527 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3528 return WINED3DERR_INVALIDCALL;
3530 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3534 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3535 IWineD3DDevice *iface,
3537 CONST float *srcData,
3540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3543 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3544 iface, srcData, start, count);
3546 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3547 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3548 return WINED3DERR_INVALIDCALL;
3550 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3552 for (i = 0; i < count; i++)
3553 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3554 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3557 for (i = start; i < count + start; ++i) {
3558 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3559 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3560 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3561 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3562 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3564 ptr->idx[ptr->count++] = i;
3565 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3574 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3575 IWineD3DDevice *iface,
3577 CONST float *srcData,
3580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3583 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3584 iface, srcData, start, count);
3586 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3587 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3588 return WINED3DERR_INVALIDCALL;
3590 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3592 for (i = 0; i < count; i++)
3593 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3594 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3597 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3598 * context. On a context switch the old context will be fully dirtified
3600 memset(This->activeContext->vshader_const_dirty + start, 1,
3601 sizeof(*This->activeContext->vshader_const_dirty) * count);
3602 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3609 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3610 IWineD3DDevice *iface,
3615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3616 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3618 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3619 iface, dstData, start, count);
3621 if (dstData == NULL || cnt < 0)
3622 return WINED3DERR_INVALIDCALL;
3624 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3628 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3630 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3635 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3636 int i = This->rev_tex_unit_map[unit];
3637 int j = This->texUnitMap[stage];
3639 This->texUnitMap[stage] = unit;
3640 if (i != -1 && i != stage) {
3641 This->texUnitMap[i] = -1;
3644 This->rev_tex_unit_map[unit] = stage;
3645 if (j != -1 && j != unit) {
3646 This->rev_tex_unit_map[j] = -1;
3650 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3653 for (i = 0; i < MAX_TEXTURES; ++i) {
3654 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3655 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3656 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3657 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3658 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3659 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3660 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3661 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3663 if (color_op == WINED3DTOP_DISABLE) {
3664 /* Not used, and disable higher stages */
3665 while (i < MAX_TEXTURES) {
3666 This->fixed_function_usage_map[i] = FALSE;
3672 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3673 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3674 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3675 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3676 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3677 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3678 This->fixed_function_usage_map[i] = TRUE;
3680 This->fixed_function_usage_map[i] = FALSE;
3683 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3684 This->fixed_function_usage_map[i+1] = TRUE;
3689 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3692 device_update_fixed_function_usage_map(This);
3694 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3695 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3696 if (!This->fixed_function_usage_map[i]) continue;
3698 if (This->texUnitMap[i] != i) {
3699 device_map_stage(This, i, i);
3700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3701 markTextureStagesDirty(This, i);
3707 /* Now work out the mapping */
3709 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3710 if (!This->fixed_function_usage_map[i]) continue;
3712 if (This->texUnitMap[i] != tex) {
3713 device_map_stage(This, i, tex);
3714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3715 markTextureStagesDirty(This, i);
3722 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3723 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3726 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3727 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3728 device_map_stage(This, i, i);
3729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3730 if (i < MAX_TEXTURES) {
3731 markTextureStagesDirty(This, i);
3737 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3738 int current_mapping = This->rev_tex_unit_map[unit];
3740 if (current_mapping == -1) {
3741 /* Not currently used */
3745 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3746 /* Used by a fragment sampler */
3748 if (!pshader_sampler_tokens) {
3749 /* No pixel shader, check fixed function */
3750 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3753 /* Pixel shader, check the shader's sampler map */
3754 return !pshader_sampler_tokens[current_mapping];
3757 /* Used by a vertex sampler */
3758 return !vshader_sampler_tokens[current_mapping];
3761 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3762 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3763 DWORD *pshader_sampler_tokens = NULL;
3764 int start = GL_LIMITS(combined_samplers) - 1;
3768 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3770 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3771 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3772 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3775 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3776 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3777 if (vshader_sampler_tokens[i]) {
3778 if (This->texUnitMap[vsampler_idx] != -1) {
3779 /* Already mapped somewhere */
3783 while (start >= 0) {
3784 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3785 device_map_stage(This, vsampler_idx, start);
3786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3798 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3799 BOOL vs = use_vs(This);
3800 BOOL ps = use_ps(This);
3803 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3804 * that would be really messy and require shader recompilation
3805 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3806 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3809 device_map_psamplers(This);
3811 device_map_fixed_function_samplers(This);
3815 device_map_vsamplers(This, ps);
3819 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3821 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3822 This->updateStateBlock->pixelShader = pShader;
3823 This->updateStateBlock->changed.pixelShader = TRUE;
3825 /* Handle recording of state blocks */
3826 if (This->isRecordingState) {
3827 TRACE("Recording... not performing anything\n");
3830 if (This->isRecordingState) {
3831 TRACE("Recording... not performing anything\n");
3832 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3833 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3837 if(pShader == oldShader) {
3838 TRACE("App is setting the old pixel shader over, nothing to do\n");
3842 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3843 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3845 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3851 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 if (NULL == ppShader) {
3855 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3856 return WINED3DERR_INVALIDCALL;
3859 *ppShader = This->stateBlock->pixelShader;
3860 if (NULL != *ppShader) {
3861 IWineD3DPixelShader_AddRef(*ppShader);
3863 TRACE("(%p) : returning %p\n", This, *ppShader);
3867 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3868 IWineD3DDevice *iface,
3870 CONST BOOL *srcData,
3873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3874 int i, cnt = min(count, MAX_CONST_B - start);
3876 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3877 iface, srcData, start, count);
3879 if (srcData == NULL || cnt < 0)
3880 return WINED3DERR_INVALIDCALL;
3882 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3883 for (i = 0; i < cnt; i++)
3884 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3886 for (i = start; i < cnt + start; ++i) {
3887 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3895 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3896 IWineD3DDevice *iface,
3901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3902 int cnt = min(count, MAX_CONST_B - start);
3904 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3905 iface, dstData, start, count);
3907 if (dstData == NULL || cnt < 0)
3908 return WINED3DERR_INVALIDCALL;
3910 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3914 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3915 IWineD3DDevice *iface,
3920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3921 int i, cnt = min(count, MAX_CONST_I - start);
3923 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3924 iface, srcData, start, count);
3926 if (srcData == NULL || cnt < 0)
3927 return WINED3DERR_INVALIDCALL;
3929 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3930 for (i = 0; i < cnt; i++)
3931 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3932 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3934 for (i = start; i < cnt + start; ++i) {
3935 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3943 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3944 IWineD3DDevice *iface,
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 int cnt = min(count, MAX_CONST_I - start);
3952 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3953 iface, dstData, start, count);
3955 if (dstData == NULL || cnt < 0)
3956 return WINED3DERR_INVALIDCALL;
3958 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3962 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3963 IWineD3DDevice *iface,
3965 CONST float *srcData,
3968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3971 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3972 iface, srcData, start, count);
3974 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3975 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3976 return WINED3DERR_INVALIDCALL;
3978 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3980 for (i = 0; i < count; i++)
3981 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3982 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3985 for (i = start; i < count + start; ++i) {
3986 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3987 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3988 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3989 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3990 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3992 ptr->idx[ptr->count++] = i;
3993 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4002 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4003 IWineD3DDevice *iface,
4005 CONST float *srcData,
4008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4011 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4012 iface, srcData, start, count);
4014 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4015 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4016 return WINED3DERR_INVALIDCALL;
4018 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4020 for (i = 0; i < count; i++)
4021 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4022 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4025 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4026 * context. On a context switch the old context will be fully dirtified
4028 memset(This->activeContext->pshader_const_dirty + start, 1,
4029 sizeof(*This->activeContext->pshader_const_dirty) * count);
4030 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4037 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4038 IWineD3DDevice *iface,
4043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4044 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4046 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4047 iface, dstData, start, count);
4049 if (dstData == NULL || cnt < 0)
4050 return WINED3DERR_INVALIDCALL;
4052 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4056 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4058 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4059 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4061 DWORD DestFVF = dest->fvf;
4063 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4067 if (lpStrideData->u.s.normal.lpData) {
4068 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4071 if (lpStrideData->u.s.position.lpData == NULL) {
4072 ERR("Source has no position mask\n");
4073 return WINED3DERR_INVALIDCALL;
4076 /* We might access VBOs from this code, so hold the lock */
4079 if (dest->resource.allocatedMemory == NULL) {
4080 /* This may happen if we do direct locking into a vbo. Unlikely,
4081 * but theoretically possible(ddraw processvertices test)
4083 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4084 if(!dest->resource.allocatedMemory) {
4086 ERR("Out of memory\n");
4087 return E_OUTOFMEMORY;
4091 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4092 checkGLcall("glBindBufferARB");
4093 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4095 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4097 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4098 checkGLcall("glUnmapBufferARB");
4102 /* Get a pointer into the destination vbo(create one if none exists) and
4103 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4105 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4106 dest->Flags |= VBFLAG_CREATEVBO;
4107 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4111 unsigned char extrabytes = 0;
4112 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4113 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4114 * this may write 4 extra bytes beyond the area that should be written
4116 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4117 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4118 if(!dest_conv_addr) {
4119 ERR("Out of memory\n");
4120 /* Continue without storing converted vertices */
4122 dest_conv = dest_conv_addr;
4126 * a) WINED3DRS_CLIPPING is enabled
4127 * b) WINED3DVOP_CLIP is passed
4129 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4130 static BOOL warned = FALSE;
4132 * The clipping code is not quite correct. Some things need
4133 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4134 * so disable clipping for now.
4135 * (The graphics in Half-Life are broken, and my processvertices
4136 * test crashes with IDirect3DDevice3)
4142 FIXME("Clipping is broken and disabled for now\n");
4144 } else doClip = FALSE;
4145 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4147 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4150 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4151 WINED3DTS_PROJECTION,
4153 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4154 WINED3DTS_WORLDMATRIX(0),
4157 TRACE("View mat:\n");
4158 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);
4159 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);
4160 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);
4161 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);
4163 TRACE("Proj mat:\n");
4164 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);
4165 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);
4166 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);
4167 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);
4169 TRACE("World mat:\n");
4170 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);
4171 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);
4172 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);
4173 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);
4175 /* Get the viewport */
4176 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4177 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4178 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4180 multiply_matrix(&mat,&view_mat,&world_mat);
4181 multiply_matrix(&mat,&proj_mat,&mat);
4183 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4185 for (i = 0; i < dwCount; i+= 1) {
4186 unsigned int tex_index;
4188 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4189 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4190 /* The position first */
4192 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4194 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4196 /* Multiplication with world, view and projection matrix */
4197 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);
4198 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);
4199 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);
4200 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);
4202 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4204 /* WARNING: The following things are taken from d3d7 and were not yet checked
4205 * against d3d8 or d3d9!
4208 /* Clipping conditions: From msdn
4210 * A vertex is clipped if it does not match the following requirements
4214 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4216 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4217 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4222 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4223 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4226 /* "Normal" viewport transformation (not clipped)
4227 * 1) The values are divided by rhw
4228 * 2) The y axis is negative, so multiply it with -1
4229 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4230 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4231 * 4) Multiply x with Width/2 and add Width/2
4232 * 5) The same for the height
4233 * 6) Add the viewpoint X and Y to the 2D coordinates and
4234 * The minimum Z value to z
4235 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4237 * Well, basically it's simply a linear transformation into viewport
4249 z *= vp.MaxZ - vp.MinZ;
4251 x += vp.Width / 2 + vp.X;
4252 y += vp.Height / 2 + vp.Y;
4257 /* That vertex got clipped
4258 * Contrary to OpenGL it is not dropped completely, it just
4259 * undergoes a different calculation.
4261 TRACE("Vertex got clipped\n");
4268 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4269 * outside of the main vertex buffer memory. That needs some more
4274 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4277 ( (float *) dest_ptr)[0] = x;
4278 ( (float *) dest_ptr)[1] = y;
4279 ( (float *) dest_ptr)[2] = z;
4280 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4282 dest_ptr += 3 * sizeof(float);
4284 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4285 dest_ptr += sizeof(float);
4290 ( (float *) dest_conv)[0] = x * w;
4291 ( (float *) dest_conv)[1] = y * w;
4292 ( (float *) dest_conv)[2] = z * w;
4293 ( (float *) dest_conv)[3] = w;
4295 dest_conv += 3 * sizeof(float);
4297 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4298 dest_conv += sizeof(float);
4302 if (DestFVF & WINED3DFVF_PSIZE) {
4303 dest_ptr += sizeof(DWORD);
4304 if(dest_conv) dest_conv += sizeof(DWORD);
4306 if (DestFVF & WINED3DFVF_NORMAL) {
4308 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4309 /* AFAIK this should go into the lighting information */
4310 FIXME("Didn't expect the destination to have a normal\n");
4311 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4313 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4317 if (DestFVF & WINED3DFVF_DIFFUSE) {
4319 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4321 static BOOL warned = FALSE;
4324 ERR("No diffuse color in source, but destination has one\n");
4328 *( (DWORD *) dest_ptr) = 0xffffffff;
4329 dest_ptr += sizeof(DWORD);
4332 *( (DWORD *) dest_conv) = 0xffffffff;
4333 dest_conv += sizeof(DWORD);
4337 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4339 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4340 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4341 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4342 dest_conv += sizeof(DWORD);
4347 if (DestFVF & WINED3DFVF_SPECULAR) {
4348 /* What's the color value in the feedback buffer? */
4350 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4352 static BOOL warned = FALSE;
4355 ERR("No specular color in source, but destination has one\n");
4359 *( (DWORD *) dest_ptr) = 0xFF000000;
4360 dest_ptr += sizeof(DWORD);
4363 *( (DWORD *) dest_conv) = 0xFF000000;
4364 dest_conv += sizeof(DWORD);
4368 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4370 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4371 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4372 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4373 dest_conv += sizeof(DWORD);
4378 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4380 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4381 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4383 ERR("No source texture, but destination requests one\n");
4384 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4385 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4388 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4390 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4397 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4398 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4399 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4400 dwCount * get_flexible_vertex_size(DestFVF),
4402 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4403 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4410 #undef copy_and_next
4412 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4414 WineDirect3DVertexStridedData strided;
4415 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4416 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4419 ERR("Output vertex declaration not implemented yet\n");
4422 /* Need any context to write to the vbo. */
4423 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4425 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4426 * control the streamIsUP flag, thus restore it afterwards.
4428 This->stateBlock->streamIsUP = FALSE;
4429 memset(&strided, 0, sizeof(strided));
4430 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4431 This->stateBlock->streamIsUP = streamWasUP;
4433 if(vbo || SrcStartIndex) {
4435 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4436 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4438 * Also get the start index in, but only loop over all elements if there's something to add at all.
4440 #define FIXSRC(type) \
4441 if(strided.u.s.type.VBO) { \
4442 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4443 strided.u.s.type.VBO = 0; \
4444 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4446 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4450 if(strided.u.s.type.lpData) { \
4451 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4454 FIXSRC(blendWeights);
4455 FIXSRC(blendMatrixIndices);
4460 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4461 FIXSRC(texCoords[i]);
4474 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4478 * Get / Set Texture Stage States
4479 * TODO: Verify against dx9 definitions
4481 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4483 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4485 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4487 if (Stage >= MAX_TEXTURES) {
4488 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4492 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4493 This->updateStateBlock->textureState[Stage][Type] = Value;
4495 if (This->isRecordingState) {
4496 TRACE("Recording... not performing anything\n");
4500 /* Checked after the assignments to allow proper stateblock recording */
4501 if(oldValue == Value) {
4502 TRACE("App is setting the old value over, nothing to do\n");
4506 if(Stage > This->stateBlock->lowest_disabled_stage &&
4507 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4508 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4509 * Changes in other states are important on disabled stages too
4514 if(Type == WINED3DTSS_COLOROP) {
4517 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4518 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4519 * they have to be disabled
4521 * The current stage is dirtified below.
4523 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4524 TRACE("Additionally dirtifying stage %d\n", i);
4525 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4527 This->stateBlock->lowest_disabled_stage = Stage;
4528 TRACE("New lowest disabled: %d\n", Stage);
4529 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4530 /* Previously disabled stage enabled. Stages above it may need enabling
4531 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4532 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4534 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4537 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4538 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4541 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4542 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4544 This->stateBlock->lowest_disabled_stage = i;
4545 TRACE("New lowest disabled: %d\n", i);
4547 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4548 /* TODO: Built a stage -> texture unit mapping for register combiners */
4552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4557 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4560 *pValue = This->updateStateBlock->textureState[Stage][Type];
4567 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 IWineD3DBaseTexture *oldTexture;
4571 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4573 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4574 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4577 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4578 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4579 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4582 oldTexture = This->updateStateBlock->textures[Stage];
4584 if(pTexture != NULL) {
4585 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4587 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4588 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4589 return WINED3DERR_INVALIDCALL;
4591 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4594 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4595 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4597 This->updateStateBlock->changed.textures[Stage] = TRUE;
4598 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4599 This->updateStateBlock->textures[Stage] = pTexture;
4601 /* Handle recording of state blocks */
4602 if (This->isRecordingState) {
4603 TRACE("Recording... not performing anything\n");
4607 if(oldTexture == pTexture) {
4608 TRACE("App is setting the same texture again, nothing to do\n");
4612 /** NOTE: MSDN says that setTexture increases the reference count,
4613 * and that the application must set the texture back to null (or have a leaky application),
4614 * This means we should pass the refcount up to the parent
4615 *******************************/
4616 if (NULL != This->updateStateBlock->textures[Stage]) {
4617 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4618 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4620 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4621 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4622 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4623 * so the COLOROP and ALPHAOP have to be dirtified.
4625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4628 if(bindCount == 1) {
4629 new->baseTexture.sampler = Stage;
4631 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4635 if (NULL != oldTexture) {
4636 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4637 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4639 IWineD3DBaseTexture_Release(oldTexture);
4640 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4645 if(bindCount && old->baseTexture.sampler == Stage) {
4647 /* Have to do a search for the other sampler(s) where the texture is bound to
4648 * Shouldn't happen as long as apps bind a texture only to one stage
4650 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4651 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4652 if(This->updateStateBlock->textures[i] == oldTexture) {
4653 old->baseTexture.sampler = i;
4660 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4665 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4668 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4670 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4671 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4674 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4675 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4676 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4679 *ppTexture=This->stateBlock->textures[Stage];
4681 IWineD3DBaseTexture_AddRef(*ppTexture);
4683 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4691 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4692 IWineD3DSurface **ppBackBuffer) {
4693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4694 IWineD3DSwapChain *swapChain;
4697 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4699 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4700 if (hr == WINED3D_OK) {
4701 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4702 IWineD3DSwapChain_Release(swapChain);
4704 *ppBackBuffer = NULL;
4709 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 WARN("(%p) : stub, calling idirect3d for now\n", This);
4712 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4715 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 IWineD3DSwapChain *swapChain;
4720 if(iSwapChain > 0) {
4721 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4722 if (hr == WINED3D_OK) {
4723 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4724 IWineD3DSwapChain_Release(swapChain);
4726 FIXME("(%p) Error getting display mode\n", This);
4729 /* Don't read the real display mode,
4730 but return the stored mode instead. X11 can't change the color
4731 depth, and some apps are pretty angry if they SetDisplayMode from
4732 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4734 Also don't relay to the swapchain because with ddraw it's possible
4735 that there isn't a swapchain at all */
4736 pMode->Width = This->ddraw_width;
4737 pMode->Height = This->ddraw_height;
4738 pMode->Format = This->ddraw_format;
4739 pMode->RefreshRate = 0;
4746 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4748 TRACE("(%p)->(%p)\n", This, hWnd);
4750 if(This->ddraw_fullscreen) {
4751 if(This->ddraw_window && This->ddraw_window != hWnd) {
4752 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4754 if(hWnd && This->ddraw_window != hWnd) {
4755 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4759 This->ddraw_window = hWnd;
4763 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4765 TRACE("(%p)->(%p)\n", This, hWnd);
4767 *hWnd = This->ddraw_window;
4772 * Stateblock related functions
4775 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4777 IWineD3DStateBlockImpl *object;
4778 HRESULT temp_result;
4781 TRACE("(%p)\n", This);
4783 if (This->isRecordingState) {
4784 return WINED3DERR_INVALIDCALL;
4787 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4788 if (NULL == object ) {
4789 FIXME("(%p)Error allocating memory for stateblock\n", This);
4790 return E_OUTOFMEMORY;
4792 TRACE("(%p) created object %p\n", This, object);
4793 object->wineD3DDevice= This;
4794 /** FIXME: object->parent = parent; **/
4795 object->parent = NULL;
4796 object->blockType = WINED3DSBT_RECORDED;
4798 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4800 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4801 list_init(&object->lightMap[i]);
4804 temp_result = allocate_shader_constants(object);
4805 if (WINED3D_OK != temp_result)
4808 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4809 This->updateStateBlock = object;
4810 This->isRecordingState = TRUE;
4812 TRACE("(%p) recording stateblock %p\n",This , object);
4816 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4819 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4821 if (!This->isRecordingState) {
4822 FIXME("(%p) not recording! returning error\n", This);
4823 *ppStateBlock = NULL;
4824 return WINED3DERR_INVALIDCALL;
4827 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4828 if(object->changed.renderState[i]) {
4829 object->contained_render_states[object->num_contained_render_states] = i;
4830 object->num_contained_render_states++;
4833 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4834 if(object->changed.transform[i]) {
4835 object->contained_transform_states[object->num_contained_transform_states] = i;
4836 object->num_contained_transform_states++;
4839 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4840 if(object->changed.vertexShaderConstantsF[i]) {
4841 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4842 object->num_contained_vs_consts_f++;
4845 for(i = 0; i < MAX_CONST_I; i++) {
4846 if(object->changed.vertexShaderConstantsI[i]) {
4847 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4848 object->num_contained_vs_consts_i++;
4851 for(i = 0; i < MAX_CONST_B; i++) {
4852 if(object->changed.vertexShaderConstantsB[i]) {
4853 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4854 object->num_contained_vs_consts_b++;
4857 for(i = 0; i < MAX_CONST_I; i++) {
4858 if(object->changed.pixelShaderConstantsI[i]) {
4859 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4860 object->num_contained_ps_consts_i++;
4863 for(i = 0; i < MAX_CONST_B; i++) {
4864 if(object->changed.pixelShaderConstantsB[i]) {
4865 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4866 object->num_contained_ps_consts_b++;
4869 for(i = 0; i < MAX_TEXTURES; i++) {
4870 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4871 if(object->changed.textureState[i][j]) {
4872 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4873 object->contained_tss_states[object->num_contained_tss_states].state = j;
4874 object->num_contained_tss_states++;
4878 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4879 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4880 if(object->changed.samplerState[i][j]) {
4881 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4882 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4883 object->num_contained_sampler_states++;
4888 *ppStateBlock = (IWineD3DStateBlock*) object;
4889 This->isRecordingState = FALSE;
4890 This->updateStateBlock = This->stateBlock;
4891 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4892 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4893 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4898 * Scene related functions
4900 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4901 /* At the moment we have no need for any functionality at the beginning
4903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4904 TRACE("(%p)\n", This);
4907 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4908 return WINED3DERR_INVALIDCALL;
4910 This->inScene = TRUE;
4914 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4916 TRACE("(%p)\n", This);
4918 if(!This->inScene) {
4919 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4920 return WINED3DERR_INVALIDCALL;
4923 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4924 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4927 checkGLcall("glFlush");
4930 This->inScene = FALSE;
4934 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4935 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4936 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4938 IWineD3DSwapChain *swapChain = NULL;
4940 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4942 TRACE("(%p) Presenting the frame\n", This);
4944 for(i = 0 ; i < swapchains ; i ++) {
4946 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4947 TRACE("presentinng chain %d, %p\n", i, swapChain);
4948 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4949 IWineD3DSwapChain_Release(swapChain);
4955 /* Not called from the VTable (internal subroutine) */
4956 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4957 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4958 float Z, DWORD Stencil) {
4959 GLbitfield glMask = 0;
4961 WINED3DRECT curRect;
4963 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4964 UINT drawable_width, drawable_height;
4965 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4967 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4968 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4969 * for the cleared parts, and the untouched parts.
4971 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4972 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4973 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4974 * checking all this if the dest surface is in the drawable anyway.
4976 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4978 if(vp->X != 0 || vp->Y != 0 ||
4979 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4980 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4983 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4984 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4985 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4986 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4987 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4990 if(Count > 0 && pRects && (
4991 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4992 pRects[0].x2 < target->currentDesc.Width ||
4993 pRects[0].y2 < target->currentDesc.Height)) {
4994 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5001 target->get_drawable_size(target, &drawable_width, &drawable_height);
5003 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5006 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5007 apply_fbo_state((IWineD3DDevice *) This);
5010 /* Only set the values up once, as they are not changing */
5011 if (Flags & WINED3DCLEAR_STENCIL) {
5012 glClearStencil(Stencil);
5013 checkGLcall("glClearStencil");
5014 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5015 glStencilMask(0xFFFFFFFF);
5018 if (Flags & WINED3DCLEAR_ZBUFFER) {
5019 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5020 glDepthMask(GL_TRUE);
5022 checkGLcall("glClearDepth");
5023 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5026 if (vp->X != 0 || vp->Y != 0 ||
5027 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5028 surface_load_ds_location(This->stencilBufferTarget, location);
5030 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5031 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5032 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5033 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5034 surface_load_ds_location(This->stencilBufferTarget, location);
5036 else if (Count > 0 && pRects && (
5037 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5038 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5039 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5040 surface_load_ds_location(This->stencilBufferTarget, location);
5044 if (Flags & WINED3DCLEAR_TARGET) {
5045 TRACE("Clearing screen with glClear to color %x\n", Color);
5046 glClearColor(D3DCOLOR_R(Color),
5050 checkGLcall("glClearColor");
5052 /* Clear ALL colors! */
5053 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5054 glMask = glMask | GL_COLOR_BUFFER_BIT;
5057 vp_rect.left = vp->X;
5058 vp_rect.top = vp->Y;
5059 vp_rect.right = vp->X + vp->Width;
5060 vp_rect.bottom = vp->Y + vp->Height;
5061 if (!(Count > 0 && pRects)) {
5062 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5063 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5065 if(This->render_offscreen) {
5066 glScissor(vp_rect.left, vp_rect.top,
5067 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5069 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5070 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5072 checkGLcall("glScissor");
5074 checkGLcall("glClear");
5076 /* Now process each rect in turn */
5077 for (i = 0; i < Count; i++) {
5078 /* Note gl uses lower left, width/height */
5079 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5080 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5081 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5083 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5084 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5085 curRect.x1, (target->currentDesc.Height - curRect.y2),
5086 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5088 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5089 * The rectangle is not cleared, no error is returned, but further rectanlges are
5090 * still cleared if they are valid
5092 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5093 TRACE("Rectangle with negative dimensions, ignoring\n");
5097 if(This->render_offscreen) {
5098 glScissor(curRect.x1, curRect.y1,
5099 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5101 glScissor(curRect.x1, drawable_height - curRect.y2,
5102 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5104 checkGLcall("glScissor");
5107 checkGLcall("glClear");
5111 /* Restore the old values (why..?) */
5112 if (Flags & WINED3DCLEAR_STENCIL) {
5113 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5115 if (Flags & WINED3DCLEAR_TARGET) {
5116 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5117 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5118 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5119 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5120 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5122 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5123 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5125 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5126 /* TODO: Move the fbo logic into ModifyLocation() */
5127 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5128 target->Flags |= SFLAG_INTEXTURE;
5131 if (Flags & WINED3DCLEAR_ZBUFFER) {
5132 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5133 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5134 surface_modify_ds_location(This->stencilBufferTarget, location);
5142 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5143 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5145 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5147 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5148 Count, pRects, Flags, Color, Z, Stencil);
5150 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5151 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5152 /* TODO: What about depth stencil buffers without stencil bits? */
5153 return WINED3DERR_INVALIDCALL;
5156 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5162 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5163 UINT PrimitiveCount) {
5165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5168 debug_d3dprimitivetype(PrimitiveType),
5169 StartVertex, PrimitiveCount);
5171 if(!This->stateBlock->vertexDecl) {
5172 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5173 return WINED3DERR_INVALIDCALL;
5176 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5177 if(This->stateBlock->streamIsUP) {
5178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5179 This->stateBlock->streamIsUP = FALSE;
5182 if(This->stateBlock->loadBaseVertexIndex != 0) {
5183 This->stateBlock->loadBaseVertexIndex = 0;
5184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5186 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5187 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5188 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5192 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5193 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5194 WINED3DPRIMITIVETYPE PrimitiveType,
5195 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5199 IWineD3DIndexBuffer *pIB;
5200 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5203 pIB = This->stateBlock->pIndexData;
5205 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5206 * without an index buffer set. (The first time at least...)
5207 * D3D8 simply dies, but I doubt it can do much harm to return
5208 * D3DERR_INVALIDCALL there as well. */
5209 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5210 return WINED3DERR_INVALIDCALL;
5213 if(!This->stateBlock->vertexDecl) {
5214 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5215 return WINED3DERR_INVALIDCALL;
5218 if(This->stateBlock->streamIsUP) {
5219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5220 This->stateBlock->streamIsUP = FALSE;
5222 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5224 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5225 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5226 minIndex, NumVertices, startIndex, primCount);
5228 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5229 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5235 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5236 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5240 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5241 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5246 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5247 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5248 UINT VertexStreamZeroStride) {
5249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250 IWineD3DVertexBuffer *vb;
5252 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5253 debug_d3dprimitivetype(PrimitiveType),
5254 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5256 if(!This->stateBlock->vertexDecl) {
5257 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5258 return WINED3DERR_INVALIDCALL;
5261 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5262 vb = This->stateBlock->streamSource[0];
5263 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5264 if(vb) IWineD3DVertexBuffer_Release(vb);
5265 This->stateBlock->streamOffset[0] = 0;
5266 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5267 This->stateBlock->streamIsUP = TRUE;
5268 This->stateBlock->loadBaseVertexIndex = 0;
5270 /* TODO: Only mark dirty if drawing from a different UP address */
5271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5273 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5274 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5276 /* MSDN specifies stream zero settings must be set to NULL */
5277 This->stateBlock->streamStride[0] = 0;
5278 This->stateBlock->streamSource[0] = NULL;
5280 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5281 * the new stream sources or use UP drawing again
5286 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5287 UINT MinVertexIndex, UINT NumVertices,
5288 UINT PrimitiveCount, CONST void* pIndexData,
5289 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5290 UINT VertexStreamZeroStride) {
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5293 IWineD3DVertexBuffer *vb;
5294 IWineD3DIndexBuffer *ib;
5296 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5297 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5298 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5299 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5301 if(!This->stateBlock->vertexDecl) {
5302 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5303 return WINED3DERR_INVALIDCALL;
5306 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5312 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5313 vb = This->stateBlock->streamSource[0];
5314 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5315 if(vb) IWineD3DVertexBuffer_Release(vb);
5316 This->stateBlock->streamIsUP = TRUE;
5317 This->stateBlock->streamOffset[0] = 0;
5318 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5320 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5321 This->stateBlock->baseVertexIndex = 0;
5322 This->stateBlock->loadBaseVertexIndex = 0;
5323 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5327 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5329 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5330 This->stateBlock->streamSource[0] = NULL;
5331 This->stateBlock->streamStride[0] = 0;
5332 ib = This->stateBlock->pIndexData;
5334 IWineD3DIndexBuffer_Release(ib);
5335 This->stateBlock->pIndexData = NULL;
5337 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5338 * SetStreamSource to specify a vertex buffer
5344 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5347 /* Mark the state dirty until we have nicer tracking
5348 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5353 This->stateBlock->baseVertexIndex = 0;
5354 This->up_strided = DrawPrimStrideData;
5355 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5356 This->up_strided = NULL;
5360 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5362 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5364 /* Mark the state dirty until we have nicer tracking
5365 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5370 This->stateBlock->streamIsUP = TRUE;
5371 This->stateBlock->baseVertexIndex = 0;
5372 This->up_strided = DrawPrimStrideData;
5373 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5374 This->up_strided = NULL;
5378 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5379 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5380 * not callable by the app directly no parameter validation checks are needed here.
5382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5383 WINED3DLOCKED_BOX src;
5384 WINED3DLOCKED_BOX dst;
5386 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5388 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5389 * dirtification to improve loading performance.
5391 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5392 if(FAILED(hr)) return hr;
5393 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5395 IWineD3DVolume_UnlockBox(pSourceVolume);
5399 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5401 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5403 IWineD3DVolume_UnlockBox(pSourceVolume);
5405 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5410 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5411 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5413 HRESULT hr = WINED3D_OK;
5414 WINED3DRESOURCETYPE sourceType;
5415 WINED3DRESOURCETYPE destinationType;
5418 /* TODO: think about moving the code into IWineD3DBaseTexture */
5420 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5422 /* verify that the source and destination textures aren't NULL */
5423 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5424 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5425 This, pSourceTexture, pDestinationTexture);
5426 hr = WINED3DERR_INVALIDCALL;
5429 if (pSourceTexture == pDestinationTexture) {
5430 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5431 This, pSourceTexture, pDestinationTexture);
5432 hr = WINED3DERR_INVALIDCALL;
5434 /* Verify that the source and destination textures are the same type */
5435 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5436 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5438 if (sourceType != destinationType) {
5439 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5441 hr = WINED3DERR_INVALIDCALL;
5444 /* check that both textures have the identical numbers of levels */
5445 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5446 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5447 hr = WINED3DERR_INVALIDCALL;
5450 if (WINED3D_OK == hr) {
5452 /* Make sure that the destination texture is loaded */
5453 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5455 /* Update every surface level of the texture */
5456 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5458 switch (sourceType) {
5459 case WINED3DRTYPE_TEXTURE:
5461 IWineD3DSurface *srcSurface;
5462 IWineD3DSurface *destSurface;
5464 for (i = 0 ; i < levels ; ++i) {
5465 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5466 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5467 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5468 IWineD3DSurface_Release(srcSurface);
5469 IWineD3DSurface_Release(destSurface);
5470 if (WINED3D_OK != hr) {
5471 WARN("(%p) : Call to update surface failed\n", This);
5477 case WINED3DRTYPE_CUBETEXTURE:
5479 IWineD3DSurface *srcSurface;
5480 IWineD3DSurface *destSurface;
5481 WINED3DCUBEMAP_FACES faceType;
5483 for (i = 0 ; i < levels ; ++i) {
5484 /* Update each cube face */
5485 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5486 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5487 if (WINED3D_OK != hr) {
5488 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5490 TRACE("Got srcSurface %p\n", srcSurface);
5492 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5493 if (WINED3D_OK != hr) {
5494 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5496 TRACE("Got desrSurface %p\n", destSurface);
5498 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5499 IWineD3DSurface_Release(srcSurface);
5500 IWineD3DSurface_Release(destSurface);
5501 if (WINED3D_OK != hr) {
5502 WARN("(%p) : Call to update surface failed\n", This);
5510 case WINED3DRTYPE_VOLUMETEXTURE:
5512 IWineD3DVolume *srcVolume = NULL;
5513 IWineD3DVolume *destVolume = NULL;
5515 for (i = 0 ; i < levels ; ++i) {
5516 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5517 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5518 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5519 IWineD3DVolume_Release(srcVolume);
5520 IWineD3DVolume_Release(destVolume);
5521 if (WINED3D_OK != hr) {
5522 WARN("(%p) : Call to update volume failed\n", This);
5530 FIXME("(%p) : Unsupported source and destination type\n", This);
5531 hr = WINED3DERR_INVALIDCALL;
5538 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5539 IWineD3DSwapChain *swapChain;
5541 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5542 if(hr == WINED3D_OK) {
5543 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5544 IWineD3DSwapChain_Release(swapChain);
5549 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5551 /* return a sensible default */
5553 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5554 FIXME("(%p) : stub\n", This);
5558 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5562 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5563 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5564 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5565 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5570 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5574 PALETTEENTRY **palettes;
5576 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5578 if (PaletteNumber >= MAX_PALETTES) {
5579 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5580 return WINED3DERR_INVALIDCALL;
5583 if (PaletteNumber >= This->NumberOfPalettes) {
5584 NewSize = This->NumberOfPalettes;
5587 } while(PaletteNumber >= NewSize);
5588 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5590 ERR("Out of memory!\n");
5591 return E_OUTOFMEMORY;
5593 This->palettes = palettes;
5594 This->NumberOfPalettes = NewSize;
5597 if (!This->palettes[PaletteNumber]) {
5598 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5599 if (!This->palettes[PaletteNumber]) {
5600 ERR("Out of memory!\n");
5601 return E_OUTOFMEMORY;
5605 for (j = 0; j < 256; ++j) {
5606 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5607 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5608 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5609 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5611 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5612 TRACE("(%p) : returning\n", This);
5616 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5619 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5620 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5621 /* What happens in such situation isn't documented; Native seems to silently abort
5622 on such conditions. Return Invalid Call. */
5623 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5624 return WINED3DERR_INVALIDCALL;
5626 for (j = 0; j < 256; ++j) {
5627 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5628 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5629 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5630 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5632 TRACE("(%p) : returning\n", This);
5636 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5638 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5639 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5640 (tested with reference rasterizer). Return Invalid Call. */
5641 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5642 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5643 return WINED3DERR_INVALIDCALL;
5645 /*TODO: stateblocks */
5646 if (This->currentPalette != PaletteNumber) {
5647 This->currentPalette = PaletteNumber;
5648 dirtify_p8_texture_samplers(This);
5650 TRACE("(%p) : returning\n", This);
5654 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5656 if (PaletteNumber == NULL) {
5657 WARN("(%p) : returning Invalid Call\n", This);
5658 return WINED3DERR_INVALIDCALL;
5660 /*TODO: stateblocks */
5661 *PaletteNumber = This->currentPalette;
5662 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5666 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 static BOOL showFixmes = TRUE;
5670 FIXME("(%p) : stub\n", This);
5674 This->softwareVertexProcessing = bSoftware;
5679 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 static BOOL showFixmes = TRUE;
5683 FIXME("(%p) : stub\n", This);
5686 return This->softwareVertexProcessing;
5690 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5692 IWineD3DSwapChain *swapChain;
5695 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5697 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5698 if(hr == WINED3D_OK){
5699 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5700 IWineD3DSwapChain_Release(swapChain);
5702 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5708 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5710 static BOOL showfixmes = TRUE;
5711 if(nSegments != 0.0f) {
5713 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5720 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5722 static BOOL showfixmes = TRUE;
5724 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5730 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5732 /** TODO: remove casts to IWineD3DSurfaceImpl
5733 * NOTE: move code to surface to accomplish this
5734 ****************************************/
5735 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5736 int srcWidth, srcHeight;
5737 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5738 WINED3DFORMAT destFormat, srcFormat;
5740 int srcLeft, destLeft, destTop;
5741 WINED3DPOOL srcPool, destPool;
5743 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5744 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, (RECT *) 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);
5798 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5799 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5800 checkGLcall("glActiveTextureARB");
5803 /* Make sure the surface is loaded and up to date */
5804 IWineD3DSurface_PreLoad(pDestinationSurface);
5806 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5808 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5809 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5810 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5811 srcLeft = pSourceRect ? pSourceRect->left : 0;
5812 destLeft = pDestPoint ? pDestPoint->x : 0;
5813 destTop = pDestPoint ? pDestPoint->y : 0;
5816 /* This function doesn't support compressed textures
5817 the pitch is just bytesPerPixel * width */
5818 if(srcWidth != srcSurfaceWidth || srcLeft ){
5819 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5820 offset += srcLeft * pSrcSurface->bytesPerPixel;
5821 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5823 /* TODO DXT formats */
5825 if(pSourceRect != NULL && pSourceRect->top != 0){
5826 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5828 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5830 ,glDescription->level
5835 ,glDescription->glFormat
5836 ,glDescription->glType
5837 ,IWineD3DSurface_GetData(pSourceSurface)
5841 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5843 /* need to lock the surface to get the data */
5844 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5847 /* TODO: Cube and volume support */
5849 /* not a whole row so we have to do it a line at a time */
5852 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5853 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5855 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5857 glTexSubImage2D(glDescription->target
5858 ,glDescription->level
5863 ,glDescription->glFormat
5864 ,glDescription->glType
5865 ,data /* could be quicker using */
5870 } else { /* Full width, so just write out the whole texture */
5872 if (WINED3DFMT_DXT1 == destFormat ||
5873 WINED3DFMT_DXT2 == destFormat ||
5874 WINED3DFMT_DXT3 == destFormat ||
5875 WINED3DFMT_DXT4 == destFormat ||
5876 WINED3DFMT_DXT5 == destFormat) {
5877 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5878 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5879 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5880 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5881 } if (destFormat != srcFormat) {
5882 FIXME("Updating mixed format compressed texture is not curretly support\n");
5884 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5885 glDescription->level,
5886 glDescription->glFormatInternal,
5891 IWineD3DSurface_GetData(pSourceSurface));
5894 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5899 glTexSubImage2D(glDescription->target
5900 ,glDescription->level
5905 ,glDescription->glFormat
5906 ,glDescription->glType
5907 ,IWineD3DSurface_GetData(pSourceSurface)
5911 checkGLcall("glTexSubImage2D");
5915 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5921 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5923 struct WineD3DRectPatch *patch;
5927 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5929 if(!(Handle || pRectPatchInfo)) {
5930 /* TODO: Write a test for the return value, thus the FIXME */
5931 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5932 return WINED3DERR_INVALIDCALL;
5936 i = PATCHMAP_HASHFUNC(Handle);
5938 LIST_FOR_EACH(e, &This->patches[i]) {
5939 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5940 if(patch->Handle == Handle) {
5947 TRACE("Patch does not exist. Creating a new one\n");
5948 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5949 patch->Handle = Handle;
5950 list_add_head(&This->patches[i], &patch->entry);
5952 TRACE("Found existing patch %p\n", patch);
5955 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5956 * attributes we have to tesselate, read back, and draw. This needs a patch
5957 * management structure instance. Create one.
5959 * A possible improvement is to check if a vertex shader is used, and if not directly
5962 FIXME("Drawing an uncached patch. This is slow\n");
5963 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5966 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5967 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5968 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5970 TRACE("Tesselation density or patch info changed, retesselating\n");
5972 if(pRectPatchInfo) {
5973 patch->RectPatchInfo = *pRectPatchInfo;
5975 patch->numSegs[0] = pNumSegs[0];
5976 patch->numSegs[1] = pNumSegs[1];
5977 patch->numSegs[2] = pNumSegs[2];
5978 patch->numSegs[3] = pNumSegs[3];
5980 hr = tesselate_rectpatch(This, patch);
5982 WARN("Patch tesselation failed\n");
5984 /* Do not release the handle to store the params of the patch */
5986 HeapFree(GetProcessHeap(), 0, patch);
5992 This->currentPatch = patch;
5993 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5994 This->currentPatch = NULL;
5996 /* Destroy uncached patches */
5998 HeapFree(GetProcessHeap(), 0, patch->mem);
5999 HeapFree(GetProcessHeap(), 0, patch);
6004 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6006 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6007 FIXME("(%p) : Stub\n", This);
6011 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6014 struct WineD3DRectPatch *patch;
6016 TRACE("(%p) Handle(%d)\n", This, Handle);
6018 i = PATCHMAP_HASHFUNC(Handle);
6019 LIST_FOR_EACH(e, &This->patches[i]) {
6020 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6021 if(patch->Handle == Handle) {
6022 TRACE("Deleting patch %p\n", patch);
6023 list_remove(&patch->entry);
6024 HeapFree(GetProcessHeap(), 0, patch->mem);
6025 HeapFree(GetProcessHeap(), 0, patch);
6030 /* TODO: Write a test for the return value */
6031 FIXME("Attempt to destroy nonexistent patch\n");
6032 return WINED3DERR_INVALIDCALL;
6035 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6037 IWineD3DSwapChain *swapchain;
6039 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6040 if (SUCCEEDED(hr)) {
6041 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6048 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6052 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6053 checkGLcall("glGenFramebuffersEXT()");
6055 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6056 checkGLcall("glBindFramebuffer()");
6059 /* TODO: Handle stencil attachments */
6060 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6061 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6063 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6064 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6065 checkGLcall("glFramebufferRenderbufferEXT()");
6067 IWineD3DBaseTextureImpl *texture_impl;
6068 GLenum texttarget, target;
6069 GLint old_binding = 0;
6071 texttarget = depth_stencil_impl->glDescription.target;
6072 if(texttarget == GL_TEXTURE_2D) {
6073 target = GL_TEXTURE_2D;
6074 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6075 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6076 target = GL_TEXTURE_RECTANGLE_ARB;
6077 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6079 target = GL_TEXTURE_CUBE_MAP_ARB;
6080 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6083 IWineD3DSurface_PreLoad(depth_stencil);
6085 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6086 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6087 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6088 glBindTexture(target, old_binding);
6090 /* Update base texture states array */
6091 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6092 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6093 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6094 if (texture_impl->baseTexture.bindCount) {
6095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6098 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6101 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6102 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6103 checkGLcall("glFramebufferTexture2DEXT()");
6107 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6108 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6109 IWineD3DBaseTextureImpl *texture_impl;
6110 GLenum texttarget, target;
6113 texttarget = surface_impl->glDescription.target;
6114 if(texttarget == GL_TEXTURE_2D) {
6115 target = GL_TEXTURE_2D;
6116 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6117 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6118 target = GL_TEXTURE_RECTANGLE_ARB;
6119 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6121 target = GL_TEXTURE_CUBE_MAP_ARB;
6122 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6125 IWineD3DSurface_PreLoad(surface);
6127 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6128 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6129 glBindTexture(target, old_binding);
6131 /* Update base texture states array */
6132 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6133 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6134 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6135 if (texture_impl->baseTexture.bindCount) {
6136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6139 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6142 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6143 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6145 checkGLcall("attach_surface_fbo");
6148 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6150 IWineD3DSwapChain *swapchain;
6152 swapchain = get_swapchain(surface);
6156 TRACE("Surface %p is onscreen\n", surface);
6158 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6159 buffer = surface_get_gl_buffer(surface, swapchain);
6160 glDrawBuffer(buffer);
6161 checkGLcall("glDrawBuffer()");
6163 TRACE("Surface %p is offscreen\n", surface);
6164 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6165 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6166 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6167 checkGLcall("glFramebufferRenderbufferEXT");
6171 glEnable(GL_SCISSOR_TEST);
6173 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6175 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6176 rect->x2 - rect->x1, rect->y2 - rect->y1);
6178 checkGLcall("glScissor");
6180 glDisable(GL_SCISSOR_TEST);
6182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6184 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6187 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6188 glClear(GL_COLOR_BUFFER_BIT);
6189 checkGLcall("glClear");
6191 if (This->render_offscreen) {
6192 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6194 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6195 checkGLcall("glBindFramebuffer()");
6198 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6199 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6200 glDrawBuffer(GL_BACK);
6201 checkGLcall("glDrawBuffer()");
6205 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6206 unsigned int r, g, b, a;
6209 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6210 destfmt == WINED3DFMT_R8G8B8)
6213 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6215 a = (color & 0xff000000) >> 24;
6216 r = (color & 0x00ff0000) >> 16;
6217 g = (color & 0x0000ff00) >> 8;
6218 b = (color & 0x000000ff) >> 0;
6222 case WINED3DFMT_R5G6B5:
6223 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6230 TRACE("Returning %08x\n", ret);
6233 case WINED3DFMT_X1R5G5B5:
6234 case WINED3DFMT_A1R5G5B5:
6243 TRACE("Returning %08x\n", ret);
6247 TRACE("Returning %08x\n", a);
6250 case WINED3DFMT_X4R4G4B4:
6251 case WINED3DFMT_A4R4G4B4:
6260 TRACE("Returning %08x\n", ret);
6263 case WINED3DFMT_R3G3B2:
6270 TRACE("Returning %08x\n", ret);
6273 case WINED3DFMT_X8B8G8R8:
6274 case WINED3DFMT_A8B8G8R8:
6279 TRACE("Returning %08x\n", ret);
6282 case WINED3DFMT_A2R10G10B10:
6284 r = (r * 1024) / 256;
6285 g = (g * 1024) / 256;
6286 b = (b * 1024) / 256;
6291 TRACE("Returning %08x\n", ret);
6294 case WINED3DFMT_A2B10G10R10:
6296 r = (r * 1024) / 256;
6297 g = (g * 1024) / 256;
6298 b = (b * 1024) / 256;
6303 TRACE("Returning %08x\n", ret);
6307 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6312 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6314 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6316 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6318 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6319 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6320 return WINED3DERR_INVALIDCALL;
6323 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6325 color_fill_fbo(iface, pSurface, pRect, color);
6329 /* Just forward this to the DirectDraw blitting engine */
6330 memset(&BltFx, 0, sizeof(BltFx));
6331 BltFx.dwSize = sizeof(BltFx);
6332 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6333 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6337 /* rendertarget and depth stencil functions */
6338 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6341 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6342 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6343 return WINED3DERR_INVALIDCALL;
6346 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6347 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6348 /* Note inc ref on returned surface */
6349 if(*ppRenderTarget != NULL)
6350 IWineD3DSurface_AddRef(*ppRenderTarget);
6354 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6356 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6357 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6358 IWineD3DSwapChainImpl *Swapchain;
6361 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6363 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6364 if(hr != WINED3D_OK) {
6365 ERR("Can't get the swapchain\n");
6369 /* Make sure to release the swapchain */
6370 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6372 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6373 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6374 return WINED3DERR_INVALIDCALL;
6376 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6377 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6378 return WINED3DERR_INVALIDCALL;
6381 if(Swapchain->frontBuffer != Front) {
6382 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6384 if(Swapchain->frontBuffer)
6385 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6386 Swapchain->frontBuffer = Front;
6388 if(Swapchain->frontBuffer) {
6389 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6393 if(Back && !Swapchain->backBuffer) {
6394 /* We need memory for the back buffer array - only one back buffer this way */
6395 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6396 if(!Swapchain->backBuffer) {
6397 ERR("Out of memory\n");
6398 return E_OUTOFMEMORY;
6402 if(Swapchain->backBuffer[0] != Back) {
6403 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6405 /* What to do about the context here in the case of multithreading? Not sure.
6406 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6409 if(!Swapchain->backBuffer[0]) {
6410 /* GL was told to draw to the front buffer at creation,
6413 glDrawBuffer(GL_BACK);
6414 checkGLcall("glDrawBuffer(GL_BACK)");
6415 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6416 Swapchain->presentParms.BackBufferCount = 1;
6418 /* That makes problems - disable for now */
6419 /* glDrawBuffer(GL_FRONT); */
6420 checkGLcall("glDrawBuffer(GL_FRONT)");
6421 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6422 Swapchain->presentParms.BackBufferCount = 0;
6426 if(Swapchain->backBuffer[0])
6427 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6428 Swapchain->backBuffer[0] = Back;
6430 if(Swapchain->backBuffer[0]) {
6431 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6433 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6434 Swapchain->backBuffer = NULL;
6442 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6444 *ppZStencilSurface = This->stencilBufferTarget;
6445 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6447 if(*ppZStencilSurface != NULL) {
6448 /* Note inc ref on returned surface */
6449 IWineD3DSurface_AddRef(*ppZStencilSurface);
6452 return WINED3DERR_NOTFOUND;
6456 /* TODO: Handle stencil attachments */
6457 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6460 TRACE("Set depth stencil to %p\n", depth_stencil);
6462 if (depth_stencil) {
6463 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6465 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6466 checkGLcall("glFramebufferTexture2DEXT()");
6470 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6473 TRACE("Set render target %u to %p\n", idx, render_target);
6475 if (render_target) {
6476 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6477 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6479 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6480 checkGLcall("glFramebufferTexture2DEXT()");
6482 This->draw_buffers[idx] = GL_NONE;
6486 static void check_fbo_status(IWineD3DDevice *iface) {
6487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6490 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6491 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6492 TRACE("FBO complete\n");
6494 IWineD3DSurfaceImpl *attachment;
6496 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6498 /* Dump the FBO attachments */
6499 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6500 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6502 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6503 attachment->pow2Width, attachment->pow2Height);
6506 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6508 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6509 attachment->pow2Width, attachment->pow2Height);
6514 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6516 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6517 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6519 if (!ds_impl) return FALSE;
6521 if (ds_impl->current_renderbuffer) {
6522 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6523 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6526 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6527 rt_impl->pow2Height != ds_impl->pow2Height);
6530 void apply_fbo_state(IWineD3DDevice *iface) {
6531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6534 if (This->render_offscreen) {
6535 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6537 /* Apply render targets */
6538 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6539 IWineD3DSurface *render_target = This->render_targets[i];
6540 if (This->fbo_color_attachments[i] != render_target) {
6541 set_render_target_fbo(iface, i, render_target);
6542 This->fbo_color_attachments[i] = render_target;
6546 /* Apply depth targets */
6547 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6548 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6549 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6551 if (This->stencilBufferTarget) {
6552 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6554 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6555 This->fbo_depth_attachment = This->stencilBufferTarget;
6558 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6559 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6560 checkGLcall("glDrawBuffers()");
6562 glDrawBuffer(This->draw_buffers[0]);
6563 checkGLcall("glDrawBuffer()");
6566 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6569 check_fbo_status(iface);
6572 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6573 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6575 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6576 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6579 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6580 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6581 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6582 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6585 case WINED3DTEXF_LINEAR:
6586 gl_filter = GL_LINEAR;
6590 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6591 case WINED3DTEXF_NONE:
6592 case WINED3DTEXF_POINT:
6593 gl_filter = GL_NEAREST;
6597 /* Attach src surface to src fbo */
6598 src_swapchain = get_swapchain(src_surface);
6599 if (src_swapchain) {
6602 TRACE("Source surface %p is onscreen\n", src_surface);
6603 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6604 /* Make sure the drawable is up to date. In the offscreen case
6605 * attach_surface_fbo() implicitly takes care of this. */
6606 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6609 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6610 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6611 glReadBuffer(buffer);
6612 checkGLcall("glReadBuffer()");
6614 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6615 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6617 TRACE("Source surface %p is offscreen\n", src_surface);
6619 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6620 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6621 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6622 checkGLcall("glReadBuffer()");
6623 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6624 checkGLcall("glFramebufferRenderbufferEXT");
6628 /* Attach dst surface to dst fbo */
6629 dst_swapchain = get_swapchain(dst_surface);
6630 if (dst_swapchain) {
6633 TRACE("Destination surface %p is onscreen\n", dst_surface);
6634 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6635 /* Make sure the drawable is up to date. In the offscreen case
6636 * attach_surface_fbo() implicitly takes care of this. */
6637 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6640 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6641 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6642 glDrawBuffer(buffer);
6643 checkGLcall("glDrawBuffer()");
6645 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6646 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6648 TRACE("Destination surface %p is offscreen\n", dst_surface);
6650 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6651 if(!src_swapchain) {
6652 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6656 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6657 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6658 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6659 checkGLcall("glDrawBuffer()");
6660 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6661 checkGLcall("glFramebufferRenderbufferEXT");
6663 glDisable(GL_SCISSOR_TEST);
6664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6667 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6668 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6669 checkGLcall("glBlitFramebuffer()");
6671 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6672 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6673 checkGLcall("glBlitFramebuffer()");
6676 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6678 if (This->render_offscreen) {
6679 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6681 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6682 checkGLcall("glBindFramebuffer()");
6685 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6686 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6687 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6688 glDrawBuffer(GL_BACK);
6689 checkGLcall("glDrawBuffer()");
6694 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6696 WINED3DVIEWPORT viewport;
6698 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6700 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6701 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6702 This, RenderTargetIndex, GL_LIMITS(buffers));
6703 return WINED3DERR_INVALIDCALL;
6706 /* MSDN says that null disables the render target
6707 but a device must always be associated with a render target
6708 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6710 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6711 FIXME("Trying to set render target 0 to NULL\n");
6712 return WINED3DERR_INVALIDCALL;
6714 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6715 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);
6716 return WINED3DERR_INVALIDCALL;
6719 /* If we are trying to set what we already have, don't bother */
6720 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6721 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6724 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6725 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6726 This->render_targets[RenderTargetIndex] = pRenderTarget;
6728 /* Render target 0 is special */
6729 if(RenderTargetIndex == 0) {
6730 /* Finally, reset the viewport as the MSDN states. */
6731 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6732 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6735 viewport.MaxZ = 1.0f;
6736 viewport.MinZ = 0.0f;
6737 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6738 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6739 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6746 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6748 HRESULT hr = WINED3D_OK;
6749 IWineD3DSurface *tmp;
6751 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6753 if (pNewZStencil == This->stencilBufferTarget) {
6754 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6756 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6757 * depending on the renter target implementation being used.
6758 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6759 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6760 * stencil buffer and incur an extra memory overhead
6761 ******************************************************/
6763 if (This->stencilBufferTarget) {
6764 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6765 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6766 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6769 tmp = This->stencilBufferTarget;
6770 This->stencilBufferTarget = pNewZStencil;
6771 /* should we be calling the parent or the wined3d surface? */
6772 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6773 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6776 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6777 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6787 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6788 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6790 /* TODO: the use of Impl is deprecated. */
6791 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6792 WINED3DLOCKED_RECT lockedRect;
6794 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6796 /* some basic validation checks */
6797 if(This->cursorTexture) {
6798 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6800 glDeleteTextures(1, &This->cursorTexture);
6802 This->cursorTexture = 0;
6805 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6806 This->haveHardwareCursor = TRUE;
6808 This->haveHardwareCursor = FALSE;
6811 WINED3DLOCKED_RECT rect;
6813 /* MSDN: Cursor must be A8R8G8B8 */
6814 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6815 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6816 return WINED3DERR_INVALIDCALL;
6819 /* MSDN: Cursor must be smaller than the display mode */
6820 if(pSur->currentDesc.Width > This->ddraw_width ||
6821 pSur->currentDesc.Height > This->ddraw_height) {
6822 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);
6823 return WINED3DERR_INVALIDCALL;
6826 if (!This->haveHardwareCursor) {
6827 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6829 /* Do not store the surface's pointer because the application may
6830 * release it after setting the cursor image. Windows doesn't
6831 * addref the set surface, so we can't do this either without
6832 * creating circular refcount dependencies. Copy out the gl texture
6835 This->cursorWidth = pSur->currentDesc.Width;
6836 This->cursorHeight = pSur->currentDesc.Height;
6837 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6839 const GlPixelFormatDesc *glDesc;
6840 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6841 char *mem, *bits = (char *)rect.pBits;
6842 GLint intfmt = glDesc->glInternal;
6843 GLint format = glDesc->glFormat;
6844 GLint type = glDesc->glType;
6845 INT height = This->cursorHeight;
6846 INT width = This->cursorWidth;
6847 INT bpp = tableEntry->bpp;
6850 /* Reformat the texture memory (pitch and width can be
6852 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6853 for(i = 0; i < height; i++)
6854 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6855 IWineD3DSurface_UnlockRect(pCursorBitmap);
6858 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6859 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6860 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6863 /* Make sure that a proper texture unit is selected */
6864 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6865 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6866 checkGLcall("glActiveTextureARB");
6868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6869 /* Create a new cursor texture */
6870 glGenTextures(1, &This->cursorTexture);
6871 checkGLcall("glGenTextures");
6872 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6873 checkGLcall("glBindTexture");
6874 /* Copy the bitmap memory into the cursor texture */
6875 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6876 HeapFree(GetProcessHeap(), 0, mem);
6877 checkGLcall("glTexImage2D");
6879 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6880 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6881 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6888 FIXME("A cursor texture was not returned.\n");
6889 This->cursorTexture = 0;
6894 /* Draw a hardware cursor */
6895 ICONINFO cursorInfo;
6897 /* Create and clear maskBits because it is not needed for
6898 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6900 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6901 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6902 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6903 WINED3DLOCK_NO_DIRTY_UPDATE |
6904 WINED3DLOCK_READONLY
6906 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6907 pSur->currentDesc.Height);
6909 cursorInfo.fIcon = FALSE;
6910 cursorInfo.xHotspot = XHotSpot;
6911 cursorInfo.yHotspot = YHotSpot;
6912 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6913 pSur->currentDesc.Height, 1,
6915 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6916 pSur->currentDesc.Height, 1,
6917 32, lockedRect.pBits);
6918 IWineD3DSurface_UnlockRect(pCursorBitmap);
6919 /* Create our cursor and clean up. */
6920 cursor = CreateIconIndirect(&cursorInfo);
6922 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6923 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6924 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6925 This->hardwareCursor = cursor;
6926 HeapFree(GetProcessHeap(), 0, maskBits);
6930 This->xHotSpot = XHotSpot;
6931 This->yHotSpot = YHotSpot;
6935 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6937 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6939 This->xScreenSpace = XScreenSpace;
6940 This->yScreenSpace = YScreenSpace;
6946 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6948 BOOL oldVisible = This->bCursorVisible;
6951 TRACE("(%p) : visible(%d)\n", This, bShow);
6954 * When ShowCursor is first called it should make the cursor appear at the OS's last
6955 * known cursor position. Because of this, some applications just repetitively call
6956 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6959 This->xScreenSpace = pt.x;
6960 This->yScreenSpace = pt.y;
6962 if (This->haveHardwareCursor) {
6963 This->bCursorVisible = bShow;
6965 SetCursor(This->hardwareCursor);
6971 if (This->cursorTexture)
6972 This->bCursorVisible = bShow;
6978 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6980 IWineD3DResourceImpl *resource;
6981 TRACE("(%p) : state (%u)\n", This, This->state);
6983 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6984 switch (This->state) {
6987 case WINED3DERR_DEVICELOST:
6989 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6990 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6991 return WINED3DERR_DEVICENOTRESET;
6993 return WINED3DERR_DEVICELOST;
6995 case WINED3DERR_DRIVERINTERNALERROR:
6996 return WINED3DERR_DRIVERINTERNALERROR;
7000 return WINED3DERR_DRIVERINTERNALERROR;
7004 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7006 /** FIXME: Resource tracking needs to be done,
7007 * The closes we can do to this is set the priorities of all managed textures low
7008 * and then reset them.
7009 ***********************************************************/
7010 FIXME("(%p) : stub\n", This);
7014 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7015 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7017 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7018 if(surface->Flags & SFLAG_DIBSECTION) {
7019 /* Release the DC */
7020 SelectObject(surface->hDC, surface->dib.holdbitmap);
7021 DeleteDC(surface->hDC);
7022 /* Release the DIB section */
7023 DeleteObject(surface->dib.DIBsection);
7024 surface->dib.bitmap_data = NULL;
7025 surface->resource.allocatedMemory = NULL;
7026 surface->Flags &= ~SFLAG_DIBSECTION;
7028 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7029 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7030 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
7031 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7032 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7034 surface->pow2Width = surface->pow2Height = 1;
7035 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7036 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7038 surface->glRect.left = 0;
7039 surface->glRect.top = 0;
7040 surface->glRect.right = surface->pow2Width;
7041 surface->glRect.bottom = surface->pow2Height;
7043 if(surface->glDescription.textureName) {
7044 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7046 glDeleteTextures(1, &surface->glDescription.textureName);
7048 surface->glDescription.textureName = 0;
7049 surface->Flags &= ~SFLAG_CLIENT;
7051 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7052 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7053 surface->Flags |= SFLAG_NONPOW2;
7055 surface->Flags &= ~SFLAG_NONPOW2;
7057 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7058 surface->resource.allocatedMemory = NULL;
7059 surface->resource.heapMemory = NULL;
7060 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7061 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7062 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7063 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7065 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7069 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7070 TRACE("Unloading resource %p\n", resource);
7071 IWineD3DResource_UnLoad(resource);
7072 IWineD3DResource_Release(resource);
7076 static void reset_fbo_state(IWineD3DDevice *iface) {
7077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7081 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7082 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7085 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7088 if (This->src_fbo) {
7089 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7092 if (This->dst_fbo) {
7093 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7096 checkGLcall("Tear down FBOs\n");
7099 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7100 This->fbo_color_attachments[i] = NULL;
7102 This->fbo_depth_attachment = NULL;
7105 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7107 WINED3DDISPLAYMODE m;
7110 /* All Windowed modes are supported, as is leaving the current mode */
7111 if(pp->Windowed) return TRUE;
7112 if(!pp->BackBufferWidth) return TRUE;
7113 if(!pp->BackBufferHeight) return TRUE;
7115 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7116 for(i = 0; i < count; i++) {
7117 memset(&m, 0, sizeof(m));
7118 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7120 ERR("EnumAdapterModes failed\n");
7122 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7123 /* Mode found, it is supported */
7127 /* Mode not found -> not supported */
7131 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7133 IWineD3DSwapChainImpl *swapchain;
7135 BOOL DisplayModeChanged = FALSE;
7136 WINED3DDISPLAYMODE mode;
7137 IWineD3DBaseShaderImpl *shader;
7138 IWineD3DSurfaceImpl *target;
7140 TRACE("(%p)\n", This);
7142 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7144 ERR("Failed to get the first implicit swapchain\n");
7148 if(!is_display_mode_supported(This, pPresentationParameters)) {
7149 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7150 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7151 pPresentationParameters->BackBufferHeight);
7152 return WINED3DERR_INVALIDCALL;
7155 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7156 * on an existing gl context, so there's no real need for recreation.
7158 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7160 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7162 TRACE("New params:\n");
7163 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7164 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7165 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7166 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7167 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7168 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7169 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7170 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7171 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7172 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7173 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7174 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7175 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7177 /* No special treatment of these parameters. Just store them */
7178 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7179 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7180 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7181 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7183 /* What to do about these? */
7184 if(pPresentationParameters->BackBufferCount != 0 &&
7185 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7186 ERR("Cannot change the back buffer count yet\n");
7188 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7189 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7190 ERR("Cannot change the back buffer format yet\n");
7192 if(pPresentationParameters->hDeviceWindow != NULL &&
7193 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7194 ERR("Cannot change the device window yet\n");
7196 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7197 ERR("What do do about a changed auto depth stencil parameter?\n");
7200 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7201 reset_fbo_state((IWineD3DDevice *) This);
7204 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7205 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7206 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7210 if(This->depth_blt_texture) {
7211 glDeleteTextures(1, &This->depth_blt_texture);
7212 This->depth_blt_texture = 0;
7214 if (This->depth_blt_rb) {
7215 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7216 This->depth_blt_rb = 0;
7217 This->depth_blt_rb_w = 0;
7218 This->depth_blt_rb_h = 0;
7220 This->shader_backend->shader_free_private(iface);
7222 for (i = 0; i < GL_LIMITS(textures); i++) {
7223 /* Textures are recreated below */
7224 glDeleteTextures(1, &This->dummyTextureName[i]);
7225 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7226 This->dummyTextureName[i] = 0;
7230 while(This->numContexts) {
7231 DestroyContext(This, This->contexts[0]);
7233 This->activeContext = NULL;
7234 HeapFree(GetProcessHeap(), 0, swapchain->context);
7235 swapchain->context = NULL;
7236 swapchain->num_contexts = 0;
7238 if(pPresentationParameters->Windowed) {
7239 mode.Width = swapchain->orig_width;
7240 mode.Height = swapchain->orig_height;
7241 mode.RefreshRate = 0;
7242 mode.Format = swapchain->presentParms.BackBufferFormat;
7244 mode.Width = pPresentationParameters->BackBufferWidth;
7245 mode.Height = pPresentationParameters->BackBufferHeight;
7246 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7247 mode.Format = swapchain->presentParms.BackBufferFormat;
7250 /* Should Width == 800 && Height == 0 set 800x600? */
7251 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7252 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7253 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7260 vp.Width = pPresentationParameters->BackBufferWidth;
7261 vp.Height = pPresentationParameters->BackBufferHeight;
7265 if(!pPresentationParameters->Windowed) {
7266 DisplayModeChanged = TRUE;
7268 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7269 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7271 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7272 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7273 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7275 if(This->auto_depth_stencil_buffer) {
7276 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7280 /* Now set the new viewport */
7281 IWineD3DDevice_SetViewport(iface, &vp);
7284 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7285 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7286 DisplayModeChanged) {
7288 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7289 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7290 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7291 } else if(!pPresentationParameters->Windowed) {
7292 DWORD style = This->style, exStyle = This->exStyle;
7293 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7294 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7295 * Reset to clear up their mess. Guild Wars also loses the device during that.
7299 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7300 This->style = style;
7301 This->exStyle = exStyle;
7304 /* Recreate the primary swapchain's context */
7305 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7306 if(swapchain->backBuffer) {
7307 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7309 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7311 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7312 &swapchain->presentParms);
7313 swapchain->num_contexts = 1;
7314 This->activeContext = swapchain->context[0];
7315 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7317 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7319 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7321 create_dummy_textures(This);
7324 hr = This->shader_backend->shader_alloc_private(iface);
7326 ERR("Failed to recreate shader private data\n");
7330 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7336 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7338 /** FIXME: always true at the moment **/
7339 if(!bEnableDialogs) {
7340 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7346 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7348 TRACE("(%p) : pParameters %p\n", This, pParameters);
7350 *pParameters = This->createParms;
7354 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7355 IWineD3DSwapChain *swapchain;
7357 TRACE("Relaying to swapchain\n");
7359 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7360 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7361 IWineD3DSwapChain_Release(swapchain);
7366 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7367 IWineD3DSwapChain *swapchain;
7369 TRACE("Relaying to swapchain\n");
7371 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7372 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7373 IWineD3DSwapChain_Release(swapchain);
7379 /** ********************************************************
7380 * Notification functions
7381 ** ********************************************************/
7382 /** This function must be called in the release of a resource when ref == 0,
7383 * the contents of resource must still be correct,
7384 * any handles to other resource held by the caller must be closed
7385 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7386 *****************************************************/
7387 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7390 TRACE("(%p) : Adding Resource %p\n", This, resource);
7391 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7394 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7397 TRACE("(%p) : Removing resource %p\n", This, resource);
7399 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7403 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7407 TRACE("(%p) : resource %p\n", This, resource);
7408 switch(IWineD3DResource_GetType(resource)){
7409 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7410 case WINED3DRTYPE_SURFACE: {
7413 /* Cleanup any FBO attachments if d3d is enabled */
7414 if(This->d3d_initialized) {
7415 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7416 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7418 TRACE("Last active render target destroyed\n");
7419 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7420 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7421 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7422 * and the lastActiveRenderTarget member shouldn't matter
7425 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7426 TRACE("Activating primary back buffer\n");
7427 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7428 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7429 /* Single buffering environment */
7430 TRACE("Activating primary front buffer\n");
7431 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7433 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7434 /* Implicit render target destroyed, that means the device is being destroyed
7435 * whatever we set here, it shouldn't matter
7437 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7440 /* May happen during ddraw uninitialization */
7441 TRACE("Render target set, but swapchain does not exist!\n");
7442 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7447 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7448 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7449 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7450 set_render_target_fbo(iface, i, NULL);
7451 This->fbo_color_attachments[i] = NULL;
7454 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7455 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7456 set_depth_stencil_fbo(iface, NULL);
7457 This->fbo_depth_attachment = NULL;
7464 case WINED3DRTYPE_TEXTURE:
7465 case WINED3DRTYPE_CUBETEXTURE:
7466 case WINED3DRTYPE_VOLUMETEXTURE:
7467 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7468 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7469 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7470 This->stateBlock->textures[counter] = NULL;
7472 if (This->updateStateBlock != This->stateBlock ){
7473 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7474 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7475 This->updateStateBlock->textures[counter] = NULL;
7480 case WINED3DRTYPE_VOLUME:
7481 /* TODO: nothing really? */
7483 case WINED3DRTYPE_VERTEXBUFFER:
7484 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7487 TRACE("Cleaning up stream pointers\n");
7489 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7490 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7491 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7493 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7494 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7495 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7496 This->updateStateBlock->streamSource[streamNumber] = 0;
7497 /* Set changed flag? */
7500 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) */
7501 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7502 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7503 This->stateBlock->streamSource[streamNumber] = 0;
7506 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7507 else { /* This shouldn't happen */
7508 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7515 case WINED3DRTYPE_INDEXBUFFER:
7516 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7517 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7518 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7519 This->updateStateBlock->pIndexData = NULL;
7522 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7523 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7524 This->stateBlock->pIndexData = NULL;
7530 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7535 /* Remove the resource from the resourceStore */
7536 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7538 TRACE("Resource released\n");
7542 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7544 IWineD3DResourceImpl *resource, *cursor;
7546 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7548 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7549 TRACE("enumerating resource %p\n", resource);
7550 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7551 ret = pCallback((IWineD3DResource *) resource, pData);
7552 if(ret == S_FALSE) {
7553 TRACE("Canceling enumeration\n");
7560 /**********************************************************
7561 * IWineD3DDevice VTbl follows
7562 **********************************************************/
7564 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7566 /*** IUnknown methods ***/
7567 IWineD3DDeviceImpl_QueryInterface,
7568 IWineD3DDeviceImpl_AddRef,
7569 IWineD3DDeviceImpl_Release,
7570 /*** IWineD3DDevice methods ***/
7571 IWineD3DDeviceImpl_GetParent,
7572 /*** Creation methods**/
7573 IWineD3DDeviceImpl_CreateVertexBuffer,
7574 IWineD3DDeviceImpl_CreateIndexBuffer,
7575 IWineD3DDeviceImpl_CreateStateBlock,
7576 IWineD3DDeviceImpl_CreateSurface,
7577 IWineD3DDeviceImpl_CreateTexture,
7578 IWineD3DDeviceImpl_CreateVolumeTexture,
7579 IWineD3DDeviceImpl_CreateVolume,
7580 IWineD3DDeviceImpl_CreateCubeTexture,
7581 IWineD3DDeviceImpl_CreateQuery,
7582 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7583 IWineD3DDeviceImpl_CreateVertexDeclaration,
7584 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7585 IWineD3DDeviceImpl_CreateVertexShader,
7586 IWineD3DDeviceImpl_CreatePixelShader,
7587 IWineD3DDeviceImpl_CreatePalette,
7588 /*** Odd functions **/
7589 IWineD3DDeviceImpl_Init3D,
7590 IWineD3DDeviceImpl_Uninit3D,
7591 IWineD3DDeviceImpl_SetFullscreen,
7592 IWineD3DDeviceImpl_SetMultithreaded,
7593 IWineD3DDeviceImpl_EvictManagedResources,
7594 IWineD3DDeviceImpl_GetAvailableTextureMem,
7595 IWineD3DDeviceImpl_GetBackBuffer,
7596 IWineD3DDeviceImpl_GetCreationParameters,
7597 IWineD3DDeviceImpl_GetDeviceCaps,
7598 IWineD3DDeviceImpl_GetDirect3D,
7599 IWineD3DDeviceImpl_GetDisplayMode,
7600 IWineD3DDeviceImpl_SetDisplayMode,
7601 IWineD3DDeviceImpl_GetHWND,
7602 IWineD3DDeviceImpl_SetHWND,
7603 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7604 IWineD3DDeviceImpl_GetRasterStatus,
7605 IWineD3DDeviceImpl_GetSwapChain,
7606 IWineD3DDeviceImpl_Reset,
7607 IWineD3DDeviceImpl_SetDialogBoxMode,
7608 IWineD3DDeviceImpl_SetCursorProperties,
7609 IWineD3DDeviceImpl_SetCursorPosition,
7610 IWineD3DDeviceImpl_ShowCursor,
7611 IWineD3DDeviceImpl_TestCooperativeLevel,
7612 /*** Getters and setters **/
7613 IWineD3DDeviceImpl_SetClipPlane,
7614 IWineD3DDeviceImpl_GetClipPlane,
7615 IWineD3DDeviceImpl_SetClipStatus,
7616 IWineD3DDeviceImpl_GetClipStatus,
7617 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7618 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7619 IWineD3DDeviceImpl_SetDepthStencilSurface,
7620 IWineD3DDeviceImpl_GetDepthStencilSurface,
7621 IWineD3DDeviceImpl_SetFVF,
7622 IWineD3DDeviceImpl_GetFVF,
7623 IWineD3DDeviceImpl_SetGammaRamp,
7624 IWineD3DDeviceImpl_GetGammaRamp,
7625 IWineD3DDeviceImpl_SetIndices,
7626 IWineD3DDeviceImpl_GetIndices,
7627 IWineD3DDeviceImpl_SetBaseVertexIndex,
7628 IWineD3DDeviceImpl_GetBaseVertexIndex,
7629 IWineD3DDeviceImpl_SetLight,
7630 IWineD3DDeviceImpl_GetLight,
7631 IWineD3DDeviceImpl_SetLightEnable,
7632 IWineD3DDeviceImpl_GetLightEnable,
7633 IWineD3DDeviceImpl_SetMaterial,
7634 IWineD3DDeviceImpl_GetMaterial,
7635 IWineD3DDeviceImpl_SetNPatchMode,
7636 IWineD3DDeviceImpl_GetNPatchMode,
7637 IWineD3DDeviceImpl_SetPaletteEntries,
7638 IWineD3DDeviceImpl_GetPaletteEntries,
7639 IWineD3DDeviceImpl_SetPixelShader,
7640 IWineD3DDeviceImpl_GetPixelShader,
7641 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7642 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7643 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7644 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7645 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7646 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7647 IWineD3DDeviceImpl_SetRenderState,
7648 IWineD3DDeviceImpl_GetRenderState,
7649 IWineD3DDeviceImpl_SetRenderTarget,
7650 IWineD3DDeviceImpl_GetRenderTarget,
7651 IWineD3DDeviceImpl_SetFrontBackBuffers,
7652 IWineD3DDeviceImpl_SetSamplerState,
7653 IWineD3DDeviceImpl_GetSamplerState,
7654 IWineD3DDeviceImpl_SetScissorRect,
7655 IWineD3DDeviceImpl_GetScissorRect,
7656 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7657 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7658 IWineD3DDeviceImpl_SetStreamSource,
7659 IWineD3DDeviceImpl_GetStreamSource,
7660 IWineD3DDeviceImpl_SetStreamSourceFreq,
7661 IWineD3DDeviceImpl_GetStreamSourceFreq,
7662 IWineD3DDeviceImpl_SetTexture,
7663 IWineD3DDeviceImpl_GetTexture,
7664 IWineD3DDeviceImpl_SetTextureStageState,
7665 IWineD3DDeviceImpl_GetTextureStageState,
7666 IWineD3DDeviceImpl_SetTransform,
7667 IWineD3DDeviceImpl_GetTransform,
7668 IWineD3DDeviceImpl_SetVertexDeclaration,
7669 IWineD3DDeviceImpl_GetVertexDeclaration,
7670 IWineD3DDeviceImpl_SetVertexShader,
7671 IWineD3DDeviceImpl_GetVertexShader,
7672 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7673 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7674 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7675 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7676 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7677 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7678 IWineD3DDeviceImpl_SetViewport,
7679 IWineD3DDeviceImpl_GetViewport,
7680 IWineD3DDeviceImpl_MultiplyTransform,
7681 IWineD3DDeviceImpl_ValidateDevice,
7682 IWineD3DDeviceImpl_ProcessVertices,
7683 /*** State block ***/
7684 IWineD3DDeviceImpl_BeginStateBlock,
7685 IWineD3DDeviceImpl_EndStateBlock,
7686 /*** Scene management ***/
7687 IWineD3DDeviceImpl_BeginScene,
7688 IWineD3DDeviceImpl_EndScene,
7689 IWineD3DDeviceImpl_Present,
7690 IWineD3DDeviceImpl_Clear,
7692 IWineD3DDeviceImpl_DrawPrimitive,
7693 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7694 IWineD3DDeviceImpl_DrawPrimitiveUP,
7695 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7696 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7697 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7698 IWineD3DDeviceImpl_DrawRectPatch,
7699 IWineD3DDeviceImpl_DrawTriPatch,
7700 IWineD3DDeviceImpl_DeletePatch,
7701 IWineD3DDeviceImpl_ColorFill,
7702 IWineD3DDeviceImpl_UpdateTexture,
7703 IWineD3DDeviceImpl_UpdateSurface,
7704 IWineD3DDeviceImpl_GetFrontBufferData,
7705 /*** object tracking ***/
7706 IWineD3DDeviceImpl_ResourceReleased,
7707 IWineD3DDeviceImpl_EnumResources
7710 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7712 /*** IUnknown methods ***/
7713 IWineD3DDeviceImpl_QueryInterface,
7714 IWineD3DDeviceImpl_AddRef,
7715 IWineD3DDeviceImpl_Release,
7716 /*** IWineD3DDevice methods ***/
7717 IWineD3DDeviceImpl_GetParent,
7718 /*** Creation methods**/
7719 IWineD3DDeviceImpl_CreateVertexBuffer,
7720 IWineD3DDeviceImpl_CreateIndexBuffer,
7721 IWineD3DDeviceImpl_CreateStateBlock,
7722 IWineD3DDeviceImpl_CreateSurface,
7723 IWineD3DDeviceImpl_CreateTexture,
7724 IWineD3DDeviceImpl_CreateVolumeTexture,
7725 IWineD3DDeviceImpl_CreateVolume,
7726 IWineD3DDeviceImpl_CreateCubeTexture,
7727 IWineD3DDeviceImpl_CreateQuery,
7728 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7729 IWineD3DDeviceImpl_CreateVertexDeclaration,
7730 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7731 IWineD3DDeviceImpl_CreateVertexShader,
7732 IWineD3DDeviceImpl_CreatePixelShader,
7733 IWineD3DDeviceImpl_CreatePalette,
7734 /*** Odd functions **/
7735 IWineD3DDeviceImpl_Init3D,
7736 IWineD3DDeviceImpl_Uninit3D,
7737 IWineD3DDeviceImpl_SetFullscreen,
7738 IWineD3DDeviceImpl_SetMultithreaded,
7739 IWineD3DDeviceImpl_EvictManagedResources,
7740 IWineD3DDeviceImpl_GetAvailableTextureMem,
7741 IWineD3DDeviceImpl_GetBackBuffer,
7742 IWineD3DDeviceImpl_GetCreationParameters,
7743 IWineD3DDeviceImpl_GetDeviceCaps,
7744 IWineD3DDeviceImpl_GetDirect3D,
7745 IWineD3DDeviceImpl_GetDisplayMode,
7746 IWineD3DDeviceImpl_SetDisplayMode,
7747 IWineD3DDeviceImpl_GetHWND,
7748 IWineD3DDeviceImpl_SetHWND,
7749 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7750 IWineD3DDeviceImpl_GetRasterStatus,
7751 IWineD3DDeviceImpl_GetSwapChain,
7752 IWineD3DDeviceImpl_Reset,
7753 IWineD3DDeviceImpl_SetDialogBoxMode,
7754 IWineD3DDeviceImpl_SetCursorProperties,
7755 IWineD3DDeviceImpl_SetCursorPosition,
7756 IWineD3DDeviceImpl_ShowCursor,
7757 IWineD3DDeviceImpl_TestCooperativeLevel,
7758 /*** Getters and setters **/
7759 IWineD3DDeviceImpl_SetClipPlane,
7760 IWineD3DDeviceImpl_GetClipPlane,
7761 IWineD3DDeviceImpl_SetClipStatus,
7762 IWineD3DDeviceImpl_GetClipStatus,
7763 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7764 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7765 IWineD3DDeviceImpl_SetDepthStencilSurface,
7766 IWineD3DDeviceImpl_GetDepthStencilSurface,
7767 IWineD3DDeviceImpl_SetFVF,
7768 IWineD3DDeviceImpl_GetFVF,
7769 IWineD3DDeviceImpl_SetGammaRamp,
7770 IWineD3DDeviceImpl_GetGammaRamp,
7771 IWineD3DDeviceImpl_SetIndices,
7772 IWineD3DDeviceImpl_GetIndices,
7773 IWineD3DDeviceImpl_SetBaseVertexIndex,
7774 IWineD3DDeviceImpl_GetBaseVertexIndex,
7775 IWineD3DDeviceImpl_SetLight,
7776 IWineD3DDeviceImpl_GetLight,
7777 IWineD3DDeviceImpl_SetLightEnable,
7778 IWineD3DDeviceImpl_GetLightEnable,
7779 IWineD3DDeviceImpl_SetMaterial,
7780 IWineD3DDeviceImpl_GetMaterial,
7781 IWineD3DDeviceImpl_SetNPatchMode,
7782 IWineD3DDeviceImpl_GetNPatchMode,
7783 IWineD3DDeviceImpl_SetPaletteEntries,
7784 IWineD3DDeviceImpl_GetPaletteEntries,
7785 IWineD3DDeviceImpl_SetPixelShader,
7786 IWineD3DDeviceImpl_GetPixelShader,
7787 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7788 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7789 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7790 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7791 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7792 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7793 IWineD3DDeviceImpl_SetRenderState,
7794 IWineD3DDeviceImpl_GetRenderState,
7795 IWineD3DDeviceImpl_SetRenderTarget,
7796 IWineD3DDeviceImpl_GetRenderTarget,
7797 IWineD3DDeviceImpl_SetFrontBackBuffers,
7798 IWineD3DDeviceImpl_SetSamplerState,
7799 IWineD3DDeviceImpl_GetSamplerState,
7800 IWineD3DDeviceImpl_SetScissorRect,
7801 IWineD3DDeviceImpl_GetScissorRect,
7802 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7803 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7804 IWineD3DDeviceImpl_SetStreamSource,
7805 IWineD3DDeviceImpl_GetStreamSource,
7806 IWineD3DDeviceImpl_SetStreamSourceFreq,
7807 IWineD3DDeviceImpl_GetStreamSourceFreq,
7808 IWineD3DDeviceImpl_SetTexture,
7809 IWineD3DDeviceImpl_GetTexture,
7810 IWineD3DDeviceImpl_SetTextureStageState,
7811 IWineD3DDeviceImpl_GetTextureStageState,
7812 IWineD3DDeviceImpl_SetTransform,
7813 IWineD3DDeviceImpl_GetTransform,
7814 IWineD3DDeviceImpl_SetVertexDeclaration,
7815 IWineD3DDeviceImpl_GetVertexDeclaration,
7816 IWineD3DDeviceImpl_SetVertexShader,
7817 IWineD3DDeviceImpl_GetVertexShader,
7818 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7819 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7820 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7821 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7822 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7823 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7824 IWineD3DDeviceImpl_SetViewport,
7825 IWineD3DDeviceImpl_GetViewport,
7826 IWineD3DDeviceImpl_MultiplyTransform,
7827 IWineD3DDeviceImpl_ValidateDevice,
7828 IWineD3DDeviceImpl_ProcessVertices,
7829 /*** State block ***/
7830 IWineD3DDeviceImpl_BeginStateBlock,
7831 IWineD3DDeviceImpl_EndStateBlock,
7832 /*** Scene management ***/
7833 IWineD3DDeviceImpl_BeginScene,
7834 IWineD3DDeviceImpl_EndScene,
7835 IWineD3DDeviceImpl_Present,
7836 IWineD3DDeviceImpl_Clear,
7838 IWineD3DDeviceImpl_DrawPrimitive,
7839 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7840 IWineD3DDeviceImpl_DrawPrimitiveUP,
7841 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7842 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7843 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7844 IWineD3DDeviceImpl_DrawRectPatch,
7845 IWineD3DDeviceImpl_DrawTriPatch,
7846 IWineD3DDeviceImpl_DeletePatch,
7847 IWineD3DDeviceImpl_ColorFill,
7848 IWineD3DDeviceImpl_UpdateTexture,
7849 IWineD3DDeviceImpl_UpdateSurface,
7850 IWineD3DDeviceImpl_GetFrontBufferData,
7851 /*** object tracking ***/
7852 IWineD3DDeviceImpl_ResourceReleased,
7853 IWineD3DDeviceImpl_EnumResources
7856 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7857 WINED3DRS_ALPHABLENDENABLE ,
7858 WINED3DRS_ALPHAFUNC ,
7859 WINED3DRS_ALPHAREF ,
7860 WINED3DRS_ALPHATESTENABLE ,
7862 WINED3DRS_COLORWRITEENABLE ,
7863 WINED3DRS_DESTBLEND ,
7864 WINED3DRS_DITHERENABLE ,
7865 WINED3DRS_FILLMODE ,
7866 WINED3DRS_FOGDENSITY ,
7868 WINED3DRS_FOGSTART ,
7869 WINED3DRS_LASTPIXEL ,
7870 WINED3DRS_SHADEMODE ,
7871 WINED3DRS_SRCBLEND ,
7872 WINED3DRS_STENCILENABLE ,
7873 WINED3DRS_STENCILFAIL ,
7874 WINED3DRS_STENCILFUNC ,
7875 WINED3DRS_STENCILMASK ,
7876 WINED3DRS_STENCILPASS ,
7877 WINED3DRS_STENCILREF ,
7878 WINED3DRS_STENCILWRITEMASK ,
7879 WINED3DRS_STENCILZFAIL ,
7880 WINED3DRS_TEXTUREFACTOR ,
7891 WINED3DRS_ZWRITEENABLE
7894 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7895 WINED3DTSS_ADDRESSW ,
7896 WINED3DTSS_ALPHAARG0 ,
7897 WINED3DTSS_ALPHAARG1 ,
7898 WINED3DTSS_ALPHAARG2 ,
7899 WINED3DTSS_ALPHAOP ,
7900 WINED3DTSS_BUMPENVLOFFSET ,
7901 WINED3DTSS_BUMPENVLSCALE ,
7902 WINED3DTSS_BUMPENVMAT00 ,
7903 WINED3DTSS_BUMPENVMAT01 ,
7904 WINED3DTSS_BUMPENVMAT10 ,
7905 WINED3DTSS_BUMPENVMAT11 ,
7906 WINED3DTSS_COLORARG0 ,
7907 WINED3DTSS_COLORARG1 ,
7908 WINED3DTSS_COLORARG2 ,
7909 WINED3DTSS_COLOROP ,
7910 WINED3DTSS_RESULTARG ,
7911 WINED3DTSS_TEXCOORDINDEX ,
7912 WINED3DTSS_TEXTURETRANSFORMFLAGS
7915 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7916 WINED3DSAMP_ADDRESSU ,
7917 WINED3DSAMP_ADDRESSV ,
7918 WINED3DSAMP_ADDRESSW ,
7919 WINED3DSAMP_BORDERCOLOR ,
7920 WINED3DSAMP_MAGFILTER ,
7921 WINED3DSAMP_MINFILTER ,
7922 WINED3DSAMP_MIPFILTER ,
7923 WINED3DSAMP_MIPMAPLODBIAS ,
7924 WINED3DSAMP_MAXMIPLEVEL ,
7925 WINED3DSAMP_MAXANISOTROPY ,
7926 WINED3DSAMP_SRGBTEXTURE ,
7927 WINED3DSAMP_ELEMENTINDEX
7930 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7932 WINED3DRS_AMBIENTMATERIALSOURCE ,
7933 WINED3DRS_CLIPPING ,
7934 WINED3DRS_CLIPPLANEENABLE ,
7935 WINED3DRS_COLORVERTEX ,
7936 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7937 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7938 WINED3DRS_FOGDENSITY ,
7940 WINED3DRS_FOGSTART ,
7941 WINED3DRS_FOGTABLEMODE ,
7942 WINED3DRS_FOGVERTEXMODE ,
7943 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7944 WINED3DRS_LIGHTING ,
7945 WINED3DRS_LOCALVIEWER ,
7946 WINED3DRS_MULTISAMPLEANTIALIAS ,
7947 WINED3DRS_MULTISAMPLEMASK ,
7948 WINED3DRS_NORMALIZENORMALS ,
7949 WINED3DRS_PATCHEDGESTYLE ,
7950 WINED3DRS_POINTSCALE_A ,
7951 WINED3DRS_POINTSCALE_B ,
7952 WINED3DRS_POINTSCALE_C ,
7953 WINED3DRS_POINTSCALEENABLE ,
7954 WINED3DRS_POINTSIZE ,
7955 WINED3DRS_POINTSIZE_MAX ,
7956 WINED3DRS_POINTSIZE_MIN ,
7957 WINED3DRS_POINTSPRITEENABLE ,
7958 WINED3DRS_RANGEFOGENABLE ,
7959 WINED3DRS_SPECULARMATERIALSOURCE ,
7960 WINED3DRS_TWEENFACTOR ,
7961 WINED3DRS_VERTEXBLEND ,
7962 WINED3DRS_CULLMODE ,
7966 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7967 WINED3DTSS_TEXCOORDINDEX ,
7968 WINED3DTSS_TEXTURETRANSFORMFLAGS
7971 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7972 WINED3DSAMP_DMAPOFFSET
7975 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7976 DWORD rep = This->StateTable[state].representative;
7980 WineD3DContext *context;
7983 for(i = 0; i < This->numContexts; i++) {
7984 context = This->contexts[i];
7985 if(isStateDirty(context, rep)) continue;
7987 context->dirtyArray[context->numDirtyEntries++] = rep;
7990 context->isStateDirty[idx] |= (1 << shift);
7994 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7995 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7996 /* The drawable size of a pbuffer render target is the current pbuffer size
7998 *width = dev->pbufferWidth;
7999 *height = dev->pbufferHeight;
8002 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8003 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8005 *width = This->pow2Width;
8006 *height = This->pow2Height;
8009 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8010 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8011 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8012 * current context's drawable, which is the size of the back buffer of the swapchain
8013 * the active context belongs to. The back buffer of the swapchain is stored as the
8014 * surface the context belongs to.
8016 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8017 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;