2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
210 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
211 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
212 GLenum error, glUsage;
213 DWORD vboUsage = object->resource.usage;
214 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
215 WARN("Creating a vbo failed once, not trying again\n");
219 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
221 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
222 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
225 /* Make sure that the gl error is cleared. Do not use checkGLcall
226 * here because checkGLcall just prints a fixme and continues. However,
227 * if an error during VBO creation occurs we can fall back to non-vbo operation
228 * with full functionality(but performance loss)
230 while(glGetError() != GL_NO_ERROR);
232 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
233 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
234 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
235 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
236 * to check if the rhw and color values are in the correct format.
239 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
240 error = glGetError();
241 if(object->vbo == 0 || error != GL_NO_ERROR) {
242 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
246 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
247 error = glGetError();
248 if(error != GL_NO_ERROR) {
249 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
253 /* Don't use static, because dx apps tend to update the buffer
254 * quite often even if they specify 0 usage. Because we always keep the local copy
255 * we never read from the vbo and can create a write only opengl buffer.
257 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
258 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
259 case WINED3DUSAGE_DYNAMIC:
260 TRACE("Gl usage = GL_STREAM_DRAW\n");
261 glUsage = GL_STREAM_DRAW_ARB;
263 case WINED3DUSAGE_WRITEONLY:
265 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
266 glUsage = GL_DYNAMIC_DRAW_ARB;
270 /* Reserve memory for the buffer. The amount of data won't change
271 * so we are safe with calling glBufferData once with a NULL ptr and
272 * calling glBufferSubData on updates
274 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
275 error = glGetError();
276 if(error != GL_NO_ERROR) {
277 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
285 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
286 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
287 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
289 object->Flags |= VBFLAG_VBOCREATEFAIL;
294 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
295 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
298 IWineD3DVertexBufferImpl *object;
299 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
300 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
304 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
305 *ppVertexBuffer = NULL;
306 return WINED3DERR_INVALIDCALL;
307 } else if(Pool == WINED3DPOOL_SCRATCH) {
308 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
309 * anyway, SCRATCH vertex buffers aren't useable anywhere
311 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
312 *ppVertexBuffer = NULL;
313 return WINED3DERR_INVALIDCALL;
316 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
318 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
319 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
323 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
324 * drawStridedFast (half-life 2).
326 * Basically converting the vertices in the buffer is quite expensive, and observations
327 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
328 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
330 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
331 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
332 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
333 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
335 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
336 * more. In this call we can convert dx7 buffers too.
338 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
339 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
340 (dxVersion > 7 || !conv) ) {
346 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
347 GLenum error, glUsage;
348 TRACE("Creating VBO for Index Buffer %p\n", object);
350 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
351 * restored on the next draw
353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
355 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
356 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
361 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
362 error = glGetError();
363 if(error != GL_NO_ERROR || object->vbo == 0) {
364 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
368 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
369 error = glGetError();
370 if(error != GL_NO_ERROR) {
371 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
375 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
376 * copy no readback will be needed
378 glUsage = GL_STATIC_DRAW_ARB;
379 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
380 error = glGetError();
381 if(error != GL_NO_ERROR) {
382 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
386 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
390 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
391 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
396 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
397 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
398 HANDLE *sharedHandle, IUnknown *parent) {
399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
400 IWineD3DIndexBufferImpl *object;
401 TRACE("(%p) Creating index buffer\n", This);
403 /* Allocate the storage for the device */
404 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
406 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
407 CreateIndexBufferVBO(This, object);
410 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
411 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
412 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
417 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
420 IWineD3DStateBlockImpl *object;
424 D3DCREATEOBJECTINSTANCE(object, StateBlock)
425 object->blockType = Type;
427 for(i = 0; i < LIGHTMAP_SIZE; i++) {
428 list_init(&object->lightMap[i]);
431 /* Special case - Used during initialization to produce a placeholder stateblock
432 so other functions called can update a state block */
433 if (Type == WINED3DSBT_INIT) {
434 /* Don't bother increasing the reference count otherwise a device will never
435 be freed due to circular dependencies */
439 temp_result = allocate_shader_constants(object);
440 if (WINED3D_OK != temp_result)
443 /* Otherwise, might as well set the whole state block to the appropriate values */
444 if (This->stateBlock != NULL)
445 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
447 memset(object->streamFreq, 1, sizeof(object->streamFreq));
449 /* Reset the ref and type after kludging it */
450 object->wineD3DDevice = This;
452 object->blockType = Type;
454 TRACE("Updating changed flags appropriate for type %d\n", Type);
456 if (Type == WINED3DSBT_ALL) {
458 TRACE("ALL => Pretend everything has changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
461 /* Lights are not part of the changed / set structure */
462 for(j = 0; j < LIGHTMAP_SIZE; j++) {
464 LIST_FOR_EACH(e, &object->lightMap[j]) {
465 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
466 light->changed = TRUE;
467 light->enabledChanged = TRUE;
470 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
471 object->contained_render_states[j - 1] = j;
473 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
474 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
475 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
476 object->contained_transform_states[j - 1] = j;
478 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
479 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
480 object->contained_vs_consts_f[j] = j;
482 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
483 for(j = 0; j < MAX_CONST_I; j++) {
484 object->contained_vs_consts_i[j] = j;
486 object->num_contained_vs_consts_i = MAX_CONST_I;
487 for(j = 0; j < MAX_CONST_B; j++) {
488 object->contained_vs_consts_b[j] = j;
490 object->num_contained_vs_consts_b = MAX_CONST_B;
491 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
492 object->contained_ps_consts_f[j] = j;
494 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
495 for(j = 0; j < MAX_CONST_I; j++) {
496 object->contained_ps_consts_i[j] = j;
498 object->num_contained_ps_consts_i = MAX_CONST_I;
499 for(j = 0; j < MAX_CONST_B; j++) {
500 object->contained_ps_consts_b[j] = j;
502 object->num_contained_ps_consts_b = MAX_CONST_B;
503 for(i = 0; i < MAX_TEXTURES; i++) {
504 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
505 object->contained_tss_states[object->num_contained_tss_states].stage = i;
506 object->contained_tss_states[object->num_contained_tss_states].state = j;
507 object->num_contained_tss_states++;
510 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
511 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
512 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
513 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
514 object->num_contained_sampler_states++;
518 for(i = 0; i < MAX_STREAMS; i++) {
519 if(object->streamSource[i]) {
520 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
523 if(object->pIndexData) {
524 IWineD3DIndexBuffer_AddRef(object->pIndexData);
526 if(object->vertexShader) {
527 IWineD3DVertexShader_AddRef(object->vertexShader);
529 if(object->pixelShader) {
530 IWineD3DPixelShader_AddRef(object->pixelShader);
533 } else if (Type == WINED3DSBT_PIXELSTATE) {
535 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
536 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
538 object->changed.pixelShader = TRUE;
540 /* Pixel Shader Constants */
541 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
542 object->contained_ps_consts_f[i] = i;
543 object->changed.pixelShaderConstantsF[i] = TRUE;
545 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
546 for (i = 0; i < MAX_CONST_B; ++i) {
547 object->contained_ps_consts_b[i] = i;
548 object->changed.pixelShaderConstantsB[i] = TRUE;
550 object->num_contained_ps_consts_b = MAX_CONST_B;
551 for (i = 0; i < MAX_CONST_I; ++i) {
552 object->contained_ps_consts_i[i] = i;
553 object->changed.pixelShaderConstantsI[i] = TRUE;
555 object->num_contained_ps_consts_i = MAX_CONST_I;
557 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
558 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
559 object->contained_render_states[i] = SavedPixelStates_R[i];
561 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
562 for (j = 0; j < MAX_TEXTURES; j++) {
563 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
564 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
565 object->contained_tss_states[object->num_contained_tss_states].stage = j;
566 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
567 object->num_contained_tss_states++;
570 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
571 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
572 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
573 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
574 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
575 object->num_contained_sampler_states++;
578 if(object->pixelShader) {
579 IWineD3DPixelShader_AddRef(object->pixelShader);
582 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
583 * on them. This makes releasing the buffer easier
585 for(i = 0; i < MAX_STREAMS; i++) {
586 object->streamSource[i] = NULL;
588 object->pIndexData = NULL;
589 object->vertexShader = NULL;
591 } else if (Type == WINED3DSBT_VERTEXSTATE) {
593 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
594 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
596 object->changed.vertexShader = TRUE;
598 /* Vertex Shader Constants */
599 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
600 object->changed.vertexShaderConstantsF[i] = TRUE;
601 object->contained_vs_consts_f[i] = i;
603 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
604 for (i = 0; i < MAX_CONST_B; ++i) {
605 object->changed.vertexShaderConstantsB[i] = TRUE;
606 object->contained_vs_consts_b[i] = i;
608 object->num_contained_vs_consts_b = MAX_CONST_B;
609 for (i = 0; i < MAX_CONST_I; ++i) {
610 object->changed.vertexShaderConstantsI[i] = TRUE;
611 object->contained_vs_consts_i[i] = i;
613 object->num_contained_vs_consts_i = MAX_CONST_I;
614 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
615 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
616 object->contained_render_states[i] = SavedVertexStates_R[i];
618 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
619 for (j = 0; j < MAX_TEXTURES; j++) {
620 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
621 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
622 object->contained_tss_states[object->num_contained_tss_states].stage = j;
623 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
624 object->num_contained_tss_states++;
627 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
628 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
629 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
630 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
631 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
632 object->num_contained_sampler_states++;
636 for(j = 0; j < LIGHTMAP_SIZE; j++) {
638 LIST_FOR_EACH(e, &object->lightMap[j]) {
639 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
640 light->changed = TRUE;
641 light->enabledChanged = TRUE;
645 for(i = 0; i < MAX_STREAMS; i++) {
646 if(object->streamSource[i]) {
647 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
650 if(object->vertexShader) {
651 IWineD3DVertexShader_AddRef(object->vertexShader);
653 object->pIndexData = NULL;
654 object->pixelShader = NULL;
656 FIXME("Unrecognized state block type %d\n", Type);
659 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
663 /* ************************************
665 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
668 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
670 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.
672 ******************************** */
674 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) {
675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
676 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
677 unsigned int Size = 1;
678 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
679 TRACE("(%p) Create surface\n",This);
681 /** FIXME: Check ranges on the inputs are valid
684 * [in] Quality level. The valid range is between zero and one less than the level
685 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
686 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
687 * values of paired render targets, depth stencil surfaces, and the MultiSample type
689 *******************************/
694 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
696 * If this flag is set, the contents of the depth stencil buffer will be
697 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
698 * with a different depth surface.
700 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
701 ***************************/
703 if(MultisampleQuality < 0) {
704 FIXME("Invalid multisample level %d\n", MultisampleQuality);
705 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
708 if(MultisampleQuality > 0) {
709 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
710 MultisampleQuality=0;
713 /** FIXME: Check that the format is supported
715 *******************************/
717 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
718 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
720 *********************************/
721 if (WINED3DFMT_UNKNOWN == Format) {
723 } else if (Format == WINED3DFMT_DXT1) {
724 /* DXT1 is half byte per pixel */
725 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
727 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
728 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
729 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
731 /* The pitch is a multiple of 4 bytes */
732 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
736 /** Create and initialise the surface resource **/
737 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
738 /* "Standalone" surface */
739 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
741 object->currentDesc.Width = Width;
742 object->currentDesc.Height = Height;
743 object->currentDesc.MultiSampleType = MultiSample;
744 object->currentDesc.MultiSampleQuality = MultisampleQuality;
745 object->glDescription.level = Level;
749 object->Flags |= Discard ? SFLAG_DISCARD : 0;
750 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
751 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
754 if (WINED3DFMT_UNKNOWN != Format) {
755 object->bytesPerPixel = tableEntry->bpp;
757 object->bytesPerPixel = 0;
760 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
762 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
764 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
765 * this function is too deep to need to care about things like this.
766 * Levels need to be checked too, and possibly Type since they all affect what can be done.
767 * ****************************************/
769 case WINED3DPOOL_SCRATCH:
771 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
772 "which are mutually exclusive, setting lockable to TRUE\n");
775 case WINED3DPOOL_SYSTEMMEM:
776 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
777 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
778 case WINED3DPOOL_MANAGED:
779 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
780 "Usage of DYNAMIC which are mutually exclusive, not doing "
781 "anything just telling you.\n");
783 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
784 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
785 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
786 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
789 FIXME("(%p) Unknown pool %d\n", This, Pool);
793 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
794 FIXME("Trying to create a render target that isn't in the default pool\n");
797 /* mark the texture as dirty so that it gets loaded first time around*/
798 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
799 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
800 This, Width, Height, Format, debug_d3dformat(Format),
801 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
803 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
804 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
805 This->ddraw_primary = (IWineD3DSurface *) object;
807 /* Look at the implementation and set the correct Vtable */
810 /* Check if a 3D adapter is available when creating gl surfaces */
812 ERR("OpenGL surfaces are not available without opengl\n");
813 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
814 HeapFree(GetProcessHeap(), 0, object);
815 return WINED3DERR_NOTAVAILABLE;
820 object->lpVtbl = &IWineGDISurface_Vtbl;
824 /* To be sure to catch this */
825 ERR("Unknown requested surface implementation %d!\n", Impl);
826 IWineD3DSurface_Release((IWineD3DSurface *) object);
827 return WINED3DERR_INVALIDCALL;
830 list_init(&object->renderbuffers);
832 /* Call the private setup routine */
833 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
837 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
838 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
839 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
840 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
843 IWineD3DTextureImpl *object;
848 unsigned int pow2Width;
849 unsigned int pow2Height;
850 const GlPixelFormatDesc *glDesc;
851 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
854 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
855 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
856 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
858 /* TODO: It should only be possible to create textures for formats
859 that are reported as supported */
860 if (WINED3DFMT_UNKNOWN >= Format) {
861 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
862 return WINED3DERR_INVALIDCALL;
865 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
866 D3DINITIALIZEBASETEXTURE(object->baseTexture);
867 object->width = Width;
868 object->height = Height;
870 /** Non-power2 support **/
871 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
875 /* Find the nearest pow2 match */
876 pow2Width = pow2Height = 1;
877 while (pow2Width < Width) pow2Width <<= 1;
878 while (pow2Height < Height) pow2Height <<= 1;
880 if(pow2Width != Width || pow2Height != Height) {
882 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
883 HeapFree(GetProcessHeap(), 0, object);
885 return WINED3DERR_INVALIDCALL;
892 /** FIXME: add support for real non-power-two if it's provided by the video card **/
893 /* Precalculated scaling for 'faked' non power of two texture coords */
894 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
895 (Width != pow2Width || Height != pow2Height)) {
896 object->baseTexture.pow2Matrix[0] = (float)Width;
897 object->baseTexture.pow2Matrix[5] = (float)Height;
898 object->baseTexture.pow2Matrix[10] = 1.0;
899 object->baseTexture.pow2Matrix[15] = 1.0;
900 object->target = GL_TEXTURE_RECTANGLE_ARB;
902 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
903 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
904 object->baseTexture.pow2Matrix[10] = 1.0;
905 object->baseTexture.pow2Matrix[15] = 1.0;
906 object->target = GL_TEXTURE_2D;
908 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
910 /* Calculate levels for mip mapping */
911 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
912 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
913 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
914 return WINED3DERR_INVALIDCALL;
917 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
918 return WINED3DERR_INVALIDCALL;
920 object->baseTexture.levels = 1;
921 } else if (Levels == 0) {
922 TRACE("calculating levels %d\n", object->baseTexture.levels);
923 object->baseTexture.levels++;
926 while (tmpW > 1 || tmpH > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 object->baseTexture.levels++;
931 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
934 /* Generate all the surfaces */
937 for (i = 0; i < object->baseTexture.levels; i++)
939 /* use the callback to create the texture surface */
940 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
941 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
942 FIXME("Failed to create surface %p\n", object);
944 object->surfaces[i] = NULL;
945 IWineD3DTexture_Release((IWineD3DTexture *)object);
951 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
952 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
953 /* calculate the next mipmap level */
954 tmpW = max(1, tmpW >> 1);
955 tmpH = max(1, tmpH >> 1);
957 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
959 TRACE("(%p) : Created texture %p\n", This, object);
963 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
964 UINT Width, UINT Height, UINT Depth,
965 UINT Levels, DWORD Usage,
966 WINED3DFORMAT Format, WINED3DPOOL Pool,
967 IWineD3DVolumeTexture **ppVolumeTexture,
968 HANDLE *pSharedHandle, IUnknown *parent,
969 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
972 IWineD3DVolumeTextureImpl *object;
977 const GlPixelFormatDesc *glDesc;
979 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
981 /* TODO: It should only be possible to create textures for formats
982 that are reported as supported */
983 if (WINED3DFMT_UNKNOWN >= Format) {
984 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
985 return WINED3DERR_INVALIDCALL;
987 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
988 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
989 return WINED3DERR_INVALIDCALL;
992 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
993 D3DINITIALIZEBASETEXTURE(object->baseTexture);
995 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
996 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
998 object->width = Width;
999 object->height = Height;
1000 object->depth = Depth;
1002 /* Is NP2 support for volumes needed? */
1003 object->baseTexture.pow2Matrix[ 0] = 1.0;
1004 object->baseTexture.pow2Matrix[ 5] = 1.0;
1005 object->baseTexture.pow2Matrix[10] = 1.0;
1006 object->baseTexture.pow2Matrix[15] = 1.0;
1008 /* Calculate levels for mip mapping */
1009 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1010 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1011 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1012 return WINED3DERR_INVALIDCALL;
1015 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1016 return WINED3DERR_INVALIDCALL;
1019 } else if (Levels == 0) {
1020 object->baseTexture.levels++;
1024 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1025 tmpW = max(1, tmpW >> 1);
1026 tmpH = max(1, tmpH >> 1);
1027 tmpD = max(1, tmpD >> 1);
1028 object->baseTexture.levels++;
1030 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1033 /* Generate all the surfaces */
1038 for (i = 0; i < object->baseTexture.levels; i++)
1041 /* Create the volume */
1042 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1043 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1046 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1047 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1048 *ppVolumeTexture = NULL;
1052 /* Set its container to this object */
1053 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1055 /* calcualte the next mipmap level */
1056 tmpW = max(1, tmpW >> 1);
1057 tmpH = max(1, tmpH >> 1);
1058 tmpD = max(1, tmpD >> 1);
1060 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1062 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1063 TRACE("(%p) : Created volume texture %p\n", This, object);
1067 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1068 UINT Width, UINT Height, UINT Depth,
1070 WINED3DFORMAT Format, WINED3DPOOL Pool,
1071 IWineD3DVolume** ppVolume,
1072 HANDLE* pSharedHandle, IUnknown *parent) {
1074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1075 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1076 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1078 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1079 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1080 return WINED3DERR_INVALIDCALL;
1083 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1085 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1086 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1088 object->currentDesc.Width = Width;
1089 object->currentDesc.Height = Height;
1090 object->currentDesc.Depth = Depth;
1091 object->bytesPerPixel = formatDesc->bpp;
1093 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1094 object->lockable = TRUE;
1095 object->locked = FALSE;
1096 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1097 object->dirty = TRUE;
1099 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1102 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1103 UINT Levels, DWORD Usage,
1104 WINED3DFORMAT Format, WINED3DPOOL Pool,
1105 IWineD3DCubeTexture **ppCubeTexture,
1106 HANDLE *pSharedHandle, IUnknown *parent,
1107 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1110 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1114 unsigned int pow2EdgeLength = EdgeLength;
1115 const GlPixelFormatDesc *glDesc;
1116 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1118 /* TODO: It should only be possible to create textures for formats
1119 that are reported as supported */
1120 if (WINED3DFMT_UNKNOWN >= Format) {
1121 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1122 return WINED3DERR_INVALIDCALL;
1125 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1126 WARN("(%p) : Tried to create not supported cube texture\n", This);
1127 return WINED3DERR_INVALIDCALL;
1130 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1131 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1133 TRACE("(%p) Create Cube Texture\n", This);
1135 /** Non-power2 support **/
1137 /* Find the nearest pow2 match */
1139 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1141 object->edgeLength = EdgeLength;
1142 /* TODO: support for native non-power 2 */
1143 /* Precalculated scaling for 'faked' non power of two texture coords */
1144 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1145 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1146 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1147 object->baseTexture.pow2Matrix[15] = 1.0;
1149 /* Calculate levels for mip mapping */
1150 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1151 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1152 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1153 HeapFree(GetProcessHeap(), 0, object);
1154 *ppCubeTexture = NULL;
1156 return WINED3DERR_INVALIDCALL;
1159 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1160 HeapFree(GetProcessHeap(), 0, object);
1161 *ppCubeTexture = NULL;
1163 return WINED3DERR_INVALIDCALL;
1166 } else if (Levels == 0) {
1167 object->baseTexture.levels++;
1170 tmpW = max(1, tmpW >> 1);
1171 object->baseTexture.levels++;
1173 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1176 /* Generate all the surfaces */
1178 for (i = 0; i < object->baseTexture.levels; i++) {
1180 /* Create the 6 faces */
1181 for (j = 0; j < 6; j++) {
1183 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1184 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1186 if(hr!= WINED3D_OK) {
1190 for (l = 0; l < j; l++) {
1191 IWineD3DSurface_Release(object->surfaces[l][i]);
1193 for (k = 0; k < i; k++) {
1194 for (l = 0; l < 6; l++) {
1195 IWineD3DSurface_Release(object->surfaces[l][k]);
1199 FIXME("(%p) Failed to create surface\n",object);
1200 HeapFree(GetProcessHeap(),0,object);
1201 *ppCubeTexture = NULL;
1204 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1205 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1207 tmpW = max(1, tmpW >> 1);
1209 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1211 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1212 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1216 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1218 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1219 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1221 /* Just a check to see if we support this type of query */
1223 case WINED3DQUERYTYPE_OCCLUSION:
1224 TRACE("(%p) occlusion query\n", This);
1225 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1228 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1231 case WINED3DQUERYTYPE_EVENT:
1232 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1233 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1234 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1236 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1241 case WINED3DQUERYTYPE_VCACHE:
1242 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1243 case WINED3DQUERYTYPE_VERTEXSTATS:
1244 case WINED3DQUERYTYPE_TIMESTAMP:
1245 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1246 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1247 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1248 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1249 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1250 case WINED3DQUERYTYPE_PIXELTIMINGS:
1251 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1252 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1254 FIXME("(%p) Unhandled query type %d\n", This, Type);
1256 if(NULL == ppQuery || hr != WINED3D_OK) {
1260 D3DCREATEOBJECTINSTANCE(object, Query)
1261 object->type = Type;
1262 object->state = QUERY_CREATED;
1263 /* allocated the 'extended' data based on the type of query requested */
1265 case WINED3DQUERYTYPE_OCCLUSION:
1266 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1267 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1269 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1270 TRACE("(%p) Allocating data for an occlusion query\n", This);
1271 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1274 case WINED3DQUERYTYPE_EVENT:
1275 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1276 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1278 if(GL_SUPPORT(APPLE_FENCE)) {
1279 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1280 checkGLcall("glGenFencesAPPLE");
1281 } else if(GL_SUPPORT(NV_FENCE)) {
1282 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1283 checkGLcall("glGenFencesNV");
1287 case WINED3DQUERYTYPE_VCACHE:
1288 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1289 case WINED3DQUERYTYPE_VERTEXSTATS:
1290 case WINED3DQUERYTYPE_TIMESTAMP:
1291 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1292 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1293 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1294 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1295 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1296 case WINED3DQUERYTYPE_PIXELTIMINGS:
1297 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1298 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1300 object->extendedData = 0;
1301 FIXME("(%p) Unhandled query type %d\n",This , Type);
1303 TRACE("(%p) : Created Query %p\n", This, object);
1307 /*****************************************************************************
1308 * IWineD3DDeviceImpl_SetupFullscreenWindow
1310 * Helper function that modifies a HWND's Style and ExStyle for proper
1314 * iface: Pointer to the IWineD3DDevice interface
1315 * window: Window to setup
1317 *****************************************************************************/
1318 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1321 LONG style, exStyle;
1322 /* Don't do anything if an original style is stored.
1323 * That shouldn't happen
1325 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1326 if (This->style || This->exStyle) {
1327 ERR("(%p): Want to change the window parameters of HWND %p, but "
1328 "another style is stored for restoration afterwards\n", This, window);
1331 /* Get the parameters and save them */
1332 style = GetWindowLongW(window, GWL_STYLE);
1333 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1334 This->style = style;
1335 This->exStyle = exStyle;
1337 /* Filter out window decorations */
1338 style &= ~WS_CAPTION;
1339 style &= ~WS_THICKFRAME;
1340 exStyle &= ~WS_EX_WINDOWEDGE;
1341 exStyle &= ~WS_EX_CLIENTEDGE;
1343 /* Make sure the window is managed, otherwise we won't get keyboard input */
1344 style |= WS_POPUP | WS_SYSMENU;
1346 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1347 This->style, This->exStyle, style, exStyle);
1349 SetWindowLongW(window, GWL_STYLE, style);
1350 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1352 /* Inform the window about the update. */
1353 SetWindowPos(window, HWND_TOP, 0, 0,
1354 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1355 ShowWindow(window, SW_NORMAL);
1358 /*****************************************************************************
1359 * IWineD3DDeviceImpl_RestoreWindow
1361 * Helper function that restores a windows' properties when taking it out
1362 * of fullscreen mode
1365 * iface: Pointer to the IWineD3DDevice interface
1366 * window: Window to setup
1368 *****************************************************************************/
1369 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1372 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1373 * switch, do nothing
1375 if (!This->style && !This->exStyle) return;
1377 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1378 This, window, This->style, This->exStyle);
1380 SetWindowLongW(window, GWL_STYLE, This->style);
1381 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1383 /* Delete the old values */
1387 /* Inform the window about the update */
1388 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1389 0, 0, 0, 0, /* Pos, Size, ignored */
1390 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1393 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1394 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1396 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1397 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1401 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1402 HRESULT hr = WINED3D_OK;
1403 IUnknown *bufferParent;
1404 BOOL displaymode_set = FALSE;
1406 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1408 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1409 * does a device hold a reference to a swap chain giving them a lifetime of the device
1410 * or does the swap chain notify the device of its destruction.
1411 *******************************/
1413 /* Check the params */
1414 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1415 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1416 return WINED3DERR_INVALIDCALL;
1417 } else if (pPresentationParameters->BackBufferCount > 1) {
1418 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");
1421 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1423 /*********************
1424 * Lookup the window Handle and the relating X window handle
1425 ********************/
1427 /* Setup hwnd we are using, plus which display this equates to */
1428 object->win_handle = pPresentationParameters->hDeviceWindow;
1429 if (!object->win_handle) {
1430 object->win_handle = This->createParms.hFocusWindow;
1432 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1434 hDc = GetDC(object->win_handle);
1435 TRACE("Using hDc %p\n", hDc);
1438 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1439 return WINED3DERR_NOTAVAILABLE;
1442 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1443 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1444 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1445 ReleaseDC(object->win_handle, hDc);
1447 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1448 * then the corresponding dimension of the client area of the hDeviceWindow
1449 * (or the focus window, if hDeviceWindow is NULL) is taken.
1450 **********************/
1452 if (pPresentationParameters->Windowed &&
1453 ((pPresentationParameters->BackBufferWidth == 0) ||
1454 (pPresentationParameters->BackBufferHeight == 0) ||
1455 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1458 GetClientRect(object->win_handle, &Rect);
1460 if (pPresentationParameters->BackBufferWidth == 0) {
1461 pPresentationParameters->BackBufferWidth = Rect.right;
1462 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1464 if (pPresentationParameters->BackBufferHeight == 0) {
1465 pPresentationParameters->BackBufferHeight = Rect.bottom;
1466 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1468 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1469 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1470 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1474 /* Put the correct figures in the presentation parameters */
1475 TRACE("Copying across presentation parameters\n");
1476 object->presentParms = *pPresentationParameters;
1478 TRACE("calling rendertarget CB\n");
1479 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1481 object->presentParms.BackBufferWidth,
1482 object->presentParms.BackBufferHeight,
1483 object->presentParms.BackBufferFormat,
1484 object->presentParms.MultiSampleType,
1485 object->presentParms.MultiSampleQuality,
1486 TRUE /* Lockable */,
1487 &object->frontBuffer,
1488 NULL /* pShared (always null)*/);
1489 if (object->frontBuffer != NULL) {
1490 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1491 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1493 ERR("Failed to create the front buffer\n");
1497 /*********************
1498 * Windowed / Fullscreen
1499 *******************/
1502 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1503 * so we should really check to see if there is a fullscreen swapchain already
1504 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1505 **************************************/
1507 if (!pPresentationParameters->Windowed) {
1514 /* Get info on the current display setup */
1516 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1519 /* Change the display settings */
1520 memset(&devmode, 0, sizeof(devmode));
1521 devmode.dmSize = sizeof(devmode);
1522 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1523 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1524 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1525 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1526 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1527 displaymode_set = TRUE;
1529 /* For GetDisplayMode */
1530 This->ddraw_width = devmode.dmPelsWidth;
1531 This->ddraw_height = devmode.dmPelsHeight;
1532 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1534 IWineD3DDevice_SetFullscreen(iface, TRUE);
1536 /* And finally clip mouse to our screen */
1537 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1538 ClipCursor(&clip_rc);
1542 * Create an opengl context for the display visual
1543 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1544 * use different properties after that point in time. FIXME: How to handle when requested format
1545 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1546 * it chooses is identical to the one already being used!
1547 **********************************/
1548 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1550 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1551 if(!object->context)
1552 return E_OUTOFMEMORY;
1553 object->num_contexts = 1;
1555 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1556 if (!object->context[0]) {
1557 ERR("Failed to create a new context\n");
1558 hr = WINED3DERR_NOTAVAILABLE;
1561 TRACE("Context created (HWND=%p, glContext=%p)\n",
1562 object->win_handle, object->context[0]->glCtx);
1565 /*********************
1566 * Create the back, front and stencil buffers
1567 *******************/
1568 if(object->presentParms.BackBufferCount > 0) {
1571 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1572 if(!object->backBuffer) {
1573 ERR("Out of memory\n");
1578 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1579 TRACE("calling rendertarget CB\n");
1580 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1582 object->presentParms.BackBufferWidth,
1583 object->presentParms.BackBufferHeight,
1584 object->presentParms.BackBufferFormat,
1585 object->presentParms.MultiSampleType,
1586 object->presentParms.MultiSampleQuality,
1587 TRUE /* Lockable */,
1588 &object->backBuffer[i],
1589 NULL /* pShared (always null)*/);
1590 if(hr == WINED3D_OK && object->backBuffer[i]) {
1591 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1593 ERR("Cannot create new back buffer\n");
1597 glDrawBuffer(GL_BACK);
1598 checkGLcall("glDrawBuffer(GL_BACK)");
1602 object->backBuffer = NULL;
1604 /* Single buffering - draw to front buffer */
1606 glDrawBuffer(GL_FRONT);
1607 checkGLcall("glDrawBuffer(GL_FRONT)");
1611 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1612 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1613 TRACE("Creating depth stencil buffer\n");
1614 if (This->auto_depth_stencil_buffer == NULL ) {
1615 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1617 object->presentParms.BackBufferWidth,
1618 object->presentParms.BackBufferHeight,
1619 object->presentParms.AutoDepthStencilFormat,
1620 object->presentParms.MultiSampleType,
1621 object->presentParms.MultiSampleQuality,
1622 FALSE /* FIXME: Discard */,
1623 &This->auto_depth_stencil_buffer,
1624 NULL /* pShared (always null)*/ );
1625 if (This->auto_depth_stencil_buffer != NULL)
1626 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1629 /** TODO: A check on width, height and multisample types
1630 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1631 ****************************/
1632 object->wantsDepthStencilBuffer = TRUE;
1634 object->wantsDepthStencilBuffer = FALSE;
1637 TRACE("Created swapchain %p\n", object);
1638 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1642 if (displaymode_set) {
1648 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1651 /* Get info on the current display setup */
1653 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1656 /* Change the display settings */
1657 memset(&devmode, 0, sizeof(devmode));
1658 devmode.dmSize = sizeof(devmode);
1659 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1660 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1661 devmode.dmPelsWidth = object->orig_width;
1662 devmode.dmPelsHeight = object->orig_height;
1663 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1666 if (object->backBuffer) {
1668 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1669 if(object->backBuffer[i]) {
1670 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1671 IUnknown_Release(bufferParent); /* once for the get parent */
1672 if (IUnknown_Release(bufferParent) > 0) {
1673 FIXME("(%p) Something's still holding the back buffer\n",This);
1677 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1678 object->backBuffer = NULL;
1680 if(object->context[0])
1681 DestroyContext(This, object->context[0]);
1682 if(object->frontBuffer) {
1683 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1684 IUnknown_Release(bufferParent); /* once for the get parent */
1685 if (IUnknown_Release(bufferParent) > 0) {
1686 FIXME("(%p) Something's still holding the front buffer\n",This);
1689 HeapFree(GetProcessHeap(), 0, object);
1693 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1694 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1696 TRACE("(%p)\n", This);
1698 return This->NumberOfSwapChains;
1701 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1703 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1705 if(iSwapChain < This->NumberOfSwapChains) {
1706 *pSwapChain = This->swapchains[iSwapChain];
1707 IWineD3DSwapChain_AddRef(*pSwapChain);
1708 TRACE("(%p) returning %p\n", This, *pSwapChain);
1711 TRACE("Swapchain out of range\n");
1713 return WINED3DERR_INVALIDCALL;
1718 * Vertex Declaration
1720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1721 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1723 IWineD3DVertexDeclarationImpl *object = NULL;
1724 HRESULT hr = WINED3D_OK;
1726 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1727 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1729 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1731 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1736 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1738 unsigned int idx, idx2;
1739 unsigned int offset;
1740 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1741 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1742 BOOL has_blend_idx = has_blend &&
1743 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1744 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1745 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1746 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1747 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1748 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1749 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1751 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1752 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1754 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1755 WINED3DVERTEXELEMENT *elements = NULL;
1758 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1759 if (has_blend_idx) num_blends--;
1761 /* Compute declaration size */
1762 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1763 has_psize + has_diffuse + has_specular + num_textures + 1;
1765 /* convert the declaration */
1766 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1770 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1773 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1774 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1775 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1778 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1779 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1781 elements[idx].UsageIndex = 0;
1784 if (has_blend && (num_blends > 0)) {
1785 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1786 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1788 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1789 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1790 elements[idx].UsageIndex = 0;
1793 if (has_blend_idx) {
1794 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1795 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1796 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1797 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1798 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1800 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1801 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1802 elements[idx].UsageIndex = 0;
1806 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1807 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1808 elements[idx].UsageIndex = 0;
1812 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1813 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1814 elements[idx].UsageIndex = 0;
1818 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1819 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1820 elements[idx].UsageIndex = 0;
1824 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1825 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1826 elements[idx].UsageIndex = 1;
1829 for (idx2 = 0; idx2 < num_textures; idx2++) {
1830 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1831 switch (numcoords) {
1832 case WINED3DFVF_TEXTUREFORMAT1:
1833 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1835 case WINED3DFVF_TEXTUREFORMAT2:
1836 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1838 case WINED3DFVF_TEXTUREFORMAT3:
1839 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1841 case WINED3DFVF_TEXTUREFORMAT4:
1842 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1845 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1846 elements[idx].UsageIndex = idx2;
1850 /* Now compute offsets, and initialize the rest of the fields */
1851 for (idx = 0, offset = 0; idx < size-1; idx++) {
1852 elements[idx].Stream = 0;
1853 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1854 elements[idx].Offset = offset;
1855 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1858 *ppVertexElements = elements;
1862 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1863 WINED3DVERTEXELEMENT* elements = NULL;
1867 size = ConvertFvfToDeclaration(Fvf, &elements);
1868 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1870 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1871 HeapFree(GetProcessHeap(), 0, elements);
1872 if (hr != S_OK) return hr;
1877 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1878 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1880 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1881 HRESULT hr = WINED3D_OK;
1882 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1883 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1885 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1887 if (vertex_declaration) {
1888 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1891 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1893 if (WINED3D_OK != hr) {
1894 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1895 IWineD3DVertexShader_Release(*ppVertexShader);
1896 return WINED3DERR_INVALIDCALL;
1902 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1904 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1905 HRESULT hr = WINED3D_OK;
1907 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1908 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1909 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1910 if (WINED3D_OK == hr) {
1911 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1913 WARN("(%p) : Failed to create pixel shader\n", This);
1919 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1921 IWineD3DPaletteImpl *object;
1923 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1925 /* Create the new object */
1926 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1928 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1929 return E_OUTOFMEMORY;
1932 object->lpVtbl = &IWineD3DPalette_Vtbl;
1934 object->Flags = Flags;
1935 object->parent = Parent;
1936 object->wineD3DDevice = This;
1937 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1939 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1942 HeapFree( GetProcessHeap(), 0, object);
1943 return E_OUTOFMEMORY;
1946 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1948 IWineD3DPalette_Release((IWineD3DPalette *) object);
1952 *Palette = (IWineD3DPalette *) object;
1957 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1961 HDC dcb = NULL, dcs = NULL;
1962 WINEDDCOLORKEY colorkey;
1964 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1967 GetObjectA(hbm, sizeof(BITMAP), &bm);
1968 dcb = CreateCompatibleDC(NULL);
1970 SelectObject(dcb, hbm);
1974 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1975 * couldn't be loaded
1977 memset(&bm, 0, sizeof(bm));
1982 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1983 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1984 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1986 ERR("Wine logo requested, but failed to create surface\n");
1991 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1992 if(FAILED(hr)) goto out;
1993 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1994 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1996 colorkey.dwColorSpaceLowValue = 0;
1997 colorkey.dwColorSpaceHighValue = 0;
1998 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2000 /* Fill the surface with a white color to show that wined3d is there */
2001 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2014 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2016 IWineD3DSwapChainImpl *swapchain;
2020 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2021 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2023 /* TODO: Test if OpenGL is compiled in and loaded */
2025 TRACE("(%p) : Creating stateblock\n", This);
2026 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2027 hr = IWineD3DDevice_CreateStateBlock(iface,
2029 (IWineD3DStateBlock **)&This->stateBlock,
2031 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2032 WARN("Failed to create stateblock\n");
2035 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2036 This->updateStateBlock = This->stateBlock;
2037 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2039 hr = allocate_shader_constants(This->updateStateBlock);
2040 if (WINED3D_OK != hr) {
2044 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2045 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2046 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2048 /* Initialize the texture unit mapping to a 1:1 mapping */
2049 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2050 if (state < GL_LIMITS(fragment_samplers)) {
2051 This->texUnitMap[state] = state;
2052 This->rev_tex_unit_map[state] = state;
2054 This->texUnitMap[state] = -1;
2055 This->rev_tex_unit_map[state] = -1;
2059 /* Setup the implicit swapchain */
2060 TRACE("Creating implicit swapchain\n");
2061 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2062 if (FAILED(hr) || !swapchain) {
2063 WARN("Failed to create implicit swapchain\n");
2067 This->NumberOfSwapChains = 1;
2068 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2069 if(!This->swapchains) {
2070 ERR("Out of memory!\n");
2073 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2075 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2076 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2077 This->render_targets[0] = swapchain->backBuffer[0];
2078 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2081 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2082 This->render_targets[0] = swapchain->frontBuffer;
2083 This->lastActiveRenderTarget = swapchain->frontBuffer;
2085 IWineD3DSurface_AddRef(This->render_targets[0]);
2086 This->activeContext = swapchain->context[0];
2087 This->lastThread = GetCurrentThreadId();
2089 /* Depth Stencil support */
2090 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2091 if (NULL != This->stencilBufferTarget) {
2092 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2095 /* Set up some starting GL setup */
2098 /* Setup all the devices defaults */
2099 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2101 IWineD3DImpl_CheckGraphicsMemory();
2104 { /* Set a default viewport */
2108 vp.Width = pPresentationParameters->BackBufferWidth;
2109 vp.Height = pPresentationParameters->BackBufferHeight;
2112 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2115 /* Initialize the current view state */
2116 This->view_ident = 1;
2117 This->contexts[0]->last_was_rhw = 0;
2118 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2119 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2121 switch(wined3d_settings.offscreen_rendering_mode) {
2124 This->offscreenBuffer = GL_BACK;
2127 case ORM_BACKBUFFER:
2129 if(GL_LIMITS(aux_buffers) > 0) {
2130 TRACE("Using auxilliary buffer for offscreen rendering\n");
2131 This->offscreenBuffer = GL_AUX0;
2133 TRACE("Using back buffer for offscreen rendering\n");
2134 This->offscreenBuffer = GL_BACK;
2139 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2142 /* Clear the screen */
2143 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2144 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2147 This->d3d_initialized = TRUE;
2149 if(wined3d_settings.logo) {
2150 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2155 HeapFree(GetProcessHeap(), 0, This->render_targets);
2156 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2157 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2158 HeapFree(GetProcessHeap(), 0, This->swapchains);
2159 This->NumberOfSwapChains = 0;
2161 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2163 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2164 if(This->stateBlock) {
2165 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2166 This->stateBlock = NULL;
2171 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2175 TRACE("(%p)\n", This);
2177 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2179 /* I don't think that the interface guarants that the device is destroyed from the same thread
2180 * it was created. Thus make sure a context is active for the glDelete* calls
2182 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2184 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2186 TRACE("Deleting high order patches\n");
2187 for(i = 0; i < PATCHMAP_SIZE; i++) {
2188 struct list *e1, *e2;
2189 struct WineD3DRectPatch *patch;
2190 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2191 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2192 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2196 /* Delete the palette conversion shader if it is around */
2197 if(This->paletteConversionShader) {
2198 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2199 This->paletteConversionShader = 0;
2202 /* Delete the pbuffer context if there is any */
2203 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2205 /* Delete the mouse cursor texture */
2206 if(This->cursorTexture) {
2208 glDeleteTextures(1, &This->cursorTexture);
2210 This->cursorTexture = 0;
2213 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2214 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2216 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2217 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2220 /* Release the update stateblock */
2221 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2222 if(This->updateStateBlock != This->stateBlock)
2223 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2225 This->updateStateBlock = NULL;
2227 { /* because were not doing proper internal refcounts releasing the primary state block
2228 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2229 to set this->stateBlock = NULL; first */
2230 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2231 This->stateBlock = NULL;
2233 /* Release the stateblock */
2234 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2235 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2239 /* Release the buffers (with sanity checks)*/
2240 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2241 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2242 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2243 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2245 This->stencilBufferTarget = NULL;
2247 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2248 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2249 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2251 TRACE("Setting rendertarget to NULL\n");
2252 This->render_targets[0] = NULL;
2254 if (This->auto_depth_stencil_buffer) {
2255 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2256 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2258 This->auto_depth_stencil_buffer = NULL;
2261 for(i=0; i < This->NumberOfSwapChains; i++) {
2262 TRACE("Releasing the implicit swapchain %d\n", i);
2263 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2264 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2268 HeapFree(GetProcessHeap(), 0, This->swapchains);
2269 This->swapchains = NULL;
2270 This->NumberOfSwapChains = 0;
2272 HeapFree(GetProcessHeap(), 0, This->render_targets);
2273 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2274 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2275 This->render_targets = NULL;
2276 This->fbo_color_attachments = NULL;
2277 This->draw_buffers = NULL;
2280 This->d3d_initialized = FALSE;
2284 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2286 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2288 /* Setup the window for fullscreen mode */
2289 if(fullscreen && !This->ddraw_fullscreen) {
2290 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2291 } else if(!fullscreen && This->ddraw_fullscreen) {
2292 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2295 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2296 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2297 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2300 This->ddraw_fullscreen = fullscreen;
2303 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2304 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2305 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2307 * There is no way to deactivate thread safety once it is enabled.
2309 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2312 /*For now just store the flag(needed in case of ddraw) */
2313 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2318 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2322 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2325 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2327 /* Resize the screen even without a window:
2328 * The app could have unset it with SetCooperativeLevel, but not called
2329 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2330 * but we don't have any hwnd
2333 memset(&devmode, 0, sizeof(devmode));
2334 devmode.dmSize = sizeof(devmode);
2335 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2336 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2337 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2338 devmode.dmPelsWidth = pMode->Width;
2339 devmode.dmPelsHeight = pMode->Height;
2341 devmode.dmDisplayFrequency = pMode->RefreshRate;
2342 if (pMode->RefreshRate != 0) {
2343 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2346 /* Only change the mode if necessary */
2347 if( (This->ddraw_width == pMode->Width) &&
2348 (This->ddraw_height == pMode->Height) &&
2349 (This->ddraw_format == pMode->Format) &&
2350 (pMode->RefreshRate == 0) ) {
2354 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2355 if (ret != DISP_CHANGE_SUCCESSFUL) {
2356 if(devmode.dmDisplayFrequency != 0) {
2357 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2358 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2359 devmode.dmDisplayFrequency = 0;
2360 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2362 if(ret != DISP_CHANGE_SUCCESSFUL) {
2363 return WINED3DERR_NOTAVAILABLE;
2367 /* Store the new values */
2368 This->ddraw_width = pMode->Width;
2369 This->ddraw_height = pMode->Height;
2370 This->ddraw_format = pMode->Format;
2372 /* Only do this with a window of course */
2373 if(This->ddraw_window)
2374 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2376 /* And finally clip mouse to our screen */
2377 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2378 ClipCursor(&clip_rc);
2383 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2385 *ppD3D= This->wineD3D;
2386 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2387 IWineD3D_AddRef(*ppD3D);
2391 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2395 (This->adapter->TextureRam/(1024*1024)),
2396 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2397 /* return simulated texture memory left */
2398 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2406 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2409 /* Update the current state block */
2410 This->updateStateBlock->changed.fvf = TRUE;
2412 if(This->updateStateBlock->fvf == fvf) {
2413 TRACE("Application is setting the old fvf over, nothing to do\n");
2417 This->updateStateBlock->fvf = fvf;
2418 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2424 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2426 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2427 *pfvf = This->stateBlock->fvf;
2432 * Get / Set Stream Source
2434 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2436 IWineD3DVertexBuffer *oldSrc;
2438 if (StreamNumber >= MAX_STREAMS) {
2439 WARN("Stream out of range %d\n", StreamNumber);
2440 return WINED3DERR_INVALIDCALL;
2443 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2444 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2446 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2448 if(oldSrc == pStreamData &&
2449 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2450 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2451 TRACE("Application is setting the old values over, nothing to do\n");
2455 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2457 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2458 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2461 /* Handle recording of state blocks */
2462 if (This->isRecordingState) {
2463 TRACE("Recording... not performing anything\n");
2464 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2465 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2469 /* Need to do a getParent and pass the reffs up */
2470 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2471 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2472 so for now, just count internally */
2473 if (pStreamData != NULL) {
2474 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2475 InterlockedIncrement(&vbImpl->bindCount);
2476 IWineD3DVertexBuffer_AddRef(pStreamData);
2478 if (oldSrc != NULL) {
2479 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2480 IWineD3DVertexBuffer_Release(oldSrc);
2483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2488 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2491 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2492 This->stateBlock->streamSource[StreamNumber],
2493 This->stateBlock->streamOffset[StreamNumber],
2494 This->stateBlock->streamStride[StreamNumber]);
2496 if (StreamNumber >= MAX_STREAMS) {
2497 WARN("Stream out of range %d\n", StreamNumber);
2498 return WINED3DERR_INVALIDCALL;
2500 *pStream = This->stateBlock->streamSource[StreamNumber];
2501 *pStride = This->stateBlock->streamStride[StreamNumber];
2503 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2506 if (*pStream != NULL) {
2507 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2512 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2514 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2515 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2517 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2518 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2520 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2521 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2523 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2524 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2525 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2531 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2534 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2535 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2537 TRACE("(%p) : returning %d\n", This, *Divider);
2543 * Get / Set & Multiply Transform
2545 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2548 /* Most of this routine, comments included copied from ddraw tree initially: */
2549 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2551 /* Handle recording of state blocks */
2552 if (This->isRecordingState) {
2553 TRACE("Recording... not performing anything\n");
2554 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2555 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2560 * If the new matrix is the same as the current one,
2561 * we cut off any further processing. this seems to be a reasonable
2562 * optimization because as was noticed, some apps (warcraft3 for example)
2563 * tend towards setting the same matrix repeatedly for some reason.
2565 * From here on we assume that the new matrix is different, wherever it matters.
2567 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2568 TRACE("The app is setting the same matrix over again\n");
2571 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2575 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2576 where ViewMat = Camera space, WorldMat = world space.
2578 In OpenGL, camera and world space is combined into GL_MODELVIEW
2579 matrix. The Projection matrix stay projection matrix.
2582 /* Capture the times we can just ignore the change for now */
2583 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2584 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2585 /* Handled by the state manager */
2588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2592 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2594 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2595 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2599 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2600 WINED3DMATRIX *mat = NULL;
2603 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2604 * below means it will be recorded in a state block change, but it
2605 * works regardless where it is recorded.
2606 * If this is found to be wrong, change to StateBlock.
2608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2609 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2611 if (State < HIGHEST_TRANSFORMSTATE)
2613 mat = &This->updateStateBlock->transforms[State];
2615 FIXME("Unhandled transform state!!\n");
2618 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2620 /* Apply change via set transform - will reapply to eg. lights this way */
2621 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2627 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2628 you can reference any indexes you want as long as that number max are enabled at any
2629 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2630 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2631 but when recording, just build a chain pretty much of commands to be replayed. */
2633 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2635 PLIGHTINFOEL *object = NULL;
2636 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2642 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2646 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2647 return WINED3DERR_INVALIDCALL;
2650 switch(pLight->Type) {
2651 case WINED3DLIGHT_POINT:
2652 case WINED3DLIGHT_SPOT:
2653 case WINED3DLIGHT_PARALLELPOINT:
2654 case WINED3DLIGHT_GLSPOT:
2655 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2658 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2659 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2660 return WINED3DERR_INVALIDCALL;
2664 case WINED3DLIGHT_DIRECTIONAL:
2665 /* Ignores attenuation */
2669 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2670 return WINED3DERR_INVALIDCALL;
2673 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2674 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2675 if(object->OriginalIndex == Index) break;
2680 TRACE("Adding new light\n");
2681 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2683 ERR("Out of memory error when allocating a light\n");
2684 return E_OUTOFMEMORY;
2686 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2687 object->glIndex = -1;
2688 object->OriginalIndex = Index;
2689 object->changed = TRUE;
2692 /* Initialize the object */
2693 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,
2694 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2695 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2696 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2697 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2698 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2699 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2701 /* Save away the information */
2702 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2704 switch (pLight->Type) {
2705 case WINED3DLIGHT_POINT:
2707 object->lightPosn[0] = pLight->Position.x;
2708 object->lightPosn[1] = pLight->Position.y;
2709 object->lightPosn[2] = pLight->Position.z;
2710 object->lightPosn[3] = 1.0f;
2711 object->cutoff = 180.0f;
2715 case WINED3DLIGHT_DIRECTIONAL:
2717 object->lightPosn[0] = -pLight->Direction.x;
2718 object->lightPosn[1] = -pLight->Direction.y;
2719 object->lightPosn[2] = -pLight->Direction.z;
2720 object->lightPosn[3] = 0.0;
2721 object->exponent = 0.0f;
2722 object->cutoff = 180.0f;
2725 case WINED3DLIGHT_SPOT:
2727 object->lightPosn[0] = pLight->Position.x;
2728 object->lightPosn[1] = pLight->Position.y;
2729 object->lightPosn[2] = pLight->Position.z;
2730 object->lightPosn[3] = 1.0;
2733 object->lightDirn[0] = pLight->Direction.x;
2734 object->lightDirn[1] = pLight->Direction.y;
2735 object->lightDirn[2] = pLight->Direction.z;
2736 object->lightDirn[3] = 1.0;
2739 * opengl-ish and d3d-ish spot lights use too different models for the
2740 * light "intensity" as a function of the angle towards the main light direction,
2741 * so we only can approximate very roughly.
2742 * however spot lights are rather rarely used in games (if ever used at all).
2743 * furthermore if still used, probably nobody pays attention to such details.
2745 if (pLight->Falloff == 0) {
2746 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2747 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2748 * will always be 1.0 for both of them, and we don't have to care for the
2749 * rest of the rather complex calculation
2751 object->exponent = 0;
2753 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2754 if (rho < 0.0001) rho = 0.0001f;
2755 object->exponent = -0.3/log(cos(rho/2));
2757 if (object->exponent > 128.0) {
2758 object->exponent = 128.0;
2760 object->cutoff = pLight->Phi*90/M_PI;
2766 FIXME("Unrecognized light type %d\n", pLight->Type);
2769 /* Update the live definitions if the light is currently assigned a glIndex */
2770 if (object->glIndex != -1 && !This->isRecordingState) {
2771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2776 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2777 PLIGHTINFOEL *lightInfo = NULL;
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2779 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2781 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2783 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2784 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2785 if(lightInfo->OriginalIndex == Index) break;
2789 if (lightInfo == NULL) {
2790 TRACE("Light information requested but light not defined\n");
2791 return WINED3DERR_INVALIDCALL;
2794 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2799 * Get / Set Light Enable
2800 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2802 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2803 PLIGHTINFOEL *lightInfo = NULL;
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2805 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2807 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2809 /* Tests show true = 128...not clear why */
2810 Enable = Enable? 128: 0;
2812 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2813 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2814 if(lightInfo->OriginalIndex == Index) break;
2817 TRACE("Found light: %p\n", lightInfo);
2819 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2820 if (lightInfo == NULL) {
2822 TRACE("Light enabled requested but light not defined, so defining one!\n");
2823 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2825 /* Search for it again! Should be fairly quick as near head of list */
2826 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2827 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2828 if(lightInfo->OriginalIndex == Index) break;
2831 if (lightInfo == NULL) {
2832 FIXME("Adding default lights has failed dismally\n");
2833 return WINED3DERR_INVALIDCALL;
2837 lightInfo->enabledChanged = TRUE;
2839 if(lightInfo->glIndex != -1) {
2840 if(!This->isRecordingState) {
2841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2844 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2845 lightInfo->glIndex = -1;
2847 TRACE("Light already disabled, nothing to do\n");
2849 lightInfo->enabled = FALSE;
2851 lightInfo->enabled = TRUE;
2852 if (lightInfo->glIndex != -1) {
2854 TRACE("Nothing to do as light was enabled\n");
2857 /* Find a free gl light */
2858 for(i = 0; i < This->maxConcurrentLights; i++) {
2859 if(This->stateBlock->activeLights[i] == NULL) {
2860 This->stateBlock->activeLights[i] = lightInfo;
2861 lightInfo->glIndex = i;
2865 if(lightInfo->glIndex == -1) {
2866 /* Our tests show that Windows returns D3D_OK in this situation, even with
2867 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2868 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2869 * as well for those lights.
2871 * TODO: Test how this affects rendering
2873 FIXME("Too many concurrently active lights\n");
2877 /* i == lightInfo->glIndex */
2878 if(!This->isRecordingState) {
2879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2889 PLIGHTINFOEL *lightInfo = NULL;
2890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2892 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2893 TRACE("(%p) : for idx(%d)\n", This, Index);
2895 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2896 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2897 if(lightInfo->OriginalIndex == Index) break;
2901 if (lightInfo == NULL) {
2902 TRACE("Light enabled state requested but light not defined\n");
2903 return WINED3DERR_INVALIDCALL;
2905 /* true is 128 according to SetLightEnable */
2906 *pEnable = lightInfo->enabled ? 128 : 0;
2911 * Get / Set Clip Planes
2913 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2915 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2917 /* Validate Index */
2918 if (Index >= GL_LIMITS(clipplanes)) {
2919 TRACE("Application has requested clipplane this device doesn't support\n");
2920 return WINED3DERR_INVALIDCALL;
2923 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2925 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2926 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2927 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2928 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2929 TRACE("Application is setting old values over, nothing to do\n");
2933 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2934 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2935 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2936 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2938 /* Handle recording of state blocks */
2939 if (This->isRecordingState) {
2940 TRACE("Recording... not performing anything\n");
2944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2949 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 TRACE("(%p) : for idx %d\n", This, Index);
2953 /* Validate Index */
2954 if (Index >= GL_LIMITS(clipplanes)) {
2955 TRACE("Application has requested clipplane this device doesn't support\n");
2956 return WINED3DERR_INVALIDCALL;
2959 pPlane[0] = This->stateBlock->clipplane[Index][0];
2960 pPlane[1] = This->stateBlock->clipplane[Index][1];
2961 pPlane[2] = This->stateBlock->clipplane[Index][2];
2962 pPlane[3] = This->stateBlock->clipplane[Index][3];
2967 * Get / Set Clip Plane Status
2968 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2970 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 FIXME("(%p) : stub\n", This);
2973 if (NULL == pClipStatus) {
2974 return WINED3DERR_INVALIDCALL;
2976 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2977 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2981 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 FIXME("(%p) : stub\n", This);
2984 if (NULL == pClipStatus) {
2985 return WINED3DERR_INVALIDCALL;
2987 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2988 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2993 * Get / Set Material
2995 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 This->updateStateBlock->changed.material = TRUE;
2999 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
3001 /* Handle recording of state blocks */
3002 if (This->isRecordingState) {
3003 TRACE("Recording... not performing anything\n");
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3014 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3015 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3016 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3017 pMaterial->Ambient.b, pMaterial->Ambient.a);
3018 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3019 pMaterial->Specular.b, pMaterial->Specular.a);
3020 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3021 pMaterial->Emissive.b, pMaterial->Emissive.a);
3022 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3030 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 IWineD3DIndexBuffer *oldIdxs;
3034 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3035 oldIdxs = This->updateStateBlock->pIndexData;
3037 This->updateStateBlock->changed.indices = TRUE;
3038 This->updateStateBlock->pIndexData = pIndexData;
3040 /* Handle recording of state blocks */
3041 if (This->isRecordingState) {
3042 TRACE("Recording... not performing anything\n");
3043 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3044 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3048 if(oldIdxs != pIndexData) {
3049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3050 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3051 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3056 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3059 *ppIndexData = This->stateBlock->pIndexData;
3061 /* up ref count on ppindexdata */
3063 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3064 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3066 TRACE("(%p) No index data set\n", This);
3068 TRACE("Returning %p\n", *ppIndexData);
3073 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3074 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3076 TRACE("(%p)->(%d)\n", This, BaseIndex);
3078 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3079 TRACE("Application is setting the old value over, nothing to do\n");
3083 This->updateStateBlock->baseVertexIndex = BaseIndex;
3085 if (This->isRecordingState) {
3086 TRACE("Recording... not performing anything\n");
3089 /* The base vertex index affects the stream sources */
3090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3094 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 TRACE("(%p) : base_index %p\n", This, base_index);
3098 *base_index = This->stateBlock->baseVertexIndex;
3100 TRACE("Returning %u\n", *base_index);
3106 * Get / Set Viewports
3108 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3111 TRACE("(%p)\n", This);
3112 This->updateStateBlock->changed.viewport = TRUE;
3113 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3115 /* Handle recording of state blocks */
3116 if (This->isRecordingState) {
3117 TRACE("Recording... not performing anything\n");
3121 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3122 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 TRACE("(%p)\n", This);
3132 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3137 * Get / Set Render States
3138 * TODO: Verify against dx9 definitions
3140 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 DWORD oldValue = This->stateBlock->renderState[State];
3145 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3147 This->updateStateBlock->changed.renderState[State] = TRUE;
3148 This->updateStateBlock->renderState[State] = Value;
3150 /* Handle recording of state blocks */
3151 if (This->isRecordingState) {
3152 TRACE("Recording... not performing anything\n");
3156 /* Compared here and not before the assignment to allow proper stateblock recording */
3157 if(Value == oldValue) {
3158 TRACE("Application is setting the old value over, nothing to do\n");
3160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3166 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3168 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3169 *pValue = This->stateBlock->renderState[State];
3174 * Get / Set Sampler States
3175 * TODO: Verify against dx9 definitions
3178 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3183 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3185 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3186 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3190 * SetSampler is designed to allow for more than the standard up to 8 textures
3191 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3192 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3194 * http://developer.nvidia.com/object/General_FAQ.html#t6
3196 * There are two new settings for GForce
3198 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3199 * and the texture one:
3200 * GL_MAX_TEXTURE_COORDS_ARB.
3201 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3204 oldValue = This->stateBlock->samplerState[Sampler][Type];
3205 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3206 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3208 /* Handle recording of state blocks */
3209 if (This->isRecordingState) {
3210 TRACE("Recording... not performing anything\n");
3214 if(oldValue == Value) {
3215 TRACE("Application is setting the old value over, nothing to do\n");
3219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3224 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3228 This, Sampler, debug_d3dsamplerstate(Type), Type);
3230 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3231 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3234 *Value = This->stateBlock->samplerState[Sampler][Type];
3235 TRACE("(%p) : Returning %#x\n", This, *Value);
3240 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3243 This->updateStateBlock->changed.scissorRect = TRUE;
3244 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3245 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3248 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3250 if(This->isRecordingState) {
3251 TRACE("Recording... not performing anything\n");
3255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3264 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3268 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3270 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3272 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3274 This->updateStateBlock->vertexDecl = pDecl;
3275 This->updateStateBlock->changed.vertexDecl = TRUE;
3277 if (This->isRecordingState) {
3278 TRACE("Recording... not performing anything\n");
3280 } else if(pDecl == oldDecl) {
3281 /* Checked after the assignment to allow proper stateblock recording */
3282 TRACE("Application is setting the old declaration over, nothing to do\n");
3286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3290 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3295 *ppDecl = This->stateBlock->vertexDecl;
3296 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3300 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3302 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3304 This->updateStateBlock->vertexShader = pShader;
3305 This->updateStateBlock->changed.vertexShader = TRUE;
3307 if (This->isRecordingState) {
3308 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3309 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3310 TRACE("Recording... not performing anything\n");
3312 } else if(oldShader == pShader) {
3313 /* Checked here to allow proper stateblock recording */
3314 TRACE("App is setting the old shader over, nothing to do\n");
3318 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3319 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3320 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3327 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3330 if (NULL == ppShader) {
3331 return WINED3DERR_INVALIDCALL;
3333 *ppShader = This->stateBlock->vertexShader;
3334 if( NULL != *ppShader)
3335 IWineD3DVertexShader_AddRef(*ppShader);
3337 TRACE("(%p) : returning %p\n", This, *ppShader);
3341 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3342 IWineD3DDevice *iface,
3344 CONST BOOL *srcData,
3347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 int i, cnt = min(count, MAX_CONST_B - start);
3350 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3351 iface, srcData, start, count);
3353 if (srcData == NULL || cnt < 0)
3354 return WINED3DERR_INVALIDCALL;
3356 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3357 for (i = 0; i < cnt; i++)
3358 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3360 for (i = start; i < cnt + start; ++i) {
3361 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3369 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3370 IWineD3DDevice *iface,
3375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 int cnt = min(count, MAX_CONST_B - start);
3378 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3379 iface, dstData, start, count);
3381 if (dstData == NULL || cnt < 0)
3382 return WINED3DERR_INVALIDCALL;
3384 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3388 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3389 IWineD3DDevice *iface,
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 int i, cnt = min(count, MAX_CONST_I - start);
3397 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3398 iface, srcData, start, count);
3400 if (srcData == NULL || cnt < 0)
3401 return WINED3DERR_INVALIDCALL;
3403 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3404 for (i = 0; i < cnt; i++)
3405 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3406 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3408 for (i = start; i < cnt + start; ++i) {
3409 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3417 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3418 IWineD3DDevice *iface,
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3424 int cnt = min(count, MAX_CONST_I - start);
3426 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3427 iface, dstData, start, count);
3429 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3430 return WINED3DERR_INVALIDCALL;
3432 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3436 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3437 IWineD3DDevice *iface,
3439 CONST float *srcData,
3442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3445 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3446 iface, srcData, start, count);
3448 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3449 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3450 return WINED3DERR_INVALIDCALL;
3452 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3454 for (i = 0; i < count; i++)
3455 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3456 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3459 for (i = start; i < count + start; ++i) {
3460 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3461 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3462 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3463 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3464 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3466 ptr->idx[ptr->count++] = i;
3467 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3476 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3477 IWineD3DDevice *iface,
3482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3483 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3485 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3486 iface, dstData, start, count);
3488 if (dstData == NULL || cnt < 0)
3489 return WINED3DERR_INVALIDCALL;
3491 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3495 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3497 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3502 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3503 int i = This->rev_tex_unit_map[unit];
3504 int j = This->texUnitMap[stage];
3506 This->texUnitMap[stage] = unit;
3507 if (i != -1 && i != stage) {
3508 This->texUnitMap[i] = -1;
3511 This->rev_tex_unit_map[unit] = stage;
3512 if (j != -1 && j != unit) {
3513 This->rev_tex_unit_map[j] = -1;
3517 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3520 for (i = 0; i < MAX_TEXTURES; ++i) {
3521 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3522 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3523 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3524 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3525 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3526 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3527 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3528 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3530 if (color_op == WINED3DTOP_DISABLE) {
3531 /* Not used, and disable higher stages */
3532 while (i < MAX_TEXTURES) {
3533 This->fixed_function_usage_map[i] = FALSE;
3539 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3540 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3541 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3542 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3543 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3544 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3545 This->fixed_function_usage_map[i] = TRUE;
3547 This->fixed_function_usage_map[i] = FALSE;
3550 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3551 This->fixed_function_usage_map[i+1] = TRUE;
3556 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3559 device_update_fixed_function_usage_map(This);
3561 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3562 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3563 if (!This->fixed_function_usage_map[i]) continue;
3565 if (This->texUnitMap[i] != i) {
3566 device_map_stage(This, i, i);
3567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3568 markTextureStagesDirty(This, i);
3574 /* Now work out the mapping */
3576 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3577 if (!This->fixed_function_usage_map[i]) continue;
3579 if (This->texUnitMap[i] != tex) {
3580 device_map_stage(This, i, tex);
3581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3582 markTextureStagesDirty(This, i);
3589 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3590 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3593 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3594 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3595 device_map_stage(This, i, i);
3596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3597 if (i < MAX_TEXTURES) {
3598 markTextureStagesDirty(This, i);
3604 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3605 int current_mapping = This->rev_tex_unit_map[unit];
3607 if (current_mapping == -1) {
3608 /* Not currently used */
3612 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3613 /* Used by a fragment sampler */
3615 if (!pshader_sampler_tokens) {
3616 /* No pixel shader, check fixed function */
3617 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3620 /* Pixel shader, check the shader's sampler map */
3621 return !pshader_sampler_tokens[current_mapping];
3624 /* Used by a vertex sampler */
3625 return !vshader_sampler_tokens[current_mapping];
3628 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3629 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3630 DWORD *pshader_sampler_tokens = NULL;
3631 int start = GL_LIMITS(combined_samplers) - 1;
3635 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3637 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3638 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3639 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3642 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3643 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3644 if (vshader_sampler_tokens[i]) {
3645 if (This->texUnitMap[vsampler_idx] != -1) {
3646 /* Already mapped somewhere */
3650 while (start >= 0) {
3651 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3652 device_map_stage(This, vsampler_idx, start);
3653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3665 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3666 BOOL vs = use_vs(This);
3667 BOOL ps = use_ps(This);
3670 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3671 * that would be really messy and require shader recompilation
3672 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3673 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3676 device_map_psamplers(This);
3678 device_map_fixed_function_samplers(This);
3682 device_map_vsamplers(This, ps);
3686 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3688 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3689 This->updateStateBlock->pixelShader = pShader;
3690 This->updateStateBlock->changed.pixelShader = TRUE;
3692 /* Handle recording of state blocks */
3693 if (This->isRecordingState) {
3694 TRACE("Recording... not performing anything\n");
3697 if (This->isRecordingState) {
3698 TRACE("Recording... not performing anything\n");
3699 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3700 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3704 if(pShader == oldShader) {
3705 TRACE("App is setting the old pixel shader over, nothing to do\n");
3709 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3710 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3712 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3718 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3721 if (NULL == ppShader) {
3722 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3723 return WINED3DERR_INVALIDCALL;
3726 *ppShader = This->stateBlock->pixelShader;
3727 if (NULL != *ppShader) {
3728 IWineD3DPixelShader_AddRef(*ppShader);
3730 TRACE("(%p) : returning %p\n", This, *ppShader);
3734 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3735 IWineD3DDevice *iface,
3737 CONST BOOL *srcData,
3740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3741 int i, cnt = min(count, MAX_CONST_B - start);
3743 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3744 iface, srcData, start, count);
3746 if (srcData == NULL || cnt < 0)
3747 return WINED3DERR_INVALIDCALL;
3749 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3750 for (i = 0; i < cnt; i++)
3751 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3753 for (i = start; i < cnt + start; ++i) {
3754 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3757 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3762 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3763 IWineD3DDevice *iface,
3768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3769 int cnt = min(count, MAX_CONST_B - start);
3771 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3772 iface, dstData, start, count);
3774 if (dstData == NULL || cnt < 0)
3775 return WINED3DERR_INVALIDCALL;
3777 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3781 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3782 IWineD3DDevice *iface,
3787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3788 int i, cnt = min(count, MAX_CONST_I - start);
3790 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3791 iface, srcData, start, count);
3793 if (srcData == NULL || cnt < 0)
3794 return WINED3DERR_INVALIDCALL;
3796 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3797 for (i = 0; i < cnt; i++)
3798 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3799 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3801 for (i = start; i < cnt + start; ++i) {
3802 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3810 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3811 IWineD3DDevice *iface,
3816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3817 int cnt = min(count, MAX_CONST_I - start);
3819 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3820 iface, dstData, start, count);
3822 if (dstData == NULL || cnt < 0)
3823 return WINED3DERR_INVALIDCALL;
3825 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3829 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3830 IWineD3DDevice *iface,
3832 CONST float *srcData,
3835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3838 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3839 iface, srcData, start, count);
3841 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3842 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3843 return WINED3DERR_INVALIDCALL;
3845 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3847 for (i = 0; i < count; i++)
3848 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3849 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3852 for (i = start; i < count + start; ++i) {
3853 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3854 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3855 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3856 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3857 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3859 ptr->idx[ptr->count++] = i;
3860 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3869 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3870 IWineD3DDevice *iface,
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3876 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3878 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3879 iface, dstData, start, count);
3881 if (dstData == NULL || cnt < 0)
3882 return WINED3DERR_INVALIDCALL;
3884 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3888 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3890 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3891 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3893 DWORD DestFVF = dest->fvf;
3895 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3899 if (lpStrideData->u.s.normal.lpData) {
3900 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3903 if (lpStrideData->u.s.position.lpData == NULL) {
3904 ERR("Source has no position mask\n");
3905 return WINED3DERR_INVALIDCALL;
3908 /* We might access VBOs from this code, so hold the lock */
3911 if (dest->resource.allocatedMemory == NULL) {
3912 /* This may happen if we do direct locking into a vbo. Unlikely,
3913 * but theoretically possible(ddraw processvertices test)
3915 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3916 if(!dest->resource.allocatedMemory) {
3918 ERR("Out of memory\n");
3919 return E_OUTOFMEMORY;
3923 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3924 checkGLcall("glBindBufferARB");
3925 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3927 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3929 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3930 checkGLcall("glUnmapBufferARB");
3934 /* Get a pointer into the destination vbo(create one if none exists) and
3935 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3937 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3942 unsigned char extrabytes = 0;
3943 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3944 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3945 * this may write 4 extra bytes beyond the area that should be written
3947 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3948 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3949 if(!dest_conv_addr) {
3950 ERR("Out of memory\n");
3951 /* Continue without storing converted vertices */
3953 dest_conv = dest_conv_addr;
3957 * a) WINED3DRS_CLIPPING is enabled
3958 * b) WINED3DVOP_CLIP is passed
3960 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3961 static BOOL warned = FALSE;
3963 * The clipping code is not quite correct. Some things need
3964 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3965 * so disable clipping for now.
3966 * (The graphics in Half-Life are broken, and my processvertices
3967 * test crashes with IDirect3DDevice3)
3973 FIXME("Clipping is broken and disabled for now\n");
3975 } else doClip = FALSE;
3976 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3978 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3981 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3982 WINED3DTS_PROJECTION,
3984 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3985 WINED3DTS_WORLDMATRIX(0),
3988 TRACE("View mat:\n");
3989 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);
3990 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);
3991 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);
3992 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);
3994 TRACE("Proj mat:\n");
3995 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);
3996 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);
3997 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);
3998 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);
4000 TRACE("World mat:\n");
4001 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);
4002 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);
4003 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);
4004 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);
4006 /* Get the viewport */
4007 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4008 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4009 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4011 multiply_matrix(&mat,&view_mat,&world_mat);
4012 multiply_matrix(&mat,&proj_mat,&mat);
4014 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4016 for (i = 0; i < dwCount; i+= 1) {
4017 unsigned int tex_index;
4019 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4020 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4021 /* The position first */
4023 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4025 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4027 /* Multiplication with world, view and projection matrix */
4028 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);
4029 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);
4030 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);
4031 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);
4033 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4035 /* WARNING: The following things are taken from d3d7 and were not yet checked
4036 * against d3d8 or d3d9!
4039 /* Clipping conditions: From
4040 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4042 * A vertex is clipped if it does not match the following requirements
4046 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4048 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4049 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4054 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4055 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4058 /* "Normal" viewport transformation (not clipped)
4059 * 1) The values are divided by rhw
4060 * 2) The y axis is negative, so multiply it with -1
4061 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4062 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4063 * 4) Multiply x with Width/2 and add Width/2
4064 * 5) The same for the height
4065 * 6) Add the viewpoint X and Y to the 2D coordinates and
4066 * The minimum Z value to z
4067 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4069 * Well, basically it's simply a linear transformation into viewport
4081 z *= vp.MaxZ - vp.MinZ;
4083 x += vp.Width / 2 + vp.X;
4084 y += vp.Height / 2 + vp.Y;
4089 /* That vertex got clipped
4090 * Contrary to OpenGL it is not dropped completely, it just
4091 * undergoes a different calculation.
4093 TRACE("Vertex got clipped\n");
4100 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4101 * outside of the main vertex buffer memory. That needs some more
4106 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4109 ( (float *) dest_ptr)[0] = x;
4110 ( (float *) dest_ptr)[1] = y;
4111 ( (float *) dest_ptr)[2] = z;
4112 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4114 dest_ptr += 3 * sizeof(float);
4116 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4117 dest_ptr += sizeof(float);
4122 ( (float *) dest_conv)[0] = x * w;
4123 ( (float *) dest_conv)[1] = y * w;
4124 ( (float *) dest_conv)[2] = z * w;
4125 ( (float *) dest_conv)[3] = w;
4127 dest_conv += 3 * sizeof(float);
4129 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4130 dest_conv += sizeof(float);
4134 if (DestFVF & WINED3DFVF_PSIZE) {
4135 dest_ptr += sizeof(DWORD);
4136 if(dest_conv) dest_conv += sizeof(DWORD);
4138 if (DestFVF & WINED3DFVF_NORMAL) {
4140 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4141 /* AFAIK this should go into the lighting information */
4142 FIXME("Didn't expect the destination to have a normal\n");
4143 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4145 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4149 if (DestFVF & WINED3DFVF_DIFFUSE) {
4151 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4153 static BOOL warned = FALSE;
4156 ERR("No diffuse color in source, but destination has one\n");
4160 *( (DWORD *) dest_ptr) = 0xffffffff;
4161 dest_ptr += sizeof(DWORD);
4164 *( (DWORD *) dest_conv) = 0xffffffff;
4165 dest_conv += sizeof(DWORD);
4169 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4171 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4172 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4173 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4174 dest_conv += sizeof(DWORD);
4179 if (DestFVF & WINED3DFVF_SPECULAR) {
4180 /* What's the color value in the feedback buffer? */
4182 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4184 static BOOL warned = FALSE;
4187 ERR("No specular color in source, but destination has one\n");
4191 *( (DWORD *) dest_ptr) = 0xFF000000;
4192 dest_ptr += sizeof(DWORD);
4195 *( (DWORD *) dest_conv) = 0xFF000000;
4196 dest_conv += sizeof(DWORD);
4200 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4202 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4203 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4204 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4205 dest_conv += sizeof(DWORD);
4210 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4212 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4213 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4215 ERR("No source texture, but destination requests one\n");
4216 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4217 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4220 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4222 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4229 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4230 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4231 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4232 dwCount * get_flexible_vertex_size(DestFVF),
4234 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4235 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4242 #undef copy_and_next
4244 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4246 WineDirect3DVertexStridedData strided;
4247 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4248 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4251 ERR("Output vertex declaration not implemented yet\n");
4254 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4255 * and this call is quite performance critical, so don't call needlessly
4257 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4258 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4261 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4262 * control the streamIsUP flag, thus restore it afterwards.
4264 This->stateBlock->streamIsUP = FALSE;
4265 memset(&strided, 0, sizeof(strided));
4266 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4267 This->stateBlock->streamIsUP = streamWasUP;
4269 if(vbo || SrcStartIndex) {
4271 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4272 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4274 * Also get the start index in, but only loop over all elements if there's something to add at all.
4276 #define FIXSRC(type) \
4277 if(strided.u.s.type.VBO) { \
4278 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4279 strided.u.s.type.VBO = 0; \
4280 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4282 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4286 if(strided.u.s.type.lpData) { \
4287 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4290 FIXSRC(blendWeights);
4291 FIXSRC(blendMatrixIndices);
4296 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4297 FIXSRC(texCoords[i]);
4310 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4314 * Get / Set Texture Stage States
4315 * TODO: Verify against dx9 definitions
4317 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4321 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4323 if (Stage >= MAX_TEXTURES) {
4324 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4328 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4329 This->updateStateBlock->textureState[Stage][Type] = Value;
4331 if (This->isRecordingState) {
4332 TRACE("Recording... not performing anything\n");
4336 /* Checked after the assignments to allow proper stateblock recording */
4337 if(oldValue == Value) {
4338 TRACE("App is setting the old value over, nothing to do\n");
4342 if(Stage > This->stateBlock->lowest_disabled_stage &&
4343 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4344 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4345 * Changes in other states are important on disabled stages too
4350 if(Type == WINED3DTSS_COLOROP) {
4353 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4354 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4355 * they have to be disabled
4357 * The current stage is dirtified below.
4359 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4360 TRACE("Additionally dirtifying stage %d\n", i);
4361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4363 This->stateBlock->lowest_disabled_stage = Stage;
4364 TRACE("New lowest disabled: %d\n", Stage);
4365 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4366 /* Previously disabled stage enabled. Stages above it may need enabling
4367 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4368 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4370 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4373 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4374 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4377 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4380 This->stateBlock->lowest_disabled_stage = i;
4381 TRACE("New lowest disabled: %d\n", i);
4383 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4384 /* TODO: Built a stage -> texture unit mapping for register combiners */
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4393 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4395 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4396 *pValue = This->updateStateBlock->textureState[Stage][Type];
4403 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4405 IWineD3DBaseTexture *oldTexture;
4407 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4409 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4410 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4413 oldTexture = This->updateStateBlock->textures[Stage];
4415 if(pTexture != NULL) {
4416 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4418 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4419 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4420 return WINED3DERR_INVALIDCALL;
4422 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4425 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4426 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4428 This->updateStateBlock->changed.textures[Stage] = TRUE;
4429 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4430 This->updateStateBlock->textures[Stage] = pTexture;
4432 /* Handle recording of state blocks */
4433 if (This->isRecordingState) {
4434 TRACE("Recording... not performing anything\n");
4438 if(oldTexture == pTexture) {
4439 TRACE("App is setting the same texture again, nothing to do\n");
4443 /** NOTE: MSDN says that setTexture increases the reference count,
4444 * and that the application must set the texture back to null (or have a leaky application),
4445 * This means we should pass the refcount up to the parent
4446 *******************************/
4447 if (NULL != This->updateStateBlock->textures[Stage]) {
4448 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4449 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4451 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4452 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4453 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4454 * so the COLOROP and ALPHAOP have to be dirtified.
4456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4457 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4459 if(bindCount == 1) {
4460 new->baseTexture.sampler = Stage;
4462 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4466 if (NULL != oldTexture) {
4467 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4468 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4470 IWineD3DBaseTexture_Release(oldTexture);
4471 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4476 if(bindCount && old->baseTexture.sampler == Stage) {
4478 /* Have to do a search for the other sampler(s) where the texture is bound to
4479 * Shouldn't happen as long as apps bind a texture only to one stage
4481 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4482 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4483 if(This->updateStateBlock->textures[i] == oldTexture) {
4484 old->baseTexture.sampler = i;
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4496 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4499 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4501 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4502 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4505 *ppTexture=This->stateBlock->textures[Stage];
4507 IWineD3DBaseTexture_AddRef(*ppTexture);
4509 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4517 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4518 IWineD3DSurface **ppBackBuffer) {
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 IWineD3DSwapChain *swapChain;
4523 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4525 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4526 if (hr == WINED3D_OK) {
4527 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4528 IWineD3DSwapChain_Release(swapChain);
4530 *ppBackBuffer = NULL;
4535 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4537 WARN("(%p) : stub, calling idirect3d for now\n", This);
4538 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4541 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 IWineD3DSwapChain *swapChain;
4546 if(iSwapChain > 0) {
4547 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4548 if (hr == WINED3D_OK) {
4549 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4550 IWineD3DSwapChain_Release(swapChain);
4552 FIXME("(%p) Error getting display mode\n", This);
4555 /* Don't read the real display mode,
4556 but return the stored mode instead. X11 can't change the color
4557 depth, and some apps are pretty angry if they SetDisplayMode from
4558 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4560 Also don't relay to the swapchain because with ddraw it's possible
4561 that there isn't a swapchain at all */
4562 pMode->Width = This->ddraw_width;
4563 pMode->Height = This->ddraw_height;
4564 pMode->Format = This->ddraw_format;
4565 pMode->RefreshRate = 0;
4572 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4574 TRACE("(%p)->(%p)\n", This, hWnd);
4576 if(This->ddraw_fullscreen) {
4577 if(This->ddraw_window && This->ddraw_window != hWnd) {
4578 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4580 if(hWnd && This->ddraw_window != hWnd) {
4581 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4585 This->ddraw_window = hWnd;
4589 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4591 TRACE("(%p)->(%p)\n", This, hWnd);
4593 *hWnd = This->ddraw_window;
4598 * Stateblock related functions
4601 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 IWineD3DStateBlockImpl *object;
4604 HRESULT temp_result;
4607 TRACE("(%p)\n", This);
4609 if (This->isRecordingState) {
4610 return WINED3DERR_INVALIDCALL;
4613 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4614 if (NULL == object ) {
4615 FIXME("(%p)Error allocating memory for stateblock\n", This);
4616 return E_OUTOFMEMORY;
4618 TRACE("(%p) created object %p\n", This, object);
4619 object->wineD3DDevice= This;
4620 /** FIXME: object->parent = parent; **/
4621 object->parent = NULL;
4622 object->blockType = WINED3DSBT_RECORDED;
4624 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4626 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4627 list_init(&object->lightMap[i]);
4630 temp_result = allocate_shader_constants(object);
4631 if (WINED3D_OK != temp_result)
4634 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4635 This->updateStateBlock = object;
4636 This->isRecordingState = TRUE;
4638 TRACE("(%p) recording stateblock %p\n",This , object);
4642 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4647 if (!This->isRecordingState) {
4648 FIXME("(%p) not recording! returning error\n", This);
4649 *ppStateBlock = NULL;
4650 return WINED3DERR_INVALIDCALL;
4653 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4654 if(object->changed.renderState[i]) {
4655 object->contained_render_states[object->num_contained_render_states] = i;
4656 object->num_contained_render_states++;
4659 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4660 if(object->changed.transform[i]) {
4661 object->contained_transform_states[object->num_contained_transform_states] = i;
4662 object->num_contained_transform_states++;
4665 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4666 if(object->changed.vertexShaderConstantsF[i]) {
4667 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4668 object->num_contained_vs_consts_f++;
4671 for(i = 0; i < MAX_CONST_I; i++) {
4672 if(object->changed.vertexShaderConstantsI[i]) {
4673 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4674 object->num_contained_vs_consts_i++;
4677 for(i = 0; i < MAX_CONST_B; i++) {
4678 if(object->changed.vertexShaderConstantsB[i]) {
4679 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4680 object->num_contained_vs_consts_b++;
4683 for(i = 0; i < MAX_CONST_I; i++) {
4684 if(object->changed.pixelShaderConstantsI[i]) {
4685 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4686 object->num_contained_ps_consts_i++;
4689 for(i = 0; i < MAX_CONST_B; i++) {
4690 if(object->changed.pixelShaderConstantsB[i]) {
4691 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4692 object->num_contained_ps_consts_b++;
4695 for(i = 0; i < MAX_TEXTURES; i++) {
4696 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4697 if(object->changed.textureState[i][j]) {
4698 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4699 object->contained_tss_states[object->num_contained_tss_states].state = j;
4700 object->num_contained_tss_states++;
4704 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4705 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4706 if(object->changed.samplerState[i][j]) {
4707 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4708 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4709 object->num_contained_sampler_states++;
4714 *ppStateBlock = (IWineD3DStateBlock*) object;
4715 This->isRecordingState = FALSE;
4716 This->updateStateBlock = This->stateBlock;
4717 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4718 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4719 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4724 * Scene related functions
4726 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4727 /* At the moment we have no need for any functionality at the beginning
4729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 TRACE("(%p)\n", This);
4733 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4734 return WINED3DERR_INVALIDCALL;
4736 This->inScene = TRUE;
4740 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4742 TRACE("(%p)\n", This);
4744 if(!This->inScene) {
4745 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4746 return WINED3DERR_INVALIDCALL;
4749 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4750 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4752 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4755 checkGLcall("glFlush");
4758 This->inScene = FALSE;
4762 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4763 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4764 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4766 IWineD3DSwapChain *swapChain = NULL;
4768 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4770 TRACE("(%p) Presenting the frame\n", This);
4772 for(i = 0 ; i < swapchains ; i ++) {
4774 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4775 TRACE("presentinng chain %d, %p\n", i, swapChain);
4776 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4777 IWineD3DSwapChain_Release(swapChain);
4783 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4784 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4786 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4788 GLbitfield glMask = 0;
4790 WINED3DRECT curRect;
4792 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4793 UINT drawable_width, drawable_height;
4795 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4796 Count, pRects, Flags, Color, Z, Stencil);
4798 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4799 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4800 /* TODO: What about depth stencil buffers without stencil bits? */
4801 return WINED3DERR_INVALIDCALL;
4804 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4805 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4806 * for the cleared parts, and the untouched parts.
4808 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4809 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4810 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4811 * checking all this if the dest surface is in the drawable anyway.
4813 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4815 if(vp->X != 0 || vp->Y != 0 ||
4816 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4817 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4820 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4821 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4822 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4823 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4824 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4827 if(Count > 0 && pRects && (
4828 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4829 pRects[0].x2 < target->currentDesc.Width ||
4830 pRects[0].y2 < target->currentDesc.Height)) {
4831 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4838 target->get_drawable_size(target, &drawable_width, &drawable_height);
4840 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4841 * and not the last active one.
4843 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4846 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4847 apply_fbo_state(iface);
4850 /* Only set the values up once, as they are not changing */
4851 if (Flags & WINED3DCLEAR_STENCIL) {
4852 glClearStencil(Stencil);
4853 checkGLcall("glClearStencil");
4854 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4855 glStencilMask(0xFFFFFFFF);
4858 if (Flags & WINED3DCLEAR_ZBUFFER) {
4859 glDepthMask(GL_TRUE);
4861 checkGLcall("glClearDepth");
4862 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4866 if (Flags & WINED3DCLEAR_TARGET) {
4867 TRACE("Clearing screen with glClear to color %x\n", Color);
4868 glClearColor(D3DCOLOR_R(Color),
4872 checkGLcall("glClearColor");
4874 /* Clear ALL colors! */
4875 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4876 glMask = glMask | GL_COLOR_BUFFER_BIT;
4879 vp_rect.left = vp->X;
4880 vp_rect.top = vp->Y;
4881 vp_rect.right = vp->X + vp->Width;
4882 vp_rect.bottom = vp->Y + vp->Height;
4883 if (!(Count > 0 && pRects)) {
4884 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4885 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4887 if(This->render_offscreen) {
4888 glScissor(vp_rect.left, vp_rect.top,
4889 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4891 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4892 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4894 checkGLcall("glScissor");
4896 checkGLcall("glClear");
4898 /* Now process each rect in turn */
4899 for (i = 0; i < Count; i++) {
4900 /* Note gl uses lower left, width/height */
4901 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4902 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4903 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4905 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4906 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4907 curRect.x1, (target->currentDesc.Height - curRect.y2),
4908 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4910 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4911 * The rectangle is not cleared, no error is returned, but further rectanlges are
4912 * still cleared if they are valid
4914 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4915 TRACE("Rectangle with negative dimensions, ignoring\n");
4919 if(This->render_offscreen) {
4920 glScissor(curRect.x1, curRect.y1,
4921 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4923 glScissor(curRect.x1, drawable_height - curRect.y2,
4924 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4926 checkGLcall("glScissor");
4929 checkGLcall("glClear");
4933 /* Restore the old values (why..?) */
4934 if (Flags & WINED3DCLEAR_STENCIL) {
4935 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4937 if (Flags & WINED3DCLEAR_TARGET) {
4938 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4939 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4940 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4941 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4942 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4944 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4945 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4947 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4948 /* TODO: Move the fbo logic into ModifyLocation() */
4949 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4950 target->Flags |= SFLAG_INTEXTURE;
4961 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4962 UINT PrimitiveCount) {
4964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4967 debug_d3dprimitivetype(PrimitiveType),
4968 StartVertex, PrimitiveCount);
4970 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4971 if(This->stateBlock->streamIsUP) {
4972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4973 This->stateBlock->streamIsUP = FALSE;
4976 if(This->stateBlock->loadBaseVertexIndex != 0) {
4977 This->stateBlock->loadBaseVertexIndex = 0;
4978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4980 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4981 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4982 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4986 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4987 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4988 WINED3DPRIMITIVETYPE PrimitiveType,
4989 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4993 IWineD3DIndexBuffer *pIB;
4994 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4997 pIB = This->stateBlock->pIndexData;
4999 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5000 * without an index buffer set. (The first time at least...)
5001 * D3D8 simply dies, but I doubt it can do much harm to return
5002 * D3DERR_INVALIDCALL there as well. */
5003 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5004 return WINED3DERR_INVALIDCALL;
5007 if(This->stateBlock->streamIsUP) {
5008 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5009 This->stateBlock->streamIsUP = FALSE;
5011 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5013 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5014 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5015 minIndex, NumVertices, startIndex, primCount);
5017 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5018 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5024 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5025 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5029 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5030 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5035 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5036 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5037 UINT VertexStreamZeroStride) {
5038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5039 IWineD3DVertexBuffer *vb;
5041 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5042 debug_d3dprimitivetype(PrimitiveType),
5043 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5045 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5046 vb = This->stateBlock->streamSource[0];
5047 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5048 if(vb) IWineD3DVertexBuffer_Release(vb);
5049 This->stateBlock->streamOffset[0] = 0;
5050 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5051 This->stateBlock->streamIsUP = TRUE;
5052 This->stateBlock->loadBaseVertexIndex = 0;
5054 /* TODO: Only mark dirty if drawing from a different UP address */
5055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5057 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5058 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5060 /* MSDN specifies stream zero settings must be set to NULL */
5061 This->stateBlock->streamStride[0] = 0;
5062 This->stateBlock->streamSource[0] = NULL;
5064 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5065 * the new stream sources or use UP drawing again
5070 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5071 UINT MinVertexIndex, UINT NumVertices,
5072 UINT PrimitiveCount, CONST void* pIndexData,
5073 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5074 UINT VertexStreamZeroStride) {
5076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5077 IWineD3DVertexBuffer *vb;
5078 IWineD3DIndexBuffer *ib;
5080 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5081 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5082 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5083 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5085 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5091 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5092 vb = This->stateBlock->streamSource[0];
5093 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5094 if(vb) IWineD3DVertexBuffer_Release(vb);
5095 This->stateBlock->streamIsUP = TRUE;
5096 This->stateBlock->streamOffset[0] = 0;
5097 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5099 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5100 This->stateBlock->baseVertexIndex = 0;
5101 This->stateBlock->loadBaseVertexIndex = 0;
5102 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5106 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5108 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5109 This->stateBlock->streamSource[0] = NULL;
5110 This->stateBlock->streamStride[0] = 0;
5111 ib = This->stateBlock->pIndexData;
5113 IWineD3DIndexBuffer_Release(ib);
5114 This->stateBlock->pIndexData = NULL;
5116 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5117 * SetStreamSource to specify a vertex buffer
5123 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5126 /* Mark the state dirty until we have nicer tracking
5127 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5132 This->stateBlock->baseVertexIndex = 0;
5133 This->up_strided = DrawPrimStrideData;
5134 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5135 This->up_strided = NULL;
5139 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5141 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5143 /* Mark the state dirty until we have nicer tracking
5144 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5147 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5149 This->stateBlock->streamIsUP = TRUE;
5150 This->stateBlock->baseVertexIndex = 0;
5151 This->up_strided = DrawPrimStrideData;
5152 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5153 This->up_strided = NULL;
5157 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5158 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5159 * not callable by the app directly no parameter validation checks are needed here.
5161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5162 WINED3DLOCKED_BOX src;
5163 WINED3DLOCKED_BOX dst;
5165 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5167 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5168 * dirtification to improve loading performance.
5170 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5171 if(FAILED(hr)) return hr;
5172 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5174 IWineD3DVolume_UnlockBox(pSourceVolume);
5178 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5180 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5182 IWineD3DVolume_UnlockBox(pSourceVolume);
5184 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5189 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5190 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5192 HRESULT hr = WINED3D_OK;
5193 WINED3DRESOURCETYPE sourceType;
5194 WINED3DRESOURCETYPE destinationType;
5197 /* TODO: think about moving the code into IWineD3DBaseTexture */
5199 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5201 /* verify that the source and destination textures aren't NULL */
5202 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5203 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5204 This, pSourceTexture, pDestinationTexture);
5205 hr = WINED3DERR_INVALIDCALL;
5208 if (pSourceTexture == pDestinationTexture) {
5209 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5210 This, pSourceTexture, pDestinationTexture);
5211 hr = WINED3DERR_INVALIDCALL;
5213 /* Verify that the source and destination textures are the same type */
5214 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5215 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5217 if (sourceType != destinationType) {
5218 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5220 hr = WINED3DERR_INVALIDCALL;
5223 /* check that both textures have the identical numbers of levels */
5224 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5225 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5226 hr = WINED3DERR_INVALIDCALL;
5229 if (WINED3D_OK == hr) {
5231 /* Make sure that the destination texture is loaded */
5232 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5234 /* Update every surface level of the texture */
5235 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5237 switch (sourceType) {
5238 case WINED3DRTYPE_TEXTURE:
5240 IWineD3DSurface *srcSurface;
5241 IWineD3DSurface *destSurface;
5243 for (i = 0 ; i < levels ; ++i) {
5244 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5245 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5246 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5247 IWineD3DSurface_Release(srcSurface);
5248 IWineD3DSurface_Release(destSurface);
5249 if (WINED3D_OK != hr) {
5250 WARN("(%p) : Call to update surface failed\n", This);
5256 case WINED3DRTYPE_CUBETEXTURE:
5258 IWineD3DSurface *srcSurface;
5259 IWineD3DSurface *destSurface;
5260 WINED3DCUBEMAP_FACES faceType;
5262 for (i = 0 ; i < levels ; ++i) {
5263 /* Update each cube face */
5264 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5265 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5266 if (WINED3D_OK != hr) {
5267 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5269 TRACE("Got srcSurface %p\n", srcSurface);
5271 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5272 if (WINED3D_OK != hr) {
5273 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5275 TRACE("Got desrSurface %p\n", destSurface);
5277 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5278 IWineD3DSurface_Release(srcSurface);
5279 IWineD3DSurface_Release(destSurface);
5280 if (WINED3D_OK != hr) {
5281 WARN("(%p) : Call to update surface failed\n", This);
5289 case WINED3DRTYPE_VOLUMETEXTURE:
5291 IWineD3DVolume *srcVolume = NULL;
5292 IWineD3DVolume *destVolume = NULL;
5294 for (i = 0 ; i < levels ; ++i) {
5295 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5296 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5297 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5298 IWineD3DVolume_Release(srcVolume);
5299 IWineD3DVolume_Release(destVolume);
5300 if (WINED3D_OK != hr) {
5301 WARN("(%p) : Call to update volume failed\n", This);
5309 FIXME("(%p) : Unsupported source and destination type\n", This);
5310 hr = WINED3DERR_INVALIDCALL;
5317 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5318 IWineD3DSwapChain *swapChain;
5320 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5321 if(hr == WINED3D_OK) {
5322 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5323 IWineD3DSwapChain_Release(swapChain);
5328 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5330 /* return a sensible default */
5332 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5333 FIXME("(%p) : stub\n", This);
5337 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5340 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5341 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5342 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5343 return WINED3DERR_INVALIDCALL;
5345 for (j = 0; j < 256; ++j) {
5346 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5347 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5348 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5349 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5351 TRACE("(%p) : returning\n", This);
5355 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5358 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5359 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5360 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5361 return WINED3DERR_INVALIDCALL;
5363 for (j = 0; j < 256; ++j) {
5364 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5365 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5366 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5367 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5369 TRACE("(%p) : returning\n", This);
5373 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5375 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5376 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5377 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5378 return WINED3DERR_INVALIDCALL;
5380 /*TODO: stateblocks */
5381 This->currentPalette = PaletteNumber;
5382 TRACE("(%p) : returning\n", This);
5386 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5388 if (PaletteNumber == NULL) {
5389 WARN("(%p) : returning Invalid Call\n", This);
5390 return WINED3DERR_INVALIDCALL;
5392 /*TODO: stateblocks */
5393 *PaletteNumber = This->currentPalette;
5394 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5398 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5400 static BOOL showFixmes = TRUE;
5402 FIXME("(%p) : stub\n", This);
5406 This->softwareVertexProcessing = bSoftware;
5411 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5413 static BOOL showFixmes = TRUE;
5415 FIXME("(%p) : stub\n", This);
5418 return This->softwareVertexProcessing;
5422 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5424 IWineD3DSwapChain *swapChain;
5427 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5429 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5430 if(hr == WINED3D_OK){
5431 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5432 IWineD3DSwapChain_Release(swapChain);
5434 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5440 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5442 static BOOL showfixmes = TRUE;
5443 if(nSegments != 0.0f) {
5445 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5452 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5454 static BOOL showfixmes = TRUE;
5456 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5462 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5464 /** TODO: remove casts to IWineD3DSurfaceImpl
5465 * NOTE: move code to surface to accomplish this
5466 ****************************************/
5467 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5468 int srcWidth, srcHeight;
5469 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5470 WINED3DFORMAT destFormat, srcFormat;
5472 int srcLeft, destLeft, destTop;
5473 WINED3DPOOL srcPool, destPool;
5475 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5476 glDescriptor *glDescription = NULL;
5479 CONVERT_TYPES convert = NO_CONVERSION;
5481 WINED3DSURFACE_DESC winedesc;
5483 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5484 memset(&winedesc, 0, sizeof(winedesc));
5485 winedesc.Width = &srcSurfaceWidth;
5486 winedesc.Height = &srcSurfaceHeight;
5487 winedesc.Pool = &srcPool;
5488 winedesc.Format = &srcFormat;
5490 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5492 winedesc.Width = &destSurfaceWidth;
5493 winedesc.Height = &destSurfaceHeight;
5494 winedesc.Pool = &destPool;
5495 winedesc.Format = &destFormat;
5496 winedesc.Size = &destSize;
5498 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5500 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5501 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5502 return WINED3DERR_INVALIDCALL;
5505 /* This call loads the opengl surface directly, instead of copying the surface to the
5506 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5507 * copy in sysmem and use regular surface loading.
5509 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5510 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5511 if(convert != NO_CONVERSION) {
5512 return IWineD3DSurface_BltFast(pDestinationSurface,
5513 pDestPoint ? pDestPoint->x : 0,
5514 pDestPoint ? pDestPoint->y : 0,
5515 pSourceSurface, (RECT *) pSourceRect, 0);
5518 if (destFormat == WINED3DFMT_UNKNOWN) {
5519 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5520 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5522 /* Get the update surface description */
5523 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5526 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5530 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5531 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5532 checkGLcall("glActiveTextureARB");
5535 /* Make sure the surface is loaded and up to date */
5536 IWineD3DSurface_PreLoad(pDestinationSurface);
5538 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5540 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5541 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5542 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5543 srcLeft = pSourceRect ? pSourceRect->left : 0;
5544 destLeft = pDestPoint ? pDestPoint->x : 0;
5545 destTop = pDestPoint ? pDestPoint->y : 0;
5548 /* This function doesn't support compressed textures
5549 the pitch is just bytesPerPixel * width */
5550 if(srcWidth != srcSurfaceWidth || srcLeft ){
5551 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5552 offset += srcLeft * pSrcSurface->bytesPerPixel;
5553 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5555 /* TODO DXT formats */
5557 if(pSourceRect != NULL && pSourceRect->top != 0){
5558 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5560 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5562 ,glDescription->level
5567 ,glDescription->glFormat
5568 ,glDescription->glType
5569 ,IWineD3DSurface_GetData(pSourceSurface)
5573 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5575 /* need to lock the surface to get the data */
5576 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5579 /* TODO: Cube and volume support */
5581 /* not a whole row so we have to do it a line at a time */
5584 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5585 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5587 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5589 glTexSubImage2D(glDescription->target
5590 ,glDescription->level
5595 ,glDescription->glFormat
5596 ,glDescription->glType
5597 ,data /* could be quicker using */
5602 } else { /* Full width, so just write out the whole texture */
5604 if (WINED3DFMT_DXT1 == destFormat ||
5605 WINED3DFMT_DXT2 == destFormat ||
5606 WINED3DFMT_DXT3 == destFormat ||
5607 WINED3DFMT_DXT4 == destFormat ||
5608 WINED3DFMT_DXT5 == destFormat) {
5609 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5610 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5611 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5612 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5613 } if (destFormat != srcFormat) {
5614 FIXME("Updating mixed format compressed texture is not curretly support\n");
5616 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5617 glDescription->level,
5618 glDescription->glFormatInternal,
5623 IWineD3DSurface_GetData(pSourceSurface));
5626 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5631 glTexSubImage2D(glDescription->target
5632 ,glDescription->level
5637 ,glDescription->glFormat
5638 ,glDescription->glType
5639 ,IWineD3DSurface_GetData(pSourceSurface)
5643 checkGLcall("glTexSubImage2D");
5647 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5653 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5655 struct WineD3DRectPatch *patch;
5659 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5661 if(!(Handle || pRectPatchInfo)) {
5662 /* TODO: Write a test for the return value, thus the FIXME */
5663 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5664 return WINED3DERR_INVALIDCALL;
5668 i = PATCHMAP_HASHFUNC(Handle);
5670 LIST_FOR_EACH(e, &This->patches[i]) {
5671 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5672 if(patch->Handle == Handle) {
5679 TRACE("Patch does not exist. Creating a new one\n");
5680 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5681 patch->Handle = Handle;
5682 list_add_head(&This->patches[i], &patch->entry);
5684 TRACE("Found existing patch %p\n", patch);
5687 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5688 * attributes we have to tesselate, read back, and draw. This needs a patch
5689 * management structure instance. Create one.
5691 * A possible improvement is to check if a vertex shader is used, and if not directly
5694 FIXME("Drawing an uncached patch. This is slow\n");
5695 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5698 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5699 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5700 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5702 TRACE("Tesselation density or patch info changed, retesselating\n");
5704 if(pRectPatchInfo) {
5705 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5707 patch->numSegs[0] = pNumSegs[0];
5708 patch->numSegs[1] = pNumSegs[1];
5709 patch->numSegs[2] = pNumSegs[2];
5710 patch->numSegs[3] = pNumSegs[3];
5712 hr = tesselate_rectpatch(This, patch);
5714 WARN("Patch tesselation failed\n");
5716 /* Do not release the handle to store the params of the patch */
5718 HeapFree(GetProcessHeap(), 0, patch);
5724 This->currentPatch = patch;
5725 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5726 This->currentPatch = NULL;
5728 /* Destroy uncached patches */
5730 HeapFree(GetProcessHeap(), 0, patch->mem);
5731 HeapFree(GetProcessHeap(), 0, patch);
5736 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5737 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5740 FIXME("(%p) : Stub\n", This);
5744 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5747 struct WineD3DRectPatch *patch;
5749 TRACE("(%p) Handle(%d)\n", This, Handle);
5751 i = PATCHMAP_HASHFUNC(Handle);
5752 LIST_FOR_EACH(e, &This->patches[i]) {
5753 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5754 if(patch->Handle == Handle) {
5755 TRACE("Deleting patch %p\n", patch);
5756 list_remove(&patch->entry);
5757 HeapFree(GetProcessHeap(), 0, patch->mem);
5758 HeapFree(GetProcessHeap(), 0, patch);
5763 /* TODO: Write a test for the return value */
5764 FIXME("Attempt to destroy nonexistant patch\n");
5765 return WINED3DERR_INVALIDCALL;
5768 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5770 IWineD3DSwapChain *swapchain;
5772 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5773 if (SUCCEEDED(hr)) {
5774 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5781 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5785 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5786 checkGLcall("glGenFramebuffersEXT()");
5788 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5789 checkGLcall("glBindFramebuffer()");
5792 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5793 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5794 IWineD3DBaseTextureImpl *texture_impl;
5795 GLenum texttarget, target;
5798 texttarget = surface_impl->glDescription.target;
5799 if(texttarget == GL_TEXTURE_2D) {
5800 target = GL_TEXTURE_2D;
5801 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5802 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5803 target = GL_TEXTURE_RECTANGLE_ARB;
5804 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5806 target = GL_TEXTURE_CUBE_MAP_ARB;
5807 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5810 IWineD3DSurface_PreLoad(surface);
5812 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5813 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5814 glBindTexture(target, old_binding);
5816 /* Update base texture states array */
5817 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5818 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5819 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5820 if (texture_impl->baseTexture.bindCount) {
5821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5824 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5827 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5828 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5830 checkGLcall("attach_surface_fbo");
5833 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5835 IWineD3DSwapChain *swapchain;
5837 swapchain = get_swapchain(surface);
5841 TRACE("Surface %p is onscreen\n", surface);
5843 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5844 buffer = surface_get_gl_buffer(surface, swapchain);
5845 glDrawBuffer(buffer);
5846 checkGLcall("glDrawBuffer()");
5848 TRACE("Surface %p is offscreen\n", surface);
5849 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5850 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5854 glEnable(GL_SCISSOR_TEST);
5856 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5858 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5859 rect->x2 - rect->x1, rect->y2 - rect->y1);
5861 checkGLcall("glScissor");
5863 glDisable(GL_SCISSOR_TEST);
5865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5867 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5870 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5871 glClear(GL_COLOR_BUFFER_BIT);
5872 checkGLcall("glClear");
5874 if (This->render_offscreen) {
5875 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5877 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5878 checkGLcall("glBindFramebuffer()");
5881 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5882 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5883 glDrawBuffer(GL_BACK);
5884 checkGLcall("glDrawBuffer()");
5888 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5889 unsigned int r, g, b, a;
5892 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5893 destfmt == WINED3DFMT_R8G8B8)
5896 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5898 a = (color & 0xff000000) >> 24;
5899 r = (color & 0x00ff0000) >> 16;
5900 g = (color & 0x0000ff00) >> 8;
5901 b = (color & 0x000000ff) >> 0;
5905 case WINED3DFMT_R5G6B5:
5906 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5913 TRACE("Returning %08x\n", ret);
5916 case WINED3DFMT_X1R5G5B5:
5917 case WINED3DFMT_A1R5G5B5:
5926 TRACE("Returning %08x\n", ret);
5930 TRACE("Returning %08x\n", a);
5933 case WINED3DFMT_X4R4G4B4:
5934 case WINED3DFMT_A4R4G4B4:
5943 TRACE("Returning %08x\n", ret);
5946 case WINED3DFMT_R3G3B2:
5953 TRACE("Returning %08x\n", ret);
5956 case WINED3DFMT_X8B8G8R8:
5957 case WINED3DFMT_A8B8G8R8:
5962 TRACE("Returning %08x\n", ret);
5965 case WINED3DFMT_A2R10G10B10:
5967 r = (r * 1024) / 256;
5968 g = (g * 1024) / 256;
5969 b = (b * 1024) / 256;
5974 TRACE("Returning %08x\n", ret);
5977 case WINED3DFMT_A2B10G10R10:
5979 r = (r * 1024) / 256;
5980 g = (g * 1024) / 256;
5981 b = (b * 1024) / 256;
5986 TRACE("Returning %08x\n", ret);
5990 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5995 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5997 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5999 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6001 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6002 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6003 return WINED3DERR_INVALIDCALL;
6006 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6007 color_fill_fbo(iface, pSurface, pRect, color);
6010 /* Just forward this to the DirectDraw blitting engine */
6011 memset(&BltFx, 0, sizeof(BltFx));
6012 BltFx.dwSize = sizeof(BltFx);
6013 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6014 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6018 /* rendertarget and deptth stencil functions */
6019 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6022 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6023 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6024 return WINED3DERR_INVALIDCALL;
6027 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6028 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6029 /* Note inc ref on returned surface */
6030 if(*ppRenderTarget != NULL)
6031 IWineD3DSurface_AddRef(*ppRenderTarget);
6035 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6037 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6038 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6039 IWineD3DSwapChainImpl *Swapchain;
6042 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6044 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6045 if(hr != WINED3D_OK) {
6046 ERR("Can't get the swapchain\n");
6050 /* Make sure to release the swapchain */
6051 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6053 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6054 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6055 return WINED3DERR_INVALIDCALL;
6057 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6058 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6059 return WINED3DERR_INVALIDCALL;
6062 if(Swapchain->frontBuffer != Front) {
6063 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6065 if(Swapchain->frontBuffer)
6066 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6067 Swapchain->frontBuffer = Front;
6069 if(Swapchain->frontBuffer) {
6070 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6074 if(Back && !Swapchain->backBuffer) {
6075 /* We need memory for the back buffer array - only one back buffer this way */
6076 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6077 if(!Swapchain->backBuffer) {
6078 ERR("Out of memory\n");
6079 return E_OUTOFMEMORY;
6083 if(Swapchain->backBuffer[0] != Back) {
6084 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6086 /* What to do about the context here in the case of multithreading? Not sure.
6087 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6090 if(!Swapchain->backBuffer[0]) {
6091 /* GL was told to draw to the front buffer at creation,
6094 glDrawBuffer(GL_BACK);
6095 checkGLcall("glDrawBuffer(GL_BACK)");
6096 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6097 Swapchain->presentParms.BackBufferCount = 1;
6099 /* That makes problems - disable for now */
6100 /* glDrawBuffer(GL_FRONT); */
6101 checkGLcall("glDrawBuffer(GL_FRONT)");
6102 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6103 Swapchain->presentParms.BackBufferCount = 0;
6107 if(Swapchain->backBuffer[0])
6108 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6109 Swapchain->backBuffer[0] = Back;
6111 if(Swapchain->backBuffer[0]) {
6112 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6114 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6115 Swapchain->backBuffer = NULL;
6123 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6125 *ppZStencilSurface = This->stencilBufferTarget;
6126 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6128 if(*ppZStencilSurface != NULL) {
6129 /* Note inc ref on returned surface */
6130 IWineD3DSurface_AddRef(*ppZStencilSurface);
6133 return WINED3DERR_NOTFOUND;
6137 /* TODO: Handle stencil attachments */
6138 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6140 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6142 TRACE("Set depth stencil to %p\n", depth_stencil);
6144 if (depth_stencil_impl) {
6145 if (depth_stencil_impl->current_renderbuffer) {
6146 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6147 checkGLcall("glFramebufferRenderbufferEXT()");
6149 IWineD3DBaseTextureImpl *texture_impl;
6150 GLenum texttarget, target;
6151 GLint old_binding = 0;
6153 texttarget = depth_stencil_impl->glDescription.target;
6154 if(texttarget == GL_TEXTURE_2D) {
6155 target = GL_TEXTURE_2D;
6156 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6157 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6158 target = GL_TEXTURE_RECTANGLE_ARB;
6159 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6161 target = GL_TEXTURE_CUBE_MAP_ARB;
6162 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6165 IWineD3DSurface_PreLoad(depth_stencil);
6167 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6168 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6169 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6170 glBindTexture(target, old_binding);
6172 /* Update base texture states array */
6173 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6174 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6175 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6176 if (texture_impl->baseTexture.bindCount) {
6177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6180 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6183 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6184 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6185 checkGLcall("glFramebufferTexture2DEXT()");
6188 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6189 checkGLcall("glFramebufferTexture2DEXT()");
6193 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6195 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6197 TRACE("Set render target %u to %p\n", idx, render_target);
6200 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6201 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6203 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6204 checkGLcall("glFramebufferTexture2DEXT()");
6206 This->draw_buffers[idx] = GL_NONE;
6210 static void check_fbo_status(IWineD3DDevice *iface) {
6211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6214 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6215 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6216 TRACE("FBO complete\n");
6218 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6220 /* Dump the FBO attachments */
6221 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6222 IWineD3DSurfaceImpl *attachment;
6225 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6226 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6228 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6229 attachment->pow2Width, attachment->pow2Height);
6232 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6234 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6235 attachment->pow2Width, attachment->pow2Height);
6241 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6243 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6244 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6246 if (!ds_impl) return FALSE;
6248 if (ds_impl->current_renderbuffer) {
6249 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6250 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6253 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6254 rt_impl->pow2Height != ds_impl->pow2Height);
6257 void apply_fbo_state(IWineD3DDevice *iface) {
6258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6261 if (This->render_offscreen) {
6262 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6264 /* Apply render targets */
6265 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6266 IWineD3DSurface *render_target = This->render_targets[i];
6267 if (This->fbo_color_attachments[i] != render_target) {
6268 set_render_target_fbo(iface, i, render_target);
6269 This->fbo_color_attachments[i] = render_target;
6273 /* Apply depth targets */
6274 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6275 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6276 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6278 if (This->stencilBufferTarget) {
6279 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6281 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6282 This->fbo_depth_attachment = This->stencilBufferTarget;
6285 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6286 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6287 checkGLcall("glDrawBuffers()");
6289 glDrawBuffer(This->draw_buffers[0]);
6290 checkGLcall("glDrawBuffer()");
6293 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6296 check_fbo_status(iface);
6299 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6300 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6302 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6303 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6306 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6307 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6308 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6309 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6312 case WINED3DTEXF_LINEAR:
6313 gl_filter = GL_LINEAR;
6317 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6318 case WINED3DTEXF_NONE:
6319 case WINED3DTEXF_POINT:
6320 gl_filter = GL_NEAREST;
6324 /* Attach src surface to src fbo */
6325 src_swapchain = get_swapchain(src_surface);
6326 if (src_swapchain) {
6329 TRACE("Source surface %p is onscreen\n", src_surface);
6330 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6333 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6334 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6335 glReadBuffer(buffer);
6336 checkGLcall("glReadBuffer()");
6338 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6339 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6341 TRACE("Source surface %p is offscreen\n", src_surface);
6343 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6344 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6345 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6346 checkGLcall("glReadBuffer()");
6350 /* Attach dst surface to dst fbo */
6351 dst_swapchain = get_swapchain(dst_surface);
6352 if (dst_swapchain) {
6355 TRACE("Destination surface %p is onscreen\n", dst_surface);
6356 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6359 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6360 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6361 glDrawBuffer(buffer);
6362 checkGLcall("glDrawBuffer()");
6364 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6365 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6367 TRACE("Destination surface %p is offscreen\n", dst_surface);
6369 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6370 if(!src_swapchain) {
6371 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6375 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6376 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6377 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6378 checkGLcall("glDrawBuffer()");
6380 glDisable(GL_SCISSOR_TEST);
6381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6384 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6385 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6386 checkGLcall("glBlitFramebuffer()");
6388 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6389 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6390 checkGLcall("glBlitFramebuffer()");
6393 if (This->render_offscreen) {
6394 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6396 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6397 checkGLcall("glBindFramebuffer()");
6400 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6401 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6402 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6403 glDrawBuffer(GL_BACK);
6404 checkGLcall("glDrawBuffer()");
6409 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6411 WINED3DVIEWPORT viewport;
6413 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6415 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6416 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6417 This, RenderTargetIndex, GL_LIMITS(buffers));
6418 return WINED3DERR_INVALIDCALL;
6421 /* MSDN says that null disables the render target
6422 but a device must always be associated with a render target
6423 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6425 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6428 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6429 FIXME("Trying to set render target 0 to NULL\n");
6430 return WINED3DERR_INVALIDCALL;
6432 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6433 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);
6434 return WINED3DERR_INVALIDCALL;
6437 /* If we are trying to set what we already have, don't bother */
6438 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6439 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6442 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6443 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6444 This->render_targets[RenderTargetIndex] = pRenderTarget;
6446 /* Render target 0 is special */
6447 if(RenderTargetIndex == 0) {
6448 /* Finally, reset the viewport as the MSDN states. */
6449 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6450 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6453 viewport.MaxZ = 1.0f;
6454 viewport.MinZ = 0.0f;
6455 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6456 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6457 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6461 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6463 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6464 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6466 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6471 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6473 HRESULT hr = WINED3D_OK;
6474 IWineD3DSurface *tmp;
6476 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6478 if (pNewZStencil == This->stencilBufferTarget) {
6479 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6481 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6482 * depending on the renter target implementation being used.
6483 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6484 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6485 * stencil buffer and incure an extra memory overhead
6486 ******************************************************/
6488 tmp = This->stencilBufferTarget;
6489 This->stencilBufferTarget = pNewZStencil;
6490 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6491 /* should we be calling the parent or the wined3d surface? */
6492 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6493 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6496 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6497 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6499 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6507 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6508 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6510 /* TODO: the use of Impl is deprecated. */
6511 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6512 WINED3DLOCKED_RECT lockedRect;
6514 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6516 /* some basic validation checks */
6517 if(This->cursorTexture) {
6518 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6520 glDeleteTextures(1, &This->cursorTexture);
6522 This->cursorTexture = 0;
6525 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6526 This->haveHardwareCursor = TRUE;
6528 This->haveHardwareCursor = FALSE;
6531 WINED3DLOCKED_RECT rect;
6533 /* MSDN: Cursor must be A8R8G8B8 */
6534 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6535 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6536 return WINED3DERR_INVALIDCALL;
6539 /* MSDN: Cursor must be smaller than the display mode */
6540 if(pSur->currentDesc.Width > This->ddraw_width ||
6541 pSur->currentDesc.Height > This->ddraw_height) {
6542 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);
6543 return WINED3DERR_INVALIDCALL;
6546 if (!This->haveHardwareCursor) {
6547 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6549 /* Do not store the surface's pointer because the application may
6550 * release it after setting the cursor image. Windows doesn't
6551 * addref the set surface, so we can't do this either without
6552 * creating circular refcount dependencies. Copy out the gl texture
6555 This->cursorWidth = pSur->currentDesc.Width;
6556 This->cursorHeight = pSur->currentDesc.Height;
6557 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6559 const GlPixelFormatDesc *glDesc;
6560 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6561 char *mem, *bits = (char *)rect.pBits;
6562 GLint intfmt = glDesc->glInternal;
6563 GLint format = glDesc->glFormat;
6564 GLint type = glDesc->glType;
6565 INT height = This->cursorHeight;
6566 INT width = This->cursorWidth;
6567 INT bpp = tableEntry->bpp;
6570 /* Reformat the texture memory (pitch and width can be
6572 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6573 for(i = 0; i < height; i++)
6574 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6575 IWineD3DSurface_UnlockRect(pCursorBitmap);
6578 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6579 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6580 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6583 /* Make sure that a proper texture unit is selected */
6584 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6585 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6586 checkGLcall("glActiveTextureARB");
6588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6589 /* Create a new cursor texture */
6590 glGenTextures(1, &This->cursorTexture);
6591 checkGLcall("glGenTextures");
6592 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6593 checkGLcall("glBindTexture");
6594 /* Copy the bitmap memory into the cursor texture */
6595 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6596 HeapFree(GetProcessHeap(), 0, mem);
6597 checkGLcall("glTexImage2D");
6599 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6600 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6601 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6608 FIXME("A cursor texture was not returned.\n");
6609 This->cursorTexture = 0;
6614 /* Draw a hardware cursor */
6615 ICONINFO cursorInfo;
6617 /* Create and clear maskBits because it is not needed for
6618 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6620 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6621 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6622 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6623 WINED3DLOCK_NO_DIRTY_UPDATE |
6624 WINED3DLOCK_READONLY
6626 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6627 pSur->currentDesc.Height);
6629 cursorInfo.fIcon = FALSE;
6630 cursorInfo.xHotspot = XHotSpot;
6631 cursorInfo.yHotspot = YHotSpot;
6632 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6633 pSur->currentDesc.Height, 1,
6635 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6636 pSur->currentDesc.Height, 1,
6637 32, lockedRect.pBits);
6638 IWineD3DSurface_UnlockRect(pCursorBitmap);
6639 /* Create our cursor and clean up. */
6640 cursor = CreateIconIndirect(&cursorInfo);
6642 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6643 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6644 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6645 This->hardwareCursor = cursor;
6646 HeapFree(GetProcessHeap(), 0, maskBits);
6650 This->xHotSpot = XHotSpot;
6651 This->yHotSpot = YHotSpot;
6655 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6657 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6659 This->xScreenSpace = XScreenSpace;
6660 This->yScreenSpace = YScreenSpace;
6666 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6668 BOOL oldVisible = This->bCursorVisible;
6671 TRACE("(%p) : visible(%d)\n", This, bShow);
6674 * When ShowCursor is first called it should make the cursor appear at the OS's last
6675 * known cursor position. Because of this, some applications just repetitively call
6676 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6679 This->xScreenSpace = pt.x;
6680 This->yScreenSpace = pt.y;
6682 if (This->haveHardwareCursor) {
6683 This->bCursorVisible = bShow;
6685 SetCursor(This->hardwareCursor);
6691 if (This->cursorTexture)
6692 This->bCursorVisible = bShow;
6698 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6700 IWineD3DResourceImpl *resource;
6701 TRACE("(%p) : state (%u)\n", This, This->state);
6703 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6704 switch (This->state) {
6707 case WINED3DERR_DEVICELOST:
6709 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6710 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6711 return WINED3DERR_DEVICENOTRESET;
6713 return WINED3DERR_DEVICELOST;
6715 case WINED3DERR_DRIVERINTERNALERROR:
6716 return WINED3DERR_DRIVERINTERNALERROR;
6720 return WINED3DERR_DRIVERINTERNALERROR;
6724 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6726 /** FIXME: Resource tracking needs to be done,
6727 * The closes we can do to this is set the priorities of all managed textures low
6728 * and then reset them.
6729 ***********************************************************/
6730 FIXME("(%p) : stub\n", This);
6734 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6735 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6737 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6738 if(surface->Flags & SFLAG_DIBSECTION) {
6739 /* Release the DC */
6740 SelectObject(surface->hDC, surface->dib.holdbitmap);
6741 DeleteDC(surface->hDC);
6742 /* Release the DIB section */
6743 DeleteObject(surface->dib.DIBsection);
6744 surface->dib.bitmap_data = NULL;
6745 surface->resource.allocatedMemory = NULL;
6746 surface->Flags &= ~SFLAG_DIBSECTION;
6748 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6749 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6750 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6751 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6752 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6754 surface->pow2Width = surface->pow2Height = 1;
6755 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6756 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6758 if(surface->glDescription.textureName) {
6759 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6761 glDeleteTextures(1, &surface->glDescription.textureName);
6763 surface->glDescription.textureName = 0;
6764 surface->Flags &= ~SFLAG_CLIENT;
6766 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6767 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6768 surface->Flags |= SFLAG_NONPOW2;
6770 surface->Flags &= ~SFLAG_NONPOW2;
6772 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6773 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6776 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6778 IWineD3DSwapChainImpl *swapchain;
6780 BOOL DisplayModeChanged = FALSE;
6781 WINED3DDISPLAYMODE mode;
6782 TRACE("(%p)\n", This);
6784 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6786 ERR("Failed to get the first implicit swapchain\n");
6790 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6791 * on an existing gl context, so there's no real need for recreation.
6793 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6795 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6797 TRACE("New params:\n");
6798 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6799 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6800 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6801 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6802 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6803 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6804 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6805 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6806 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6807 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6808 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6809 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6810 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6812 /* No special treatment of these parameters. Just store them */
6813 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6814 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6815 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6816 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6818 /* What to do about these? */
6819 if(pPresentationParameters->BackBufferCount != 0 &&
6820 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6821 ERR("Cannot change the back buffer count yet\n");
6823 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6824 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6825 ERR("Cannot change the back buffer format yet\n");
6827 if(pPresentationParameters->hDeviceWindow != NULL &&
6828 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6829 ERR("Cannot change the device window yet\n");
6831 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6832 ERR("What do do about a changed auto depth stencil parameter?\n");
6835 if(pPresentationParameters->Windowed) {
6836 mode.Width = swapchain->orig_width;
6837 mode.Height = swapchain->orig_height;
6838 mode.RefreshRate = 0;
6839 mode.Format = swapchain->presentParms.BackBufferFormat;
6841 mode.Width = pPresentationParameters->BackBufferWidth;
6842 mode.Height = pPresentationParameters->BackBufferHeight;
6843 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6844 mode.Format = swapchain->presentParms.BackBufferFormat;
6847 /* Should Width == 800 && Height == 0 set 800x600? */
6848 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6849 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6850 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6857 vp.Width = pPresentationParameters->BackBufferWidth;
6858 vp.Height = pPresentationParameters->BackBufferHeight;
6862 if(!pPresentationParameters->Windowed) {
6863 DisplayModeChanged = TRUE;
6865 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6866 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6868 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6869 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6870 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6873 /* Now set the new viewport */
6874 IWineD3DDevice_SetViewport(iface, &vp);
6877 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6878 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6879 DisplayModeChanged) {
6881 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6882 if(!pPresentationParameters->Windowed) {
6883 IWineD3DDevice_SetFullscreen(iface, TRUE);
6886 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6888 /* Switching out of fullscreen mode? First set the original res, then change the window */
6889 if(pPresentationParameters->Windowed) {
6890 IWineD3DDevice_SetFullscreen(iface, FALSE);
6892 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6895 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6899 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6901 /** FIXME: always true at the moment **/
6902 if(!bEnableDialogs) {
6903 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6909 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6911 TRACE("(%p) : pParameters %p\n", This, pParameters);
6913 *pParameters = This->createParms;
6917 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6918 IWineD3DSwapChain *swapchain;
6919 HRESULT hrc = WINED3D_OK;
6921 TRACE("Relaying to swapchain\n");
6923 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6924 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6925 IWineD3DSwapChain_Release(swapchain);
6930 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6931 IWineD3DSwapChain *swapchain;
6932 HRESULT hrc = WINED3D_OK;
6934 TRACE("Relaying to swapchain\n");
6936 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6937 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6938 IWineD3DSwapChain_Release(swapchain);
6944 /** ********************************************************
6945 * Notification functions
6946 ** ********************************************************/
6947 /** This function must be called in the release of a resource when ref == 0,
6948 * the contents of resource must still be correct,
6949 * any handels to other resource held by the caller must be closed
6950 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6951 *****************************************************/
6952 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6955 TRACE("(%p) : Adding Resource %p\n", This, resource);
6956 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6959 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6962 TRACE("(%p) : Removing resource %p\n", This, resource);
6964 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6968 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6972 TRACE("(%p) : resource %p\n", This, resource);
6973 switch(IWineD3DResource_GetType(resource)){
6974 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6975 case WINED3DRTYPE_SURFACE: {
6978 /* Cleanup any FBO attachments if d3d is enabled */
6979 if(This->d3d_initialized) {
6980 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6981 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6983 TRACE("Last active render target destroyed\n");
6984 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6985 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6986 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6987 * and the lastActiveRenderTarget member shouldn't matter
6990 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6991 TRACE("Activating primary back buffer\n");
6992 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6993 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6994 /* Single buffering environment */
6995 TRACE("Activating primary front buffer\n");
6996 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6998 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6999 /* Implicit render target destroyed, that means the device is being destroyed
7000 * whatever we set here, it shouldn't matter
7002 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7005 /* May happen during ddraw uninitialization */
7006 TRACE("Render target set, but swapchain does not exist!\n");
7007 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7011 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7012 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7013 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7014 set_render_target_fbo(iface, i, NULL);
7015 This->fbo_color_attachments[i] = NULL;
7018 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7019 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7020 set_depth_stencil_fbo(iface, NULL);
7021 This->fbo_depth_attachment = NULL;
7027 case WINED3DRTYPE_TEXTURE:
7028 case WINED3DRTYPE_CUBETEXTURE:
7029 case WINED3DRTYPE_VOLUMETEXTURE:
7030 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7031 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7032 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7033 This->stateBlock->textures[counter] = NULL;
7035 if (This->updateStateBlock != This->stateBlock ){
7036 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7037 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7038 This->updateStateBlock->textures[counter] = NULL;
7043 case WINED3DRTYPE_VOLUME:
7044 /* TODO: nothing really? */
7046 case WINED3DRTYPE_VERTEXBUFFER:
7047 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7050 TRACE("Cleaning up stream pointers\n");
7052 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7053 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7054 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7056 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7057 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7058 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7059 This->updateStateBlock->streamSource[streamNumber] = 0;
7060 /* Set changed flag? */
7063 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) */
7064 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7065 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7066 This->stateBlock->streamSource[streamNumber] = 0;
7069 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7070 else { /* This shouldn't happen */
7071 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7078 case WINED3DRTYPE_INDEXBUFFER:
7079 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7080 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7081 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7082 This->updateStateBlock->pIndexData = NULL;
7085 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7086 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7087 This->stateBlock->pIndexData = NULL;
7093 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7098 /* Remove the resoruce from the resourceStore */
7099 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7101 TRACE("Resource released\n");
7105 /**********************************************************
7106 * IWineD3DDevice VTbl follows
7107 **********************************************************/
7109 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7111 /*** IUnknown methods ***/
7112 IWineD3DDeviceImpl_QueryInterface,
7113 IWineD3DDeviceImpl_AddRef,
7114 IWineD3DDeviceImpl_Release,
7115 /*** IWineD3DDevice methods ***/
7116 IWineD3DDeviceImpl_GetParent,
7117 /*** Creation methods**/
7118 IWineD3DDeviceImpl_CreateVertexBuffer,
7119 IWineD3DDeviceImpl_CreateIndexBuffer,
7120 IWineD3DDeviceImpl_CreateStateBlock,
7121 IWineD3DDeviceImpl_CreateSurface,
7122 IWineD3DDeviceImpl_CreateTexture,
7123 IWineD3DDeviceImpl_CreateVolumeTexture,
7124 IWineD3DDeviceImpl_CreateVolume,
7125 IWineD3DDeviceImpl_CreateCubeTexture,
7126 IWineD3DDeviceImpl_CreateQuery,
7127 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7128 IWineD3DDeviceImpl_CreateVertexDeclaration,
7129 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7130 IWineD3DDeviceImpl_CreateVertexShader,
7131 IWineD3DDeviceImpl_CreatePixelShader,
7132 IWineD3DDeviceImpl_CreatePalette,
7133 /*** Odd functions **/
7134 IWineD3DDeviceImpl_Init3D,
7135 IWineD3DDeviceImpl_Uninit3D,
7136 IWineD3DDeviceImpl_SetFullscreen,
7137 IWineD3DDeviceImpl_SetMultithreaded,
7138 IWineD3DDeviceImpl_EvictManagedResources,
7139 IWineD3DDeviceImpl_GetAvailableTextureMem,
7140 IWineD3DDeviceImpl_GetBackBuffer,
7141 IWineD3DDeviceImpl_GetCreationParameters,
7142 IWineD3DDeviceImpl_GetDeviceCaps,
7143 IWineD3DDeviceImpl_GetDirect3D,
7144 IWineD3DDeviceImpl_GetDisplayMode,
7145 IWineD3DDeviceImpl_SetDisplayMode,
7146 IWineD3DDeviceImpl_GetHWND,
7147 IWineD3DDeviceImpl_SetHWND,
7148 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7149 IWineD3DDeviceImpl_GetRasterStatus,
7150 IWineD3DDeviceImpl_GetSwapChain,
7151 IWineD3DDeviceImpl_Reset,
7152 IWineD3DDeviceImpl_SetDialogBoxMode,
7153 IWineD3DDeviceImpl_SetCursorProperties,
7154 IWineD3DDeviceImpl_SetCursorPosition,
7155 IWineD3DDeviceImpl_ShowCursor,
7156 IWineD3DDeviceImpl_TestCooperativeLevel,
7157 /*** Getters and setters **/
7158 IWineD3DDeviceImpl_SetClipPlane,
7159 IWineD3DDeviceImpl_GetClipPlane,
7160 IWineD3DDeviceImpl_SetClipStatus,
7161 IWineD3DDeviceImpl_GetClipStatus,
7162 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7163 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7164 IWineD3DDeviceImpl_SetDepthStencilSurface,
7165 IWineD3DDeviceImpl_GetDepthStencilSurface,
7166 IWineD3DDeviceImpl_SetFVF,
7167 IWineD3DDeviceImpl_GetFVF,
7168 IWineD3DDeviceImpl_SetGammaRamp,
7169 IWineD3DDeviceImpl_GetGammaRamp,
7170 IWineD3DDeviceImpl_SetIndices,
7171 IWineD3DDeviceImpl_GetIndices,
7172 IWineD3DDeviceImpl_SetBaseVertexIndex,
7173 IWineD3DDeviceImpl_GetBaseVertexIndex,
7174 IWineD3DDeviceImpl_SetLight,
7175 IWineD3DDeviceImpl_GetLight,
7176 IWineD3DDeviceImpl_SetLightEnable,
7177 IWineD3DDeviceImpl_GetLightEnable,
7178 IWineD3DDeviceImpl_SetMaterial,
7179 IWineD3DDeviceImpl_GetMaterial,
7180 IWineD3DDeviceImpl_SetNPatchMode,
7181 IWineD3DDeviceImpl_GetNPatchMode,
7182 IWineD3DDeviceImpl_SetPaletteEntries,
7183 IWineD3DDeviceImpl_GetPaletteEntries,
7184 IWineD3DDeviceImpl_SetPixelShader,
7185 IWineD3DDeviceImpl_GetPixelShader,
7186 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7187 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7188 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7189 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7190 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7191 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7192 IWineD3DDeviceImpl_SetRenderState,
7193 IWineD3DDeviceImpl_GetRenderState,
7194 IWineD3DDeviceImpl_SetRenderTarget,
7195 IWineD3DDeviceImpl_GetRenderTarget,
7196 IWineD3DDeviceImpl_SetFrontBackBuffers,
7197 IWineD3DDeviceImpl_SetSamplerState,
7198 IWineD3DDeviceImpl_GetSamplerState,
7199 IWineD3DDeviceImpl_SetScissorRect,
7200 IWineD3DDeviceImpl_GetScissorRect,
7201 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7202 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7203 IWineD3DDeviceImpl_SetStreamSource,
7204 IWineD3DDeviceImpl_GetStreamSource,
7205 IWineD3DDeviceImpl_SetStreamSourceFreq,
7206 IWineD3DDeviceImpl_GetStreamSourceFreq,
7207 IWineD3DDeviceImpl_SetTexture,
7208 IWineD3DDeviceImpl_GetTexture,
7209 IWineD3DDeviceImpl_SetTextureStageState,
7210 IWineD3DDeviceImpl_GetTextureStageState,
7211 IWineD3DDeviceImpl_SetTransform,
7212 IWineD3DDeviceImpl_GetTransform,
7213 IWineD3DDeviceImpl_SetVertexDeclaration,
7214 IWineD3DDeviceImpl_GetVertexDeclaration,
7215 IWineD3DDeviceImpl_SetVertexShader,
7216 IWineD3DDeviceImpl_GetVertexShader,
7217 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7218 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7219 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7220 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7221 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7222 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7223 IWineD3DDeviceImpl_SetViewport,
7224 IWineD3DDeviceImpl_GetViewport,
7225 IWineD3DDeviceImpl_MultiplyTransform,
7226 IWineD3DDeviceImpl_ValidateDevice,
7227 IWineD3DDeviceImpl_ProcessVertices,
7228 /*** State block ***/
7229 IWineD3DDeviceImpl_BeginStateBlock,
7230 IWineD3DDeviceImpl_EndStateBlock,
7231 /*** Scene management ***/
7232 IWineD3DDeviceImpl_BeginScene,
7233 IWineD3DDeviceImpl_EndScene,
7234 IWineD3DDeviceImpl_Present,
7235 IWineD3DDeviceImpl_Clear,
7237 IWineD3DDeviceImpl_DrawPrimitive,
7238 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7239 IWineD3DDeviceImpl_DrawPrimitiveUP,
7240 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7241 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7242 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7243 IWineD3DDeviceImpl_DrawRectPatch,
7244 IWineD3DDeviceImpl_DrawTriPatch,
7245 IWineD3DDeviceImpl_DeletePatch,
7246 IWineD3DDeviceImpl_ColorFill,
7247 IWineD3DDeviceImpl_UpdateTexture,
7248 IWineD3DDeviceImpl_UpdateSurface,
7249 IWineD3DDeviceImpl_GetFrontBufferData,
7250 /*** object tracking ***/
7251 IWineD3DDeviceImpl_ResourceReleased
7255 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7256 WINED3DRS_ALPHABLENDENABLE ,
7257 WINED3DRS_ALPHAFUNC ,
7258 WINED3DRS_ALPHAREF ,
7259 WINED3DRS_ALPHATESTENABLE ,
7261 WINED3DRS_COLORWRITEENABLE ,
7262 WINED3DRS_DESTBLEND ,
7263 WINED3DRS_DITHERENABLE ,
7264 WINED3DRS_FILLMODE ,
7265 WINED3DRS_FOGDENSITY ,
7267 WINED3DRS_FOGSTART ,
7268 WINED3DRS_LASTPIXEL ,
7269 WINED3DRS_SHADEMODE ,
7270 WINED3DRS_SRCBLEND ,
7271 WINED3DRS_STENCILENABLE ,
7272 WINED3DRS_STENCILFAIL ,
7273 WINED3DRS_STENCILFUNC ,
7274 WINED3DRS_STENCILMASK ,
7275 WINED3DRS_STENCILPASS ,
7276 WINED3DRS_STENCILREF ,
7277 WINED3DRS_STENCILWRITEMASK ,
7278 WINED3DRS_STENCILZFAIL ,
7279 WINED3DRS_TEXTUREFACTOR ,
7290 WINED3DRS_ZWRITEENABLE
7293 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7294 WINED3DTSS_ADDRESSW ,
7295 WINED3DTSS_ALPHAARG0 ,
7296 WINED3DTSS_ALPHAARG1 ,
7297 WINED3DTSS_ALPHAARG2 ,
7298 WINED3DTSS_ALPHAOP ,
7299 WINED3DTSS_BUMPENVLOFFSET ,
7300 WINED3DTSS_BUMPENVLSCALE ,
7301 WINED3DTSS_BUMPENVMAT00 ,
7302 WINED3DTSS_BUMPENVMAT01 ,
7303 WINED3DTSS_BUMPENVMAT10 ,
7304 WINED3DTSS_BUMPENVMAT11 ,
7305 WINED3DTSS_COLORARG0 ,
7306 WINED3DTSS_COLORARG1 ,
7307 WINED3DTSS_COLORARG2 ,
7308 WINED3DTSS_COLOROP ,
7309 WINED3DTSS_RESULTARG ,
7310 WINED3DTSS_TEXCOORDINDEX ,
7311 WINED3DTSS_TEXTURETRANSFORMFLAGS
7314 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7315 WINED3DSAMP_ADDRESSU ,
7316 WINED3DSAMP_ADDRESSV ,
7317 WINED3DSAMP_ADDRESSW ,
7318 WINED3DSAMP_BORDERCOLOR ,
7319 WINED3DSAMP_MAGFILTER ,
7320 WINED3DSAMP_MINFILTER ,
7321 WINED3DSAMP_MIPFILTER ,
7322 WINED3DSAMP_MIPMAPLODBIAS ,
7323 WINED3DSAMP_MAXMIPLEVEL ,
7324 WINED3DSAMP_MAXANISOTROPY ,
7325 WINED3DSAMP_SRGBTEXTURE ,
7326 WINED3DSAMP_ELEMENTINDEX
7329 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7331 WINED3DRS_AMBIENTMATERIALSOURCE ,
7332 WINED3DRS_CLIPPING ,
7333 WINED3DRS_CLIPPLANEENABLE ,
7334 WINED3DRS_COLORVERTEX ,
7335 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7336 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7337 WINED3DRS_FOGDENSITY ,
7339 WINED3DRS_FOGSTART ,
7340 WINED3DRS_FOGTABLEMODE ,
7341 WINED3DRS_FOGVERTEXMODE ,
7342 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7343 WINED3DRS_LIGHTING ,
7344 WINED3DRS_LOCALVIEWER ,
7345 WINED3DRS_MULTISAMPLEANTIALIAS ,
7346 WINED3DRS_MULTISAMPLEMASK ,
7347 WINED3DRS_NORMALIZENORMALS ,
7348 WINED3DRS_PATCHEDGESTYLE ,
7349 WINED3DRS_POINTSCALE_A ,
7350 WINED3DRS_POINTSCALE_B ,
7351 WINED3DRS_POINTSCALE_C ,
7352 WINED3DRS_POINTSCALEENABLE ,
7353 WINED3DRS_POINTSIZE ,
7354 WINED3DRS_POINTSIZE_MAX ,
7355 WINED3DRS_POINTSIZE_MIN ,
7356 WINED3DRS_POINTSPRITEENABLE ,
7357 WINED3DRS_RANGEFOGENABLE ,
7358 WINED3DRS_SPECULARMATERIALSOURCE ,
7359 WINED3DRS_TWEENFACTOR ,
7360 WINED3DRS_VERTEXBLEND ,
7361 WINED3DRS_CULLMODE ,
7365 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7366 WINED3DTSS_TEXCOORDINDEX ,
7367 WINED3DTSS_TEXTURETRANSFORMFLAGS
7370 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7371 WINED3DSAMP_DMAPOFFSET
7374 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7375 DWORD rep = StateTable[state].representative;
7379 WineD3DContext *context;
7382 for(i = 0; i < This->numContexts; i++) {
7383 context = This->contexts[i];
7384 if(isStateDirty(context, rep)) continue;
7386 context->dirtyArray[context->numDirtyEntries++] = rep;
7389 context->isStateDirty[idx] |= (1 << shift);
7393 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7394 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7395 /* The drawable size of a pbuffer render target is the current pbuffer size
7397 *width = dev->pbufferWidth;
7398 *height = dev->pbufferHeight;
7401 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7402 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7404 *width = This->pow2Width;
7405 *height = This->pow2Height;
7408 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7409 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7410 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7411 * current context's drawable, which is the size of the back buffer of the swapchain
7412 * the active context belongs to. The back buffer of the swapchain is stored as the
7413 * surface the context belongs to.
7415 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7416 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;