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;
1405 WINED3DDISPLAYMODE Mode;
1406 const StaticPixelFormatDesc *formatDesc;
1408 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1410 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1411 * does a device hold a reference to a swap chain giving them a lifetime of the device
1412 * or does the swap chain notify the device of its destruction.
1413 *******************************/
1415 /* Check the params */
1416 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1417 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1418 return WINED3DERR_INVALIDCALL;
1419 } else if (pPresentationParameters->BackBufferCount > 1) {
1420 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");
1423 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1425 /*********************
1426 * Lookup the window Handle and the relating X window handle
1427 ********************/
1429 /* Setup hwnd we are using, plus which display this equates to */
1430 object->win_handle = pPresentationParameters->hDeviceWindow;
1431 if (!object->win_handle) {
1432 object->win_handle = This->createParms.hFocusWindow;
1434 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1436 hDc = GetDC(object->win_handle);
1437 TRACE("Using hDc %p\n", hDc);
1440 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1441 return WINED3DERR_NOTAVAILABLE;
1444 /* Get info on the current display setup */
1445 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1446 object->orig_width = Mode.Width;
1447 object->orig_height = Mode.Height;
1448 object->orig_fmt = Mode.Format;
1449 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1451 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1452 * then the corresponding dimension of the client area of the hDeviceWindow
1453 * (or the focus window, if hDeviceWindow is NULL) is taken.
1454 **********************/
1456 if (pPresentationParameters->Windowed &&
1457 ((pPresentationParameters->BackBufferWidth == 0) ||
1458 (pPresentationParameters->BackBufferHeight == 0) ||
1459 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1462 GetClientRect(object->win_handle, &Rect);
1464 if (pPresentationParameters->BackBufferWidth == 0) {
1465 pPresentationParameters->BackBufferWidth = Rect.right;
1466 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1468 if (pPresentationParameters->BackBufferHeight == 0) {
1469 pPresentationParameters->BackBufferHeight = Rect.bottom;
1470 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1472 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1473 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1474 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1478 /* Put the correct figures in the presentation parameters */
1479 TRACE("Copying across presentation parameters\n");
1480 object->presentParms = *pPresentationParameters;
1482 TRACE("calling rendertarget CB\n");
1483 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1485 object->presentParms.BackBufferWidth,
1486 object->presentParms.BackBufferHeight,
1487 object->presentParms.BackBufferFormat,
1488 object->presentParms.MultiSampleType,
1489 object->presentParms.MultiSampleQuality,
1490 TRUE /* Lockable */,
1491 &object->frontBuffer,
1492 NULL /* pShared (always null)*/);
1493 if (object->frontBuffer != NULL) {
1494 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1495 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1497 ERR("Failed to create the front buffer\n");
1501 /*********************
1502 * Windowed / Fullscreen
1503 *******************/
1506 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1507 * so we should really check to see if there is a fullscreen swapchain already
1508 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1509 **************************************/
1511 if (!pPresentationParameters->Windowed) {
1512 WINED3DDISPLAYMODE mode;
1515 /* Change the display settings */
1516 mode.Width = pPresentationParameters->BackBufferWidth;
1517 mode.Height = pPresentationParameters->BackBufferHeight;
1518 mode.Format = pPresentationParameters->BackBufferFormat;
1519 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1521 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1522 displaymode_set = TRUE;
1523 IWineD3DDevice_SetFullscreen(iface, TRUE);
1527 * Create an opengl context for the display visual
1528 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1529 * use different properties after that point in time. FIXME: How to handle when requested format
1530 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1531 * it chooses is identical to the one already being used!
1532 **********************************/
1533 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1535 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1536 if(!object->context)
1537 return E_OUTOFMEMORY;
1538 object->num_contexts = 1;
1540 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1541 if (!object->context[0]) {
1542 ERR("Failed to create a new context\n");
1543 hr = WINED3DERR_NOTAVAILABLE;
1546 TRACE("Context created (HWND=%p, glContext=%p)\n",
1547 object->win_handle, object->context[0]->glCtx);
1550 /*********************
1551 * Create the back, front and stencil buffers
1552 *******************/
1553 if(object->presentParms.BackBufferCount > 0) {
1556 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1557 if(!object->backBuffer) {
1558 ERR("Out of memory\n");
1563 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1564 TRACE("calling rendertarget CB\n");
1565 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1567 object->presentParms.BackBufferWidth,
1568 object->presentParms.BackBufferHeight,
1569 object->presentParms.BackBufferFormat,
1570 object->presentParms.MultiSampleType,
1571 object->presentParms.MultiSampleQuality,
1572 TRUE /* Lockable */,
1573 &object->backBuffer[i],
1574 NULL /* pShared (always null)*/);
1575 if(hr == WINED3D_OK && object->backBuffer[i]) {
1576 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1578 ERR("Cannot create new back buffer\n");
1582 glDrawBuffer(GL_BACK);
1583 checkGLcall("glDrawBuffer(GL_BACK)");
1587 object->backBuffer = NULL;
1589 /* Single buffering - draw to front buffer */
1591 glDrawBuffer(GL_FRONT);
1592 checkGLcall("glDrawBuffer(GL_FRONT)");
1596 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1597 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1598 TRACE("Creating depth stencil buffer\n");
1599 if (This->auto_depth_stencil_buffer == NULL ) {
1600 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1602 object->presentParms.BackBufferWidth,
1603 object->presentParms.BackBufferHeight,
1604 object->presentParms.AutoDepthStencilFormat,
1605 object->presentParms.MultiSampleType,
1606 object->presentParms.MultiSampleQuality,
1607 FALSE /* FIXME: Discard */,
1608 &This->auto_depth_stencil_buffer,
1609 NULL /* pShared (always null)*/ );
1610 if (This->auto_depth_stencil_buffer != NULL)
1611 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1614 /** TODO: A check on width, height and multisample types
1615 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1616 ****************************/
1617 object->wantsDepthStencilBuffer = TRUE;
1619 object->wantsDepthStencilBuffer = FALSE;
1622 TRACE("Created swapchain %p\n", object);
1623 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1627 if (displaymode_set) {
1631 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1634 /* Change the display settings */
1635 memset(&devmode, 0, sizeof(devmode));
1636 devmode.dmSize = sizeof(devmode);
1637 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1638 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1639 devmode.dmPelsWidth = object->orig_width;
1640 devmode.dmPelsHeight = object->orig_height;
1641 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1644 if (object->backBuffer) {
1646 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1647 if(object->backBuffer[i]) {
1648 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1649 IUnknown_Release(bufferParent); /* once for the get parent */
1650 if (IUnknown_Release(bufferParent) > 0) {
1651 FIXME("(%p) Something's still holding the back buffer\n",This);
1655 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1656 object->backBuffer = NULL;
1658 if(object->context[0])
1659 DestroyContext(This, object->context[0]);
1660 if(object->frontBuffer) {
1661 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1662 IUnknown_Release(bufferParent); /* once for the get parent */
1663 if (IUnknown_Release(bufferParent) > 0) {
1664 FIXME("(%p) Something's still holding the front buffer\n",This);
1667 HeapFree(GetProcessHeap(), 0, object);
1671 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1672 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1674 TRACE("(%p)\n", This);
1676 return This->NumberOfSwapChains;
1679 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1681 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1683 if(iSwapChain < This->NumberOfSwapChains) {
1684 *pSwapChain = This->swapchains[iSwapChain];
1685 IWineD3DSwapChain_AddRef(*pSwapChain);
1686 TRACE("(%p) returning %p\n", This, *pSwapChain);
1689 TRACE("Swapchain out of range\n");
1691 return WINED3DERR_INVALIDCALL;
1696 * Vertex Declaration
1698 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1699 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1701 IWineD3DVertexDeclarationImpl *object = NULL;
1702 HRESULT hr = WINED3D_OK;
1704 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1705 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1707 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1709 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1714 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1716 unsigned int idx, idx2;
1717 unsigned int offset;
1718 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1719 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1720 BOOL has_blend_idx = has_blend &&
1721 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1722 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1723 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1724 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1725 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1726 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1727 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1729 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1730 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1732 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1733 WINED3DVERTEXELEMENT *elements = NULL;
1736 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1737 if (has_blend_idx) num_blends--;
1739 /* Compute declaration size */
1740 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1741 has_psize + has_diffuse + has_specular + num_textures + 1;
1743 /* convert the declaration */
1744 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1748 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1751 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1752 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1753 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1756 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1757 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1759 elements[idx].UsageIndex = 0;
1762 if (has_blend && (num_blends > 0)) {
1763 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1764 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1766 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1767 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1768 elements[idx].UsageIndex = 0;
1771 if (has_blend_idx) {
1772 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1773 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1774 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1775 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1776 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1778 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1779 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1780 elements[idx].UsageIndex = 0;
1784 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1785 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1786 elements[idx].UsageIndex = 0;
1790 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1791 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1792 elements[idx].UsageIndex = 0;
1796 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1797 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1798 elements[idx].UsageIndex = 0;
1802 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1803 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1804 elements[idx].UsageIndex = 1;
1807 for (idx2 = 0; idx2 < num_textures; idx2++) {
1808 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1809 switch (numcoords) {
1810 case WINED3DFVF_TEXTUREFORMAT1:
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1813 case WINED3DFVF_TEXTUREFORMAT2:
1814 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1816 case WINED3DFVF_TEXTUREFORMAT3:
1817 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1819 case WINED3DFVF_TEXTUREFORMAT4:
1820 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1823 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1824 elements[idx].UsageIndex = idx2;
1828 /* Now compute offsets, and initialize the rest of the fields */
1829 for (idx = 0, offset = 0; idx < size-1; idx++) {
1830 elements[idx].Stream = 0;
1831 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1832 elements[idx].Offset = offset;
1833 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1836 *ppVertexElements = elements;
1840 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1841 WINED3DVERTEXELEMENT* elements = NULL;
1845 size = ConvertFvfToDeclaration(Fvf, &elements);
1846 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1848 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1849 HeapFree(GetProcessHeap(), 0, elements);
1850 if (hr != S_OK) return hr;
1855 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1856 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1858 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1859 HRESULT hr = WINED3D_OK;
1860 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1861 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1863 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1865 if (vertex_declaration) {
1866 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1869 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1871 if (WINED3D_OK != hr) {
1872 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1873 IWineD3DVertexShader_Release(*ppVertexShader);
1874 return WINED3DERR_INVALIDCALL;
1880 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1882 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1883 HRESULT hr = WINED3D_OK;
1885 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1886 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1887 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1888 if (WINED3D_OK == hr) {
1889 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1891 WARN("(%p) : Failed to create pixel shader\n", This);
1897 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1899 IWineD3DPaletteImpl *object;
1901 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1903 /* Create the new object */
1904 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1906 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1907 return E_OUTOFMEMORY;
1910 object->lpVtbl = &IWineD3DPalette_Vtbl;
1912 object->Flags = Flags;
1913 object->parent = Parent;
1914 object->wineD3DDevice = This;
1915 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1917 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1920 HeapFree( GetProcessHeap(), 0, object);
1921 return E_OUTOFMEMORY;
1924 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1926 IWineD3DPalette_Release((IWineD3DPalette *) object);
1930 *Palette = (IWineD3DPalette *) object;
1935 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1939 HDC dcb = NULL, dcs = NULL;
1940 WINEDDCOLORKEY colorkey;
1942 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1945 GetObjectA(hbm, sizeof(BITMAP), &bm);
1946 dcb = CreateCompatibleDC(NULL);
1948 SelectObject(dcb, hbm);
1952 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1953 * couldn't be loaded
1955 memset(&bm, 0, sizeof(bm));
1960 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1961 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1962 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1964 ERR("Wine logo requested, but failed to create surface\n");
1969 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1970 if(FAILED(hr)) goto out;
1971 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1972 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1974 colorkey.dwColorSpaceLowValue = 0;
1975 colorkey.dwColorSpaceHighValue = 0;
1976 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1978 /* Fill the surface with a white color to show that wined3d is there */
1979 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1992 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1994 IWineD3DSwapChainImpl *swapchain;
1998 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1999 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2001 /* TODO: Test if OpenGL is compiled in and loaded */
2003 TRACE("(%p) : Creating stateblock\n", This);
2004 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2005 hr = IWineD3DDevice_CreateStateBlock(iface,
2007 (IWineD3DStateBlock **)&This->stateBlock,
2009 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2010 WARN("Failed to create stateblock\n");
2013 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2014 This->updateStateBlock = This->stateBlock;
2015 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2017 hr = allocate_shader_constants(This->updateStateBlock);
2018 if (WINED3D_OK != hr) {
2022 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2023 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2024 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2026 /* Initialize the texture unit mapping to a 1:1 mapping */
2027 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2028 if (state < GL_LIMITS(fragment_samplers)) {
2029 This->texUnitMap[state] = state;
2030 This->rev_tex_unit_map[state] = state;
2032 This->texUnitMap[state] = -1;
2033 This->rev_tex_unit_map[state] = -1;
2037 /* Setup the implicit swapchain */
2038 TRACE("Creating implicit swapchain\n");
2039 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2040 if (FAILED(hr) || !swapchain) {
2041 WARN("Failed to create implicit swapchain\n");
2045 This->NumberOfSwapChains = 1;
2046 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2047 if(!This->swapchains) {
2048 ERR("Out of memory!\n");
2051 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2053 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2054 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2055 This->render_targets[0] = swapchain->backBuffer[0];
2056 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2059 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2060 This->render_targets[0] = swapchain->frontBuffer;
2061 This->lastActiveRenderTarget = swapchain->frontBuffer;
2063 IWineD3DSurface_AddRef(This->render_targets[0]);
2064 This->activeContext = swapchain->context[0];
2065 This->lastThread = GetCurrentThreadId();
2067 /* Depth Stencil support */
2068 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2069 if (NULL != This->stencilBufferTarget) {
2070 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2073 /* Set up some starting GL setup */
2076 /* Setup all the devices defaults */
2077 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2079 IWineD3DImpl_CheckGraphicsMemory();
2082 { /* Set a default viewport */
2086 vp.Width = pPresentationParameters->BackBufferWidth;
2087 vp.Height = pPresentationParameters->BackBufferHeight;
2090 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2093 /* Initialize the current view state */
2094 This->view_ident = 1;
2095 This->contexts[0]->last_was_rhw = 0;
2096 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2097 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2099 switch(wined3d_settings.offscreen_rendering_mode) {
2102 This->offscreenBuffer = GL_BACK;
2105 case ORM_BACKBUFFER:
2107 if(GL_LIMITS(aux_buffers) > 0) {
2108 TRACE("Using auxilliary buffer for offscreen rendering\n");
2109 This->offscreenBuffer = GL_AUX0;
2111 TRACE("Using back buffer for offscreen rendering\n");
2112 This->offscreenBuffer = GL_BACK;
2117 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2120 /* Clear the screen */
2121 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2122 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2125 This->d3d_initialized = TRUE;
2127 if(wined3d_settings.logo) {
2128 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2133 HeapFree(GetProcessHeap(), 0, This->render_targets);
2134 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2135 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2136 HeapFree(GetProcessHeap(), 0, This->swapchains);
2137 This->NumberOfSwapChains = 0;
2139 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2141 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2142 if(This->stateBlock) {
2143 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2144 This->stateBlock = NULL;
2149 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2153 TRACE("(%p)\n", This);
2155 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2157 /* I don't think that the interface guarants that the device is destroyed from the same thread
2158 * it was created. Thus make sure a context is active for the glDelete* calls
2160 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2162 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2164 TRACE("Deleting high order patches\n");
2165 for(i = 0; i < PATCHMAP_SIZE; i++) {
2166 struct list *e1, *e2;
2167 struct WineD3DRectPatch *patch;
2168 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2169 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2170 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2174 /* Delete the palette conversion shader if it is around */
2175 if(This->paletteConversionShader) {
2176 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2177 This->paletteConversionShader = 0;
2180 /* Delete the pbuffer context if there is any */
2181 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2183 /* Delete the mouse cursor texture */
2184 if(This->cursorTexture) {
2186 glDeleteTextures(1, &This->cursorTexture);
2188 This->cursorTexture = 0;
2191 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2192 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2194 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2195 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2198 /* Release the update stateblock */
2199 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2200 if(This->updateStateBlock != This->stateBlock)
2201 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2203 This->updateStateBlock = NULL;
2205 { /* because were not doing proper internal refcounts releasing the primary state block
2206 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2207 to set this->stateBlock = NULL; first */
2208 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2209 This->stateBlock = NULL;
2211 /* Release the stateblock */
2212 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2213 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2217 /* Release the buffers (with sanity checks)*/
2218 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2219 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2220 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2221 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2223 This->stencilBufferTarget = NULL;
2225 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2226 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2227 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2229 TRACE("Setting rendertarget to NULL\n");
2230 This->render_targets[0] = NULL;
2232 if (This->auto_depth_stencil_buffer) {
2233 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2234 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2236 This->auto_depth_stencil_buffer = NULL;
2239 for(i=0; i < This->NumberOfSwapChains; i++) {
2240 TRACE("Releasing the implicit swapchain %d\n", i);
2241 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2242 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2246 HeapFree(GetProcessHeap(), 0, This->swapchains);
2247 This->swapchains = NULL;
2248 This->NumberOfSwapChains = 0;
2250 HeapFree(GetProcessHeap(), 0, This->render_targets);
2251 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2252 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2253 This->render_targets = NULL;
2254 This->fbo_color_attachments = NULL;
2255 This->draw_buffers = NULL;
2258 This->d3d_initialized = FALSE;
2262 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2264 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2266 /* Setup the window for fullscreen mode */
2267 if(fullscreen && !This->ddraw_fullscreen) {
2268 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2269 } else if(!fullscreen && This->ddraw_fullscreen) {
2270 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2273 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2274 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2275 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2278 This->ddraw_fullscreen = fullscreen;
2281 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2282 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2283 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2285 * There is no way to deactivate thread safety once it is enabled.
2287 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2290 /*For now just store the flag(needed in case of ddraw) */
2291 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2296 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2300 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2303 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2305 /* Resize the screen even without a window:
2306 * The app could have unset it with SetCooperativeLevel, but not called
2307 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2308 * but we don't have any hwnd
2311 memset(&devmode, 0, sizeof(devmode));
2312 devmode.dmSize = sizeof(devmode);
2313 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2314 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2315 devmode.dmPelsWidth = pMode->Width;
2316 devmode.dmPelsHeight = pMode->Height;
2318 devmode.dmDisplayFrequency = pMode->RefreshRate;
2319 if (pMode->RefreshRate != 0) {
2320 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2323 /* Only change the mode if necessary */
2324 if( (This->ddraw_width == pMode->Width) &&
2325 (This->ddraw_height == pMode->Height) &&
2326 (This->ddraw_format == pMode->Format) &&
2327 (pMode->RefreshRate == 0) ) {
2331 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2332 if (ret != DISP_CHANGE_SUCCESSFUL) {
2333 if(devmode.dmDisplayFrequency != 0) {
2334 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2335 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2336 devmode.dmDisplayFrequency = 0;
2337 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2339 if(ret != DISP_CHANGE_SUCCESSFUL) {
2340 return WINED3DERR_NOTAVAILABLE;
2344 /* Store the new values */
2345 This->ddraw_width = pMode->Width;
2346 This->ddraw_height = pMode->Height;
2347 This->ddraw_format = pMode->Format;
2349 /* Only do this with a window of course */
2350 if(This->ddraw_window)
2351 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2353 /* And finally clip mouse to our screen */
2354 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2355 ClipCursor(&clip_rc);
2360 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2362 *ppD3D= This->wineD3D;
2363 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2364 IWineD3D_AddRef(*ppD3D);
2368 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2371 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2372 (This->adapter->TextureRam/(1024*1024)),
2373 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2374 /* return simulated texture memory left */
2375 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2383 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2386 /* Update the current state block */
2387 This->updateStateBlock->changed.fvf = TRUE;
2389 if(This->updateStateBlock->fvf == fvf) {
2390 TRACE("Application is setting the old fvf over, nothing to do\n");
2394 This->updateStateBlock->fvf = fvf;
2395 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2401 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2404 *pfvf = This->stateBlock->fvf;
2409 * Get / Set Stream Source
2411 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2413 IWineD3DVertexBuffer *oldSrc;
2415 if (StreamNumber >= MAX_STREAMS) {
2416 WARN("Stream out of range %d\n", StreamNumber);
2417 return WINED3DERR_INVALIDCALL;
2420 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2421 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2423 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2425 if(oldSrc == pStreamData &&
2426 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2427 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2428 TRACE("Application is setting the old values over, nothing to do\n");
2432 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2434 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2435 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2438 /* Handle recording of state blocks */
2439 if (This->isRecordingState) {
2440 TRACE("Recording... not performing anything\n");
2441 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2442 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2446 /* Need to do a getParent and pass the reffs up */
2447 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2448 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2449 so for now, just count internally */
2450 if (pStreamData != NULL) {
2451 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2452 InterlockedIncrement(&vbImpl->bindCount);
2453 IWineD3DVertexBuffer_AddRef(pStreamData);
2455 if (oldSrc != NULL) {
2456 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2457 IWineD3DVertexBuffer_Release(oldSrc);
2460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2465 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2469 This->stateBlock->streamSource[StreamNumber],
2470 This->stateBlock->streamOffset[StreamNumber],
2471 This->stateBlock->streamStride[StreamNumber]);
2473 if (StreamNumber >= MAX_STREAMS) {
2474 WARN("Stream out of range %d\n", StreamNumber);
2475 return WINED3DERR_INVALIDCALL;
2477 *pStream = This->stateBlock->streamSource[StreamNumber];
2478 *pStride = This->stateBlock->streamStride[StreamNumber];
2480 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2483 if (*pStream != NULL) {
2484 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2489 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2491 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2492 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2494 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2495 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2497 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2498 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2500 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2501 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2508 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2512 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2514 TRACE("(%p) : returning %d\n", This, *Divider);
2520 * Get / Set & Multiply Transform
2522 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2525 /* Most of this routine, comments included copied from ddraw tree initially: */
2526 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2528 /* Handle recording of state blocks */
2529 if (This->isRecordingState) {
2530 TRACE("Recording... not performing anything\n");
2531 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2532 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2537 * If the new matrix is the same as the current one,
2538 * we cut off any further processing. this seems to be a reasonable
2539 * optimization because as was noticed, some apps (warcraft3 for example)
2540 * tend towards setting the same matrix repeatedly for some reason.
2542 * From here on we assume that the new matrix is different, wherever it matters.
2544 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2545 TRACE("The app is setting the same matrix over again\n");
2548 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2552 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2553 where ViewMat = Camera space, WorldMat = world space.
2555 In OpenGL, camera and world space is combined into GL_MODELVIEW
2556 matrix. The Projection matrix stay projection matrix.
2559 /* Capture the times we can just ignore the change for now */
2560 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2561 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2562 /* Handled by the state manager */
2565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2569 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2572 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2576 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2577 WINED3DMATRIX *mat = NULL;
2580 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2581 * below means it will be recorded in a state block change, but it
2582 * works regardless where it is recorded.
2583 * If this is found to be wrong, change to StateBlock.
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2586 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2588 if (State < HIGHEST_TRANSFORMSTATE)
2590 mat = &This->updateStateBlock->transforms[State];
2592 FIXME("Unhandled transform state!!\n");
2595 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2597 /* Apply change via set transform - will reapply to eg. lights this way */
2598 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2604 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2605 you can reference any indexes you want as long as that number max are enabled at any
2606 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2607 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2608 but when recording, just build a chain pretty much of commands to be replayed. */
2610 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2612 PLIGHTINFOEL *object = NULL;
2613 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2617 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2619 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2623 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2624 return WINED3DERR_INVALIDCALL;
2627 switch(pLight->Type) {
2628 case WINED3DLIGHT_POINT:
2629 case WINED3DLIGHT_SPOT:
2630 case WINED3DLIGHT_PARALLELPOINT:
2631 case WINED3DLIGHT_GLSPOT:
2632 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2635 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2636 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2637 return WINED3DERR_INVALIDCALL;
2641 case WINED3DLIGHT_DIRECTIONAL:
2642 /* Ignores attenuation */
2646 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2647 return WINED3DERR_INVALIDCALL;
2650 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2651 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2652 if(object->OriginalIndex == Index) break;
2657 TRACE("Adding new light\n");
2658 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2660 ERR("Out of memory error when allocating a light\n");
2661 return E_OUTOFMEMORY;
2663 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2664 object->glIndex = -1;
2665 object->OriginalIndex = Index;
2666 object->changed = TRUE;
2669 /* Initialize the object */
2670 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,
2671 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2672 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2673 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2674 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2675 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2676 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2678 /* Save away the information */
2679 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2681 switch (pLight->Type) {
2682 case WINED3DLIGHT_POINT:
2684 object->lightPosn[0] = pLight->Position.x;
2685 object->lightPosn[1] = pLight->Position.y;
2686 object->lightPosn[2] = pLight->Position.z;
2687 object->lightPosn[3] = 1.0f;
2688 object->cutoff = 180.0f;
2692 case WINED3DLIGHT_DIRECTIONAL:
2694 object->lightPosn[0] = -pLight->Direction.x;
2695 object->lightPosn[1] = -pLight->Direction.y;
2696 object->lightPosn[2] = -pLight->Direction.z;
2697 object->lightPosn[3] = 0.0;
2698 object->exponent = 0.0f;
2699 object->cutoff = 180.0f;
2702 case WINED3DLIGHT_SPOT:
2704 object->lightPosn[0] = pLight->Position.x;
2705 object->lightPosn[1] = pLight->Position.y;
2706 object->lightPosn[2] = pLight->Position.z;
2707 object->lightPosn[3] = 1.0;
2710 object->lightDirn[0] = pLight->Direction.x;
2711 object->lightDirn[1] = pLight->Direction.y;
2712 object->lightDirn[2] = pLight->Direction.z;
2713 object->lightDirn[3] = 1.0;
2716 * opengl-ish and d3d-ish spot lights use too different models for the
2717 * light "intensity" as a function of the angle towards the main light direction,
2718 * so we only can approximate very roughly.
2719 * however spot lights are rather rarely used in games (if ever used at all).
2720 * furthermore if still used, probably nobody pays attention to such details.
2722 if (pLight->Falloff == 0) {
2723 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2724 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2725 * will always be 1.0 for both of them, and we don't have to care for the
2726 * rest of the rather complex calculation
2728 object->exponent = 0;
2730 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2731 if (rho < 0.0001) rho = 0.0001f;
2732 object->exponent = -0.3/log(cos(rho/2));
2734 if (object->exponent > 128.0) {
2735 object->exponent = 128.0;
2737 object->cutoff = pLight->Phi*90/M_PI;
2743 FIXME("Unrecognized light type %d\n", pLight->Type);
2746 /* Update the live definitions if the light is currently assigned a glIndex */
2747 if (object->glIndex != -1 && !This->isRecordingState) {
2748 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2753 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2754 PLIGHTINFOEL *lightInfo = NULL;
2755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2756 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2758 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2760 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2761 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2762 if(lightInfo->OriginalIndex == Index) break;
2766 if (lightInfo == NULL) {
2767 TRACE("Light information requested but light not defined\n");
2768 return WINED3DERR_INVALIDCALL;
2771 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2776 * Get / Set Light Enable
2777 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2779 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2780 PLIGHTINFOEL *lightInfo = NULL;
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2782 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2784 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2786 /* Tests show true = 128...not clear why */
2787 Enable = Enable? 128: 0;
2789 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2790 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2791 if(lightInfo->OriginalIndex == Index) break;
2794 TRACE("Found light: %p\n", lightInfo);
2796 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2797 if (lightInfo == NULL) {
2799 TRACE("Light enabled requested but light not defined, so defining one!\n");
2800 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2802 /* Search for it again! Should be fairly quick as near head of list */
2803 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2804 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2805 if(lightInfo->OriginalIndex == Index) break;
2808 if (lightInfo == NULL) {
2809 FIXME("Adding default lights has failed dismally\n");
2810 return WINED3DERR_INVALIDCALL;
2814 lightInfo->enabledChanged = TRUE;
2816 if(lightInfo->glIndex != -1) {
2817 if(!This->isRecordingState) {
2818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2821 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2822 lightInfo->glIndex = -1;
2824 TRACE("Light already disabled, nothing to do\n");
2826 lightInfo->enabled = FALSE;
2828 lightInfo->enabled = TRUE;
2829 if (lightInfo->glIndex != -1) {
2831 TRACE("Nothing to do as light was enabled\n");
2834 /* Find a free gl light */
2835 for(i = 0; i < This->maxConcurrentLights; i++) {
2836 if(This->stateBlock->activeLights[i] == NULL) {
2837 This->stateBlock->activeLights[i] = lightInfo;
2838 lightInfo->glIndex = i;
2842 if(lightInfo->glIndex == -1) {
2843 /* Our tests show that Windows returns D3D_OK in this situation, even with
2844 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2845 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2846 * as well for those lights.
2848 * TODO: Test how this affects rendering
2850 FIXME("Too many concurrently active lights\n");
2854 /* i == lightInfo->glIndex */
2855 if(!This->isRecordingState) {
2856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2864 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2866 PLIGHTINFOEL *lightInfo = NULL;
2867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2870 TRACE("(%p) : for idx(%d)\n", This, Index);
2872 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2873 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2874 if(lightInfo->OriginalIndex == Index) break;
2878 if (lightInfo == NULL) {
2879 TRACE("Light enabled state requested but light not defined\n");
2880 return WINED3DERR_INVALIDCALL;
2882 /* true is 128 according to SetLightEnable */
2883 *pEnable = lightInfo->enabled ? 128 : 0;
2888 * Get / Set Clip Planes
2890 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2892 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2894 /* Validate Index */
2895 if (Index >= GL_LIMITS(clipplanes)) {
2896 TRACE("Application has requested clipplane this device doesn't support\n");
2897 return WINED3DERR_INVALIDCALL;
2900 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2902 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2903 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2904 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2905 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2906 TRACE("Application is setting old values over, nothing to do\n");
2910 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2911 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2912 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2913 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2915 /* Handle recording of state blocks */
2916 if (This->isRecordingState) {
2917 TRACE("Recording... not performing anything\n");
2921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2926 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 TRACE("(%p) : for idx %d\n", This, Index);
2930 /* Validate Index */
2931 if (Index >= GL_LIMITS(clipplanes)) {
2932 TRACE("Application has requested clipplane this device doesn't support\n");
2933 return WINED3DERR_INVALIDCALL;
2936 pPlane[0] = This->stateBlock->clipplane[Index][0];
2937 pPlane[1] = This->stateBlock->clipplane[Index][1];
2938 pPlane[2] = This->stateBlock->clipplane[Index][2];
2939 pPlane[3] = This->stateBlock->clipplane[Index][3];
2944 * Get / Set Clip Plane Status
2945 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2947 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2949 FIXME("(%p) : stub\n", This);
2950 if (NULL == pClipStatus) {
2951 return WINED3DERR_INVALIDCALL;
2953 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2954 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2958 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2960 FIXME("(%p) : stub\n", This);
2961 if (NULL == pClipStatus) {
2962 return WINED3DERR_INVALIDCALL;
2964 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2965 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2970 * Get / Set Material
2972 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 This->updateStateBlock->changed.material = TRUE;
2976 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2978 /* Handle recording of state blocks */
2979 if (This->isRecordingState) {
2980 TRACE("Recording... not performing anything\n");
2984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2988 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2990 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2991 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2992 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2993 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2994 pMaterial->Ambient.b, pMaterial->Ambient.a);
2995 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2996 pMaterial->Specular.b, pMaterial->Specular.a);
2997 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2998 pMaterial->Emissive.b, pMaterial->Emissive.a);
2999 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3009 IWineD3DIndexBuffer *oldIdxs;
3011 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3012 oldIdxs = This->updateStateBlock->pIndexData;
3014 This->updateStateBlock->changed.indices = TRUE;
3015 This->updateStateBlock->pIndexData = pIndexData;
3017 /* Handle recording of state blocks */
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3020 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3021 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3025 if(oldIdxs != pIndexData) {
3026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3027 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3028 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3033 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 *ppIndexData = This->stateBlock->pIndexData;
3038 /* up ref count on ppindexdata */
3040 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3041 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3043 TRACE("(%p) No index data set\n", This);
3045 TRACE("Returning %p\n", *ppIndexData);
3050 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3051 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 TRACE("(%p)->(%d)\n", This, BaseIndex);
3055 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3056 TRACE("Application is setting the old value over, nothing to do\n");
3060 This->updateStateBlock->baseVertexIndex = BaseIndex;
3062 if (This->isRecordingState) {
3063 TRACE("Recording... not performing anything\n");
3066 /* The base vertex index affects the stream sources */
3067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3071 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3073 TRACE("(%p) : base_index %p\n", This, base_index);
3075 *base_index = This->stateBlock->baseVertexIndex;
3077 TRACE("Returning %u\n", *base_index);
3083 * Get / Set Viewports
3085 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 TRACE("(%p)\n", This);
3089 This->updateStateBlock->changed.viewport = TRUE;
3090 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3092 /* Handle recording of state blocks */
3093 if (This->isRecordingState) {
3094 TRACE("Recording... not performing anything\n");
3098 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3099 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3101 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3106 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 TRACE("(%p)\n", This);
3109 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3114 * Get / Set Render States
3115 * TODO: Verify against dx9 definitions
3117 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 DWORD oldValue = This->stateBlock->renderState[State];
3122 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3124 This->updateStateBlock->changed.renderState[State] = TRUE;
3125 This->updateStateBlock->renderState[State] = Value;
3127 /* Handle recording of state blocks */
3128 if (This->isRecordingState) {
3129 TRACE("Recording... not performing anything\n");
3133 /* Compared here and not before the assignment to allow proper stateblock recording */
3134 if(Value == oldValue) {
3135 TRACE("Application is setting the old value over, nothing to do\n");
3137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3143 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3146 *pValue = This->stateBlock->renderState[State];
3151 * Get / Set Sampler States
3152 * TODO: Verify against dx9 definitions
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3160 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3162 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3163 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3167 * SetSampler is designed to allow for more than the standard up to 8 textures
3168 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3169 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3171 * http://developer.nvidia.com/object/General_FAQ.html#t6
3173 * There are two new settings for GForce
3175 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3176 * and the texture one:
3177 * GL_MAX_TEXTURE_COORDS_ARB.
3178 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3181 oldValue = This->stateBlock->samplerState[Sampler][Type];
3182 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3183 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3185 /* Handle recording of state blocks */
3186 if (This->isRecordingState) {
3187 TRACE("Recording... not performing anything\n");
3191 if(oldValue == Value) {
3192 TRACE("Application is setting the old value over, nothing to do\n");
3196 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3201 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3204 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3205 This, Sampler, debug_d3dsamplerstate(Type), Type);
3207 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3208 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3211 *Value = This->stateBlock->samplerState[Sampler][Type];
3212 TRACE("(%p) : Returning %#x\n", This, *Value);
3217 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3220 This->updateStateBlock->changed.scissorRect = TRUE;
3221 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3222 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3225 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3227 if(This->isRecordingState) {
3228 TRACE("Recording... not performing anything\n");
3232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3237 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3241 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3247 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3249 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3251 This->updateStateBlock->vertexDecl = pDecl;
3252 This->updateStateBlock->changed.vertexDecl = TRUE;
3254 if (This->isRecordingState) {
3255 TRACE("Recording... not performing anything\n");
3257 } else if(pDecl == oldDecl) {
3258 /* Checked after the assignment to allow proper stateblock recording */
3259 TRACE("Application is setting the old declaration over, nothing to do\n");
3263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3267 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3270 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3272 *ppDecl = This->stateBlock->vertexDecl;
3273 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3277 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3281 This->updateStateBlock->vertexShader = pShader;
3282 This->updateStateBlock->changed.vertexShader = TRUE;
3284 if (This->isRecordingState) {
3285 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3286 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3287 TRACE("Recording... not performing anything\n");
3289 } else if(oldShader == pShader) {
3290 /* Checked here to allow proper stateblock recording */
3291 TRACE("App is setting the old shader over, nothing to do\n");
3295 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3296 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3297 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3304 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 if (NULL == ppShader) {
3308 return WINED3DERR_INVALIDCALL;
3310 *ppShader = This->stateBlock->vertexShader;
3311 if( NULL != *ppShader)
3312 IWineD3DVertexShader_AddRef(*ppShader);
3314 TRACE("(%p) : returning %p\n", This, *ppShader);
3318 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3319 IWineD3DDevice *iface,
3321 CONST BOOL *srcData,
3324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3325 int i, cnt = min(count, MAX_CONST_B - start);
3327 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3328 iface, srcData, start, count);
3330 if (srcData == NULL || cnt < 0)
3331 return WINED3DERR_INVALIDCALL;
3333 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3334 for (i = 0; i < cnt; i++)
3335 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3337 for (i = start; i < cnt + start; ++i) {
3338 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3341 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3346 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3347 IWineD3DDevice *iface,
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3353 int cnt = min(count, MAX_CONST_B - start);
3355 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3356 iface, dstData, start, count);
3358 if (dstData == NULL || cnt < 0)
3359 return WINED3DERR_INVALIDCALL;
3361 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3365 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3366 IWineD3DDevice *iface,
3371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3372 int i, cnt = min(count, MAX_CONST_I - start);
3374 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3375 iface, srcData, start, count);
3377 if (srcData == NULL || cnt < 0)
3378 return WINED3DERR_INVALIDCALL;
3380 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3381 for (i = 0; i < cnt; i++)
3382 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3383 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3385 for (i = start; i < cnt + start; ++i) {
3386 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3394 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3395 IWineD3DDevice *iface,
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 int cnt = min(count, MAX_CONST_I - start);
3403 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3404 iface, dstData, start, count);
3406 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3407 return WINED3DERR_INVALIDCALL;
3409 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3413 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3414 IWineD3DDevice *iface,
3416 CONST float *srcData,
3419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3423 iface, srcData, start, count);
3425 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3426 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3427 return WINED3DERR_INVALIDCALL;
3429 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3431 for (i = 0; i < count; i++)
3432 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3433 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3436 for (i = start; i < count + start; ++i) {
3437 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3438 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3439 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3440 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3441 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3443 ptr->idx[ptr->count++] = i;
3444 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3453 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3454 IWineD3DDevice *iface,
3459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3460 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3462 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3463 iface, dstData, start, count);
3465 if (dstData == NULL || cnt < 0)
3466 return WINED3DERR_INVALIDCALL;
3468 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3472 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3474 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3479 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3480 int i = This->rev_tex_unit_map[unit];
3481 int j = This->texUnitMap[stage];
3483 This->texUnitMap[stage] = unit;
3484 if (i != -1 && i != stage) {
3485 This->texUnitMap[i] = -1;
3488 This->rev_tex_unit_map[unit] = stage;
3489 if (j != -1 && j != unit) {
3490 This->rev_tex_unit_map[j] = -1;
3494 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3497 for (i = 0; i < MAX_TEXTURES; ++i) {
3498 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3499 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3500 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3501 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3502 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3503 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3504 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3505 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3507 if (color_op == WINED3DTOP_DISABLE) {
3508 /* Not used, and disable higher stages */
3509 while (i < MAX_TEXTURES) {
3510 This->fixed_function_usage_map[i] = FALSE;
3516 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3517 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3518 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3519 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3520 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3521 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3522 This->fixed_function_usage_map[i] = TRUE;
3524 This->fixed_function_usage_map[i] = FALSE;
3527 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3528 This->fixed_function_usage_map[i+1] = TRUE;
3533 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3536 device_update_fixed_function_usage_map(This);
3538 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3539 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3540 if (!This->fixed_function_usage_map[i]) continue;
3542 if (This->texUnitMap[i] != i) {
3543 device_map_stage(This, i, i);
3544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3545 markTextureStagesDirty(This, i);
3551 /* Now work out the mapping */
3553 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3554 if (!This->fixed_function_usage_map[i]) continue;
3556 if (This->texUnitMap[i] != tex) {
3557 device_map_stage(This, i, tex);
3558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3559 markTextureStagesDirty(This, i);
3566 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3567 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3570 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3571 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3572 device_map_stage(This, i, i);
3573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3574 if (i < MAX_TEXTURES) {
3575 markTextureStagesDirty(This, i);
3581 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3582 int current_mapping = This->rev_tex_unit_map[unit];
3584 if (current_mapping == -1) {
3585 /* Not currently used */
3589 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3590 /* Used by a fragment sampler */
3592 if (!pshader_sampler_tokens) {
3593 /* No pixel shader, check fixed function */
3594 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3597 /* Pixel shader, check the shader's sampler map */
3598 return !pshader_sampler_tokens[current_mapping];
3601 /* Used by a vertex sampler */
3602 return !vshader_sampler_tokens[current_mapping];
3605 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3606 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3607 DWORD *pshader_sampler_tokens = NULL;
3608 int start = GL_LIMITS(combined_samplers) - 1;
3612 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3614 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3615 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3616 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3619 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3620 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3621 if (vshader_sampler_tokens[i]) {
3622 if (This->texUnitMap[vsampler_idx] != -1) {
3623 /* Already mapped somewhere */
3627 while (start >= 0) {
3628 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3629 device_map_stage(This, vsampler_idx, start);
3630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3642 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3643 BOOL vs = use_vs(This);
3644 BOOL ps = use_ps(This);
3647 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3648 * that would be really messy and require shader recompilation
3649 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3650 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3653 device_map_psamplers(This);
3655 device_map_fixed_function_samplers(This);
3659 device_map_vsamplers(This, ps);
3663 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3665 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3666 This->updateStateBlock->pixelShader = pShader;
3667 This->updateStateBlock->changed.pixelShader = TRUE;
3669 /* Handle recording of state blocks */
3670 if (This->isRecordingState) {
3671 TRACE("Recording... not performing anything\n");
3674 if (This->isRecordingState) {
3675 TRACE("Recording... not performing anything\n");
3676 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3677 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3681 if(pShader == oldShader) {
3682 TRACE("App is setting the old pixel shader over, nothing to do\n");
3686 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3687 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3689 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3695 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 if (NULL == ppShader) {
3699 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3700 return WINED3DERR_INVALIDCALL;
3703 *ppShader = This->stateBlock->pixelShader;
3704 if (NULL != *ppShader) {
3705 IWineD3DPixelShader_AddRef(*ppShader);
3707 TRACE("(%p) : returning %p\n", This, *ppShader);
3711 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3712 IWineD3DDevice *iface,
3714 CONST BOOL *srcData,
3717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3718 int i, cnt = min(count, MAX_CONST_B - start);
3720 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3721 iface, srcData, start, count);
3723 if (srcData == NULL || cnt < 0)
3724 return WINED3DERR_INVALIDCALL;
3726 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3727 for (i = 0; i < cnt; i++)
3728 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3730 for (i = start; i < cnt + start; ++i) {
3731 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3739 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3740 IWineD3DDevice *iface,
3745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3746 int cnt = min(count, MAX_CONST_B - start);
3748 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3749 iface, dstData, start, count);
3751 if (dstData == NULL || cnt < 0)
3752 return WINED3DERR_INVALIDCALL;
3754 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3758 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3759 IWineD3DDevice *iface,
3764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3765 int i, cnt = min(count, MAX_CONST_I - start);
3767 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3768 iface, srcData, start, count);
3770 if (srcData == NULL || cnt < 0)
3771 return WINED3DERR_INVALIDCALL;
3773 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3774 for (i = 0; i < cnt; i++)
3775 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3776 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3778 for (i = start; i < cnt + start; ++i) {
3779 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3782 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3787 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3788 IWineD3DDevice *iface,
3793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3794 int cnt = min(count, MAX_CONST_I - start);
3796 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3797 iface, dstData, start, count);
3799 if (dstData == NULL || cnt < 0)
3800 return WINED3DERR_INVALIDCALL;
3802 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3806 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3807 IWineD3DDevice *iface,
3809 CONST float *srcData,
3812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3815 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3816 iface, srcData, start, count);
3818 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3819 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3820 return WINED3DERR_INVALIDCALL;
3822 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3824 for (i = 0; i < count; i++)
3825 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3826 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3829 for (i = start; i < count + start; ++i) {
3830 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3831 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3832 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3833 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3834 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3836 ptr->idx[ptr->count++] = i;
3837 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3846 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3847 IWineD3DDevice *iface,
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3855 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3856 iface, dstData, start, count);
3858 if (dstData == NULL || cnt < 0)
3859 return WINED3DERR_INVALIDCALL;
3861 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3865 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3867 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3868 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3870 DWORD DestFVF = dest->fvf;
3872 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3876 if (lpStrideData->u.s.normal.lpData) {
3877 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3880 if (lpStrideData->u.s.position.lpData == NULL) {
3881 ERR("Source has no position mask\n");
3882 return WINED3DERR_INVALIDCALL;
3885 /* We might access VBOs from this code, so hold the lock */
3888 if (dest->resource.allocatedMemory == NULL) {
3889 /* This may happen if we do direct locking into a vbo. Unlikely,
3890 * but theoretically possible(ddraw processvertices test)
3892 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3893 if(!dest->resource.allocatedMemory) {
3895 ERR("Out of memory\n");
3896 return E_OUTOFMEMORY;
3900 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3901 checkGLcall("glBindBufferARB");
3902 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3904 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3906 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3907 checkGLcall("glUnmapBufferARB");
3911 /* Get a pointer into the destination vbo(create one if none exists) and
3912 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3914 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3919 unsigned char extrabytes = 0;
3920 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3921 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3922 * this may write 4 extra bytes beyond the area that should be written
3924 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3925 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3926 if(!dest_conv_addr) {
3927 ERR("Out of memory\n");
3928 /* Continue without storing converted vertices */
3930 dest_conv = dest_conv_addr;
3934 * a) WINED3DRS_CLIPPING is enabled
3935 * b) WINED3DVOP_CLIP is passed
3937 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3938 static BOOL warned = FALSE;
3940 * The clipping code is not quite correct. Some things need
3941 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3942 * so disable clipping for now.
3943 * (The graphics in Half-Life are broken, and my processvertices
3944 * test crashes with IDirect3DDevice3)
3950 FIXME("Clipping is broken and disabled for now\n");
3952 } else doClip = FALSE;
3953 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3955 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3958 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3959 WINED3DTS_PROJECTION,
3961 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3962 WINED3DTS_WORLDMATRIX(0),
3965 TRACE("View mat:\n");
3966 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);
3967 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);
3968 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);
3969 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);
3971 TRACE("Proj mat:\n");
3972 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);
3973 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);
3974 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);
3975 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);
3977 TRACE("World mat:\n");
3978 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);
3979 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);
3980 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);
3981 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);
3983 /* Get the viewport */
3984 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3985 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3986 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3988 multiply_matrix(&mat,&view_mat,&world_mat);
3989 multiply_matrix(&mat,&proj_mat,&mat);
3991 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3993 for (i = 0; i < dwCount; i+= 1) {
3994 unsigned int tex_index;
3996 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3997 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3998 /* The position first */
4000 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4002 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4004 /* Multiplication with world, view and projection matrix */
4005 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);
4006 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);
4007 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);
4008 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);
4010 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4012 /* WARNING: The following things are taken from d3d7 and were not yet checked
4013 * against d3d8 or d3d9!
4016 /* Clipping conditions: From
4017 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4019 * A vertex is clipped if it does not match the following requirements
4023 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4025 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4026 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4031 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4032 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4035 /* "Normal" viewport transformation (not clipped)
4036 * 1) The values are divided by rhw
4037 * 2) The y axis is negative, so multiply it with -1
4038 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4039 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4040 * 4) Multiply x with Width/2 and add Width/2
4041 * 5) The same for the height
4042 * 6) Add the viewpoint X and Y to the 2D coordinates and
4043 * The minimum Z value to z
4044 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4046 * Well, basically it's simply a linear transformation into viewport
4058 z *= vp.MaxZ - vp.MinZ;
4060 x += vp.Width / 2 + vp.X;
4061 y += vp.Height / 2 + vp.Y;
4066 /* That vertex got clipped
4067 * Contrary to OpenGL it is not dropped completely, it just
4068 * undergoes a different calculation.
4070 TRACE("Vertex got clipped\n");
4077 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4078 * outside of the main vertex buffer memory. That needs some more
4083 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4086 ( (float *) dest_ptr)[0] = x;
4087 ( (float *) dest_ptr)[1] = y;
4088 ( (float *) dest_ptr)[2] = z;
4089 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4091 dest_ptr += 3 * sizeof(float);
4093 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4094 dest_ptr += sizeof(float);
4099 ( (float *) dest_conv)[0] = x * w;
4100 ( (float *) dest_conv)[1] = y * w;
4101 ( (float *) dest_conv)[2] = z * w;
4102 ( (float *) dest_conv)[3] = w;
4104 dest_conv += 3 * sizeof(float);
4106 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4107 dest_conv += sizeof(float);
4111 if (DestFVF & WINED3DFVF_PSIZE) {
4112 dest_ptr += sizeof(DWORD);
4113 if(dest_conv) dest_conv += sizeof(DWORD);
4115 if (DestFVF & WINED3DFVF_NORMAL) {
4117 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4118 /* AFAIK this should go into the lighting information */
4119 FIXME("Didn't expect the destination to have a normal\n");
4120 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4122 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4126 if (DestFVF & WINED3DFVF_DIFFUSE) {
4128 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4130 static BOOL warned = FALSE;
4133 ERR("No diffuse color in source, but destination has one\n");
4137 *( (DWORD *) dest_ptr) = 0xffffffff;
4138 dest_ptr += sizeof(DWORD);
4141 *( (DWORD *) dest_conv) = 0xffffffff;
4142 dest_conv += sizeof(DWORD);
4146 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4148 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4149 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4150 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4151 dest_conv += sizeof(DWORD);
4156 if (DestFVF & WINED3DFVF_SPECULAR) {
4157 /* What's the color value in the feedback buffer? */
4159 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4161 static BOOL warned = FALSE;
4164 ERR("No specular color in source, but destination has one\n");
4168 *( (DWORD *) dest_ptr) = 0xFF000000;
4169 dest_ptr += sizeof(DWORD);
4172 *( (DWORD *) dest_conv) = 0xFF000000;
4173 dest_conv += sizeof(DWORD);
4177 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4179 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4180 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4181 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4182 dest_conv += sizeof(DWORD);
4187 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4189 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4190 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4192 ERR("No source texture, but destination requests one\n");
4193 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4194 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4197 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4199 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4206 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4207 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4208 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4209 dwCount * get_flexible_vertex_size(DestFVF),
4211 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4212 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4219 #undef copy_and_next
4221 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4223 WineDirect3DVertexStridedData strided;
4224 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4225 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4228 ERR("Output vertex declaration not implemented yet\n");
4231 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4232 * and this call is quite performance critical, so don't call needlessly
4234 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4235 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4238 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4239 * control the streamIsUP flag, thus restore it afterwards.
4241 This->stateBlock->streamIsUP = FALSE;
4242 memset(&strided, 0, sizeof(strided));
4243 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4244 This->stateBlock->streamIsUP = streamWasUP;
4246 if(vbo || SrcStartIndex) {
4248 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4249 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4251 * Also get the start index in, but only loop over all elements if there's something to add at all.
4253 #define FIXSRC(type) \
4254 if(strided.u.s.type.VBO) { \
4255 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4256 strided.u.s.type.VBO = 0; \
4257 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4259 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4263 if(strided.u.s.type.lpData) { \
4264 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4267 FIXSRC(blendWeights);
4268 FIXSRC(blendMatrixIndices);
4273 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4274 FIXSRC(texCoords[i]);
4287 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4291 * Get / Set Texture Stage States
4292 * TODO: Verify against dx9 definitions
4294 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4296 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4298 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4300 if (Stage >= MAX_TEXTURES) {
4301 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4305 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4306 This->updateStateBlock->textureState[Stage][Type] = Value;
4308 if (This->isRecordingState) {
4309 TRACE("Recording... not performing anything\n");
4313 /* Checked after the assignments to allow proper stateblock recording */
4314 if(oldValue == Value) {
4315 TRACE("App is setting the old value over, nothing to do\n");
4319 if(Stage > This->stateBlock->lowest_disabled_stage &&
4320 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4321 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4322 * Changes in other states are important on disabled stages too
4327 if(Type == WINED3DTSS_COLOROP) {
4330 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4331 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4332 * they have to be disabled
4334 * The current stage is dirtified below.
4336 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4337 TRACE("Additionally dirtifying stage %d\n", i);
4338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4340 This->stateBlock->lowest_disabled_stage = Stage;
4341 TRACE("New lowest disabled: %d\n", Stage);
4342 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4343 /* Previously disabled stage enabled. Stages above it may need enabling
4344 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4345 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4347 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4350 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4351 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4354 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4357 This->stateBlock->lowest_disabled_stage = i;
4358 TRACE("New lowest disabled: %d\n", i);
4360 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4361 /* TODO: Built a stage -> texture unit mapping for register combiners */
4365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4370 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4372 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4373 *pValue = This->updateStateBlock->textureState[Stage][Type];
4380 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4382 IWineD3DBaseTexture *oldTexture;
4384 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4386 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4387 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4390 oldTexture = This->updateStateBlock->textures[Stage];
4392 if(pTexture != NULL) {
4393 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4395 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4396 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4397 return WINED3DERR_INVALIDCALL;
4399 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4402 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4403 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4405 This->updateStateBlock->changed.textures[Stage] = TRUE;
4406 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4407 This->updateStateBlock->textures[Stage] = pTexture;
4409 /* Handle recording of state blocks */
4410 if (This->isRecordingState) {
4411 TRACE("Recording... not performing anything\n");
4415 if(oldTexture == pTexture) {
4416 TRACE("App is setting the same texture again, nothing to do\n");
4420 /** NOTE: MSDN says that setTexture increases the reference count,
4421 * and that the application must set the texture back to null (or have a leaky application),
4422 * This means we should pass the refcount up to the parent
4423 *******************************/
4424 if (NULL != This->updateStateBlock->textures[Stage]) {
4425 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4426 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4428 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4429 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4430 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4431 * so the COLOROP and ALPHAOP have to be dirtified.
4433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4436 if(bindCount == 1) {
4437 new->baseTexture.sampler = Stage;
4439 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4443 if (NULL != oldTexture) {
4444 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4445 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4447 IWineD3DBaseTexture_Release(oldTexture);
4448 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4453 if(bindCount && old->baseTexture.sampler == Stage) {
4455 /* Have to do a search for the other sampler(s) where the texture is bound to
4456 * Shouldn't happen as long as apps bind a texture only to one stage
4458 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4459 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4460 if(This->updateStateBlock->textures[i] == oldTexture) {
4461 old->baseTexture.sampler = i;
4468 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4473 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4478 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4479 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4482 *ppTexture=This->stateBlock->textures[Stage];
4484 IWineD3DBaseTexture_AddRef(*ppTexture);
4486 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4494 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4495 IWineD3DSurface **ppBackBuffer) {
4496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4497 IWineD3DSwapChain *swapChain;
4500 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4502 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4503 if (hr == WINED3D_OK) {
4504 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4505 IWineD3DSwapChain_Release(swapChain);
4507 *ppBackBuffer = NULL;
4512 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4514 WARN("(%p) : stub, calling idirect3d for now\n", This);
4515 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4518 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 IWineD3DSwapChain *swapChain;
4523 if(iSwapChain > 0) {
4524 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4525 if (hr == WINED3D_OK) {
4526 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4527 IWineD3DSwapChain_Release(swapChain);
4529 FIXME("(%p) Error getting display mode\n", This);
4532 /* Don't read the real display mode,
4533 but return the stored mode instead. X11 can't change the color
4534 depth, and some apps are pretty angry if they SetDisplayMode from
4535 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4537 Also don't relay to the swapchain because with ddraw it's possible
4538 that there isn't a swapchain at all */
4539 pMode->Width = This->ddraw_width;
4540 pMode->Height = This->ddraw_height;
4541 pMode->Format = This->ddraw_format;
4542 pMode->RefreshRate = 0;
4549 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4551 TRACE("(%p)->(%p)\n", This, hWnd);
4553 if(This->ddraw_fullscreen) {
4554 if(This->ddraw_window && This->ddraw_window != hWnd) {
4555 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4557 if(hWnd && This->ddraw_window != hWnd) {
4558 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4562 This->ddraw_window = hWnd;
4566 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 TRACE("(%p)->(%p)\n", This, hWnd);
4570 *hWnd = This->ddraw_window;
4575 * Stateblock related functions
4578 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4580 IWineD3DStateBlockImpl *object;
4581 HRESULT temp_result;
4584 TRACE("(%p)\n", This);
4586 if (This->isRecordingState) {
4587 return WINED3DERR_INVALIDCALL;
4590 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4591 if (NULL == object ) {
4592 FIXME("(%p)Error allocating memory for stateblock\n", This);
4593 return E_OUTOFMEMORY;
4595 TRACE("(%p) created object %p\n", This, object);
4596 object->wineD3DDevice= This;
4597 /** FIXME: object->parent = parent; **/
4598 object->parent = NULL;
4599 object->blockType = WINED3DSBT_RECORDED;
4601 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4603 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4604 list_init(&object->lightMap[i]);
4607 temp_result = allocate_shader_constants(object);
4608 if (WINED3D_OK != temp_result)
4611 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4612 This->updateStateBlock = object;
4613 This->isRecordingState = TRUE;
4615 TRACE("(%p) recording stateblock %p\n",This , object);
4619 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4622 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4624 if (!This->isRecordingState) {
4625 FIXME("(%p) not recording! returning error\n", This);
4626 *ppStateBlock = NULL;
4627 return WINED3DERR_INVALIDCALL;
4630 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4631 if(object->changed.renderState[i]) {
4632 object->contained_render_states[object->num_contained_render_states] = i;
4633 object->num_contained_render_states++;
4636 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4637 if(object->changed.transform[i]) {
4638 object->contained_transform_states[object->num_contained_transform_states] = i;
4639 object->num_contained_transform_states++;
4642 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4643 if(object->changed.vertexShaderConstantsF[i]) {
4644 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4645 object->num_contained_vs_consts_f++;
4648 for(i = 0; i < MAX_CONST_I; i++) {
4649 if(object->changed.vertexShaderConstantsI[i]) {
4650 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4651 object->num_contained_vs_consts_i++;
4654 for(i = 0; i < MAX_CONST_B; i++) {
4655 if(object->changed.vertexShaderConstantsB[i]) {
4656 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4657 object->num_contained_vs_consts_b++;
4660 for(i = 0; i < MAX_CONST_I; i++) {
4661 if(object->changed.pixelShaderConstantsI[i]) {
4662 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4663 object->num_contained_ps_consts_i++;
4666 for(i = 0; i < MAX_CONST_B; i++) {
4667 if(object->changed.pixelShaderConstantsB[i]) {
4668 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4669 object->num_contained_ps_consts_b++;
4672 for(i = 0; i < MAX_TEXTURES; i++) {
4673 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4674 if(object->changed.textureState[i][j]) {
4675 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4676 object->contained_tss_states[object->num_contained_tss_states].state = j;
4677 object->num_contained_tss_states++;
4681 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4682 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4683 if(object->changed.samplerState[i][j]) {
4684 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4685 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4686 object->num_contained_sampler_states++;
4691 *ppStateBlock = (IWineD3DStateBlock*) object;
4692 This->isRecordingState = FALSE;
4693 This->updateStateBlock = This->stateBlock;
4694 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4695 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4696 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4701 * Scene related functions
4703 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4704 /* At the moment we have no need for any functionality at the beginning
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 TRACE("(%p)\n", This);
4710 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4711 return WINED3DERR_INVALIDCALL;
4713 This->inScene = TRUE;
4717 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4719 TRACE("(%p)\n", This);
4721 if(!This->inScene) {
4722 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4723 return WINED3DERR_INVALIDCALL;
4726 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4727 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4729 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4732 checkGLcall("glFlush");
4735 This->inScene = FALSE;
4739 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4740 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4741 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4743 IWineD3DSwapChain *swapChain = NULL;
4745 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4747 TRACE("(%p) Presenting the frame\n", This);
4749 for(i = 0 ; i < swapchains ; i ++) {
4751 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4752 TRACE("presentinng chain %d, %p\n", i, swapChain);
4753 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4754 IWineD3DSwapChain_Release(swapChain);
4760 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4761 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4763 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4765 GLbitfield glMask = 0;
4767 WINED3DRECT curRect;
4769 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4770 UINT drawable_width, drawable_height;
4772 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4773 Count, pRects, Flags, Color, Z, Stencil);
4775 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4776 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4777 /* TODO: What about depth stencil buffers without stencil bits? */
4778 return WINED3DERR_INVALIDCALL;
4781 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4782 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4783 * for the cleared parts, and the untouched parts.
4785 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4786 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4787 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4788 * checking all this if the dest surface is in the drawable anyway.
4790 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4792 if(vp->X != 0 || vp->Y != 0 ||
4793 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4794 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4797 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4798 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4799 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4800 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4801 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4804 if(Count > 0 && pRects && (
4805 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4806 pRects[0].x2 < target->currentDesc.Width ||
4807 pRects[0].y2 < target->currentDesc.Height)) {
4808 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4815 target->get_drawable_size(target, &drawable_width, &drawable_height);
4817 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4818 * and not the last active one.
4820 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4823 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4824 apply_fbo_state(iface);
4827 /* Only set the values up once, as they are not changing */
4828 if (Flags & WINED3DCLEAR_STENCIL) {
4829 glClearStencil(Stencil);
4830 checkGLcall("glClearStencil");
4831 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4832 glStencilMask(0xFFFFFFFF);
4835 if (Flags & WINED3DCLEAR_ZBUFFER) {
4836 glDepthMask(GL_TRUE);
4838 checkGLcall("glClearDepth");
4839 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4843 if (Flags & WINED3DCLEAR_TARGET) {
4844 TRACE("Clearing screen with glClear to color %x\n", Color);
4845 glClearColor(D3DCOLOR_R(Color),
4849 checkGLcall("glClearColor");
4851 /* Clear ALL colors! */
4852 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4853 glMask = glMask | GL_COLOR_BUFFER_BIT;
4856 vp_rect.left = vp->X;
4857 vp_rect.top = vp->Y;
4858 vp_rect.right = vp->X + vp->Width;
4859 vp_rect.bottom = vp->Y + vp->Height;
4860 if (!(Count > 0 && pRects)) {
4861 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4862 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4864 if(This->render_offscreen) {
4865 glScissor(vp_rect.left, vp_rect.top,
4866 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4868 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4869 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4871 checkGLcall("glScissor");
4873 checkGLcall("glClear");
4875 /* Now process each rect in turn */
4876 for (i = 0; i < Count; i++) {
4877 /* Note gl uses lower left, width/height */
4878 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4879 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4880 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4882 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4883 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4884 curRect.x1, (target->currentDesc.Height - curRect.y2),
4885 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4887 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4888 * The rectangle is not cleared, no error is returned, but further rectanlges are
4889 * still cleared if they are valid
4891 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4892 TRACE("Rectangle with negative dimensions, ignoring\n");
4896 if(This->render_offscreen) {
4897 glScissor(curRect.x1, curRect.y1,
4898 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4900 glScissor(curRect.x1, drawable_height - curRect.y2,
4901 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4903 checkGLcall("glScissor");
4906 checkGLcall("glClear");
4910 /* Restore the old values (why..?) */
4911 if (Flags & WINED3DCLEAR_STENCIL) {
4912 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4914 if (Flags & WINED3DCLEAR_TARGET) {
4915 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4916 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4917 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4918 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4919 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4921 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4922 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4924 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4925 /* TODO: Move the fbo logic into ModifyLocation() */
4926 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4927 target->Flags |= SFLAG_INTEXTURE;
4938 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4939 UINT PrimitiveCount) {
4941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4943 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4944 debug_d3dprimitivetype(PrimitiveType),
4945 StartVertex, PrimitiveCount);
4947 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4948 if(This->stateBlock->streamIsUP) {
4949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4950 This->stateBlock->streamIsUP = FALSE;
4953 if(This->stateBlock->loadBaseVertexIndex != 0) {
4954 This->stateBlock->loadBaseVertexIndex = 0;
4955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4957 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4958 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4959 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4963 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4964 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4965 WINED3DPRIMITIVETYPE PrimitiveType,
4966 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4970 IWineD3DIndexBuffer *pIB;
4971 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4974 pIB = This->stateBlock->pIndexData;
4976 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4977 * without an index buffer set. (The first time at least...)
4978 * D3D8 simply dies, but I doubt it can do much harm to return
4979 * D3DERR_INVALIDCALL there as well. */
4980 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4981 return WINED3DERR_INVALIDCALL;
4984 if(This->stateBlock->streamIsUP) {
4985 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4986 This->stateBlock->streamIsUP = FALSE;
4988 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4990 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4991 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4992 minIndex, NumVertices, startIndex, primCount);
4994 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4995 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5001 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5002 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5006 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5007 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5012 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5013 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5014 UINT VertexStreamZeroStride) {
5015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5016 IWineD3DVertexBuffer *vb;
5018 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5019 debug_d3dprimitivetype(PrimitiveType),
5020 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5022 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5023 vb = This->stateBlock->streamSource[0];
5024 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5025 if(vb) IWineD3DVertexBuffer_Release(vb);
5026 This->stateBlock->streamOffset[0] = 0;
5027 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5028 This->stateBlock->streamIsUP = TRUE;
5029 This->stateBlock->loadBaseVertexIndex = 0;
5031 /* TODO: Only mark dirty if drawing from a different UP address */
5032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5034 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5035 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5037 /* MSDN specifies stream zero settings must be set to NULL */
5038 This->stateBlock->streamStride[0] = 0;
5039 This->stateBlock->streamSource[0] = NULL;
5041 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5042 * the new stream sources or use UP drawing again
5047 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5048 UINT MinVertexIndex, UINT NumVertices,
5049 UINT PrimitiveCount, CONST void* pIndexData,
5050 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5051 UINT VertexStreamZeroStride) {
5053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5054 IWineD3DVertexBuffer *vb;
5055 IWineD3DIndexBuffer *ib;
5057 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5058 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5059 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5060 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5062 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5068 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5069 vb = This->stateBlock->streamSource[0];
5070 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5071 if(vb) IWineD3DVertexBuffer_Release(vb);
5072 This->stateBlock->streamIsUP = TRUE;
5073 This->stateBlock->streamOffset[0] = 0;
5074 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5076 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5077 This->stateBlock->baseVertexIndex = 0;
5078 This->stateBlock->loadBaseVertexIndex = 0;
5079 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5083 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5085 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5086 This->stateBlock->streamSource[0] = NULL;
5087 This->stateBlock->streamStride[0] = 0;
5088 ib = This->stateBlock->pIndexData;
5090 IWineD3DIndexBuffer_Release(ib);
5091 This->stateBlock->pIndexData = NULL;
5093 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5094 * SetStreamSource to specify a vertex buffer
5100 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5103 /* Mark the state dirty until we have nicer tracking
5104 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5107 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5109 This->stateBlock->baseVertexIndex = 0;
5110 This->up_strided = DrawPrimStrideData;
5111 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5112 This->up_strided = NULL;
5116 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5118 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5120 /* Mark the state dirty until we have nicer tracking
5121 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5126 This->stateBlock->streamIsUP = TRUE;
5127 This->stateBlock->baseVertexIndex = 0;
5128 This->up_strided = DrawPrimStrideData;
5129 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5130 This->up_strided = NULL;
5134 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5135 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5136 * not callable by the app directly no parameter validation checks are needed here.
5138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5139 WINED3DLOCKED_BOX src;
5140 WINED3DLOCKED_BOX dst;
5142 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5144 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5145 * dirtification to improve loading performance.
5147 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5148 if(FAILED(hr)) return hr;
5149 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5151 IWineD3DVolume_UnlockBox(pSourceVolume);
5155 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5157 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5159 IWineD3DVolume_UnlockBox(pSourceVolume);
5161 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5166 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5167 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 HRESULT hr = WINED3D_OK;
5170 WINED3DRESOURCETYPE sourceType;
5171 WINED3DRESOURCETYPE destinationType;
5174 /* TODO: think about moving the code into IWineD3DBaseTexture */
5176 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5178 /* verify that the source and destination textures aren't NULL */
5179 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5180 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5181 This, pSourceTexture, pDestinationTexture);
5182 hr = WINED3DERR_INVALIDCALL;
5185 if (pSourceTexture == pDestinationTexture) {
5186 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5187 This, pSourceTexture, pDestinationTexture);
5188 hr = WINED3DERR_INVALIDCALL;
5190 /* Verify that the source and destination textures are the same type */
5191 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5192 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5194 if (sourceType != destinationType) {
5195 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5197 hr = WINED3DERR_INVALIDCALL;
5200 /* check that both textures have the identical numbers of levels */
5201 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5202 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5203 hr = WINED3DERR_INVALIDCALL;
5206 if (WINED3D_OK == hr) {
5208 /* Make sure that the destination texture is loaded */
5209 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5211 /* Update every surface level of the texture */
5212 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5214 switch (sourceType) {
5215 case WINED3DRTYPE_TEXTURE:
5217 IWineD3DSurface *srcSurface;
5218 IWineD3DSurface *destSurface;
5220 for (i = 0 ; i < levels ; ++i) {
5221 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5222 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5223 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5224 IWineD3DSurface_Release(srcSurface);
5225 IWineD3DSurface_Release(destSurface);
5226 if (WINED3D_OK != hr) {
5227 WARN("(%p) : Call to update surface failed\n", This);
5233 case WINED3DRTYPE_CUBETEXTURE:
5235 IWineD3DSurface *srcSurface;
5236 IWineD3DSurface *destSurface;
5237 WINED3DCUBEMAP_FACES faceType;
5239 for (i = 0 ; i < levels ; ++i) {
5240 /* Update each cube face */
5241 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5242 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5243 if (WINED3D_OK != hr) {
5244 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5246 TRACE("Got srcSurface %p\n", srcSurface);
5248 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5249 if (WINED3D_OK != hr) {
5250 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5252 TRACE("Got desrSurface %p\n", destSurface);
5254 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5255 IWineD3DSurface_Release(srcSurface);
5256 IWineD3DSurface_Release(destSurface);
5257 if (WINED3D_OK != hr) {
5258 WARN("(%p) : Call to update surface failed\n", This);
5266 case WINED3DRTYPE_VOLUMETEXTURE:
5268 IWineD3DVolume *srcVolume = NULL;
5269 IWineD3DVolume *destVolume = NULL;
5271 for (i = 0 ; i < levels ; ++i) {
5272 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5273 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5274 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5275 IWineD3DVolume_Release(srcVolume);
5276 IWineD3DVolume_Release(destVolume);
5277 if (WINED3D_OK != hr) {
5278 WARN("(%p) : Call to update volume failed\n", This);
5286 FIXME("(%p) : Unsupported source and destination type\n", This);
5287 hr = WINED3DERR_INVALIDCALL;
5294 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5295 IWineD3DSwapChain *swapChain;
5297 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5298 if(hr == WINED3D_OK) {
5299 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5300 IWineD3DSwapChain_Release(swapChain);
5305 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5307 /* return a sensible default */
5309 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5310 FIXME("(%p) : stub\n", This);
5314 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5318 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5319 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5320 return WINED3DERR_INVALIDCALL;
5322 for (j = 0; j < 256; ++j) {
5323 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5324 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5325 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5326 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5328 TRACE("(%p) : returning\n", This);
5332 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5335 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5336 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5337 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5338 return WINED3DERR_INVALIDCALL;
5340 for (j = 0; j < 256; ++j) {
5341 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5342 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5343 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5344 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5346 TRACE("(%p) : returning\n", This);
5350 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5352 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5353 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5354 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5355 return WINED3DERR_INVALIDCALL;
5357 /*TODO: stateblocks */
5358 This->currentPalette = PaletteNumber;
5359 TRACE("(%p) : returning\n", This);
5363 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5365 if (PaletteNumber == NULL) {
5366 WARN("(%p) : returning Invalid Call\n", This);
5367 return WINED3DERR_INVALIDCALL;
5369 /*TODO: stateblocks */
5370 *PaletteNumber = This->currentPalette;
5371 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5375 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5377 static BOOL showFixmes = TRUE;
5379 FIXME("(%p) : stub\n", This);
5383 This->softwareVertexProcessing = bSoftware;
5388 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5390 static BOOL showFixmes = TRUE;
5392 FIXME("(%p) : stub\n", This);
5395 return This->softwareVertexProcessing;
5399 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5401 IWineD3DSwapChain *swapChain;
5404 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5406 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5407 if(hr == WINED3D_OK){
5408 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5409 IWineD3DSwapChain_Release(swapChain);
5411 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5417 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5419 static BOOL showfixmes = TRUE;
5420 if(nSegments != 0.0f) {
5422 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5429 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5431 static BOOL showfixmes = TRUE;
5433 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5439 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5441 /** TODO: remove casts to IWineD3DSurfaceImpl
5442 * NOTE: move code to surface to accomplish this
5443 ****************************************/
5444 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5445 int srcWidth, srcHeight;
5446 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5447 WINED3DFORMAT destFormat, srcFormat;
5449 int srcLeft, destLeft, destTop;
5450 WINED3DPOOL srcPool, destPool;
5452 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5453 glDescriptor *glDescription = NULL;
5456 CONVERT_TYPES convert = NO_CONVERSION;
5458 WINED3DSURFACE_DESC winedesc;
5460 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5461 memset(&winedesc, 0, sizeof(winedesc));
5462 winedesc.Width = &srcSurfaceWidth;
5463 winedesc.Height = &srcSurfaceHeight;
5464 winedesc.Pool = &srcPool;
5465 winedesc.Format = &srcFormat;
5467 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5469 winedesc.Width = &destSurfaceWidth;
5470 winedesc.Height = &destSurfaceHeight;
5471 winedesc.Pool = &destPool;
5472 winedesc.Format = &destFormat;
5473 winedesc.Size = &destSize;
5475 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5477 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5478 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5479 return WINED3DERR_INVALIDCALL;
5482 /* This call loads the opengl surface directly, instead of copying the surface to the
5483 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5484 * copy in sysmem and use regular surface loading.
5486 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5487 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5488 if(convert != NO_CONVERSION) {
5489 return IWineD3DSurface_BltFast(pDestinationSurface,
5490 pDestPoint ? pDestPoint->x : 0,
5491 pDestPoint ? pDestPoint->y : 0,
5492 pSourceSurface, (RECT *) pSourceRect, 0);
5495 if (destFormat == WINED3DFMT_UNKNOWN) {
5496 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5497 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5499 /* Get the update surface description */
5500 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5503 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5507 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5508 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5509 checkGLcall("glActiveTextureARB");
5512 /* Make sure the surface is loaded and up to date */
5513 IWineD3DSurface_PreLoad(pDestinationSurface);
5515 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5517 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5518 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5519 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5520 srcLeft = pSourceRect ? pSourceRect->left : 0;
5521 destLeft = pDestPoint ? pDestPoint->x : 0;
5522 destTop = pDestPoint ? pDestPoint->y : 0;
5525 /* This function doesn't support compressed textures
5526 the pitch is just bytesPerPixel * width */
5527 if(srcWidth != srcSurfaceWidth || srcLeft ){
5528 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5529 offset += srcLeft * pSrcSurface->bytesPerPixel;
5530 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5532 /* TODO DXT formats */
5534 if(pSourceRect != NULL && pSourceRect->top != 0){
5535 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5537 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5539 ,glDescription->level
5544 ,glDescription->glFormat
5545 ,glDescription->glType
5546 ,IWineD3DSurface_GetData(pSourceSurface)
5550 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5552 /* need to lock the surface to get the data */
5553 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5556 /* TODO: Cube and volume support */
5558 /* not a whole row so we have to do it a line at a time */
5561 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5562 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5564 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5566 glTexSubImage2D(glDescription->target
5567 ,glDescription->level
5572 ,glDescription->glFormat
5573 ,glDescription->glType
5574 ,data /* could be quicker using */
5579 } else { /* Full width, so just write out the whole texture */
5581 if (WINED3DFMT_DXT1 == destFormat ||
5582 WINED3DFMT_DXT2 == destFormat ||
5583 WINED3DFMT_DXT3 == destFormat ||
5584 WINED3DFMT_DXT4 == destFormat ||
5585 WINED3DFMT_DXT5 == destFormat) {
5586 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5587 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5588 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5589 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5590 } if (destFormat != srcFormat) {
5591 FIXME("Updating mixed format compressed texture is not curretly support\n");
5593 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5594 glDescription->level,
5595 glDescription->glFormatInternal,
5600 IWineD3DSurface_GetData(pSourceSurface));
5603 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5608 glTexSubImage2D(glDescription->target
5609 ,glDescription->level
5614 ,glDescription->glFormat
5615 ,glDescription->glType
5616 ,IWineD3DSurface_GetData(pSourceSurface)
5620 checkGLcall("glTexSubImage2D");
5624 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5630 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5632 struct WineD3DRectPatch *patch;
5636 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5638 if(!(Handle || pRectPatchInfo)) {
5639 /* TODO: Write a test for the return value, thus the FIXME */
5640 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5641 return WINED3DERR_INVALIDCALL;
5645 i = PATCHMAP_HASHFUNC(Handle);
5647 LIST_FOR_EACH(e, &This->patches[i]) {
5648 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5649 if(patch->Handle == Handle) {
5656 TRACE("Patch does not exist. Creating a new one\n");
5657 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5658 patch->Handle = Handle;
5659 list_add_head(&This->patches[i], &patch->entry);
5661 TRACE("Found existing patch %p\n", patch);
5664 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5665 * attributes we have to tesselate, read back, and draw. This needs a patch
5666 * management structure instance. Create one.
5668 * A possible improvement is to check if a vertex shader is used, and if not directly
5671 FIXME("Drawing an uncached patch. This is slow\n");
5672 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5675 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5676 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5677 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5679 TRACE("Tesselation density or patch info changed, retesselating\n");
5681 if(pRectPatchInfo) {
5682 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5684 patch->numSegs[0] = pNumSegs[0];
5685 patch->numSegs[1] = pNumSegs[1];
5686 patch->numSegs[2] = pNumSegs[2];
5687 patch->numSegs[3] = pNumSegs[3];
5689 hr = tesselate_rectpatch(This, patch);
5691 WARN("Patch tesselation failed\n");
5693 /* Do not release the handle to store the params of the patch */
5695 HeapFree(GetProcessHeap(), 0, patch);
5701 This->currentPatch = patch;
5702 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5703 This->currentPatch = NULL;
5705 /* Destroy uncached patches */
5707 HeapFree(GetProcessHeap(), 0, patch->mem);
5708 HeapFree(GetProcessHeap(), 0, patch);
5713 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5714 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5716 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5717 FIXME("(%p) : Stub\n", This);
5721 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5724 struct WineD3DRectPatch *patch;
5726 TRACE("(%p) Handle(%d)\n", This, Handle);
5728 i = PATCHMAP_HASHFUNC(Handle);
5729 LIST_FOR_EACH(e, &This->patches[i]) {
5730 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5731 if(patch->Handle == Handle) {
5732 TRACE("Deleting patch %p\n", patch);
5733 list_remove(&patch->entry);
5734 HeapFree(GetProcessHeap(), 0, patch->mem);
5735 HeapFree(GetProcessHeap(), 0, patch);
5740 /* TODO: Write a test for the return value */
5741 FIXME("Attempt to destroy nonexistent patch\n");
5742 return WINED3DERR_INVALIDCALL;
5745 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5747 IWineD3DSwapChain *swapchain;
5749 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5750 if (SUCCEEDED(hr)) {
5751 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5758 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5762 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5763 checkGLcall("glGenFramebuffersEXT()");
5765 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5766 checkGLcall("glBindFramebuffer()");
5769 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5770 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5771 IWineD3DBaseTextureImpl *texture_impl;
5772 GLenum texttarget, target;
5775 texttarget = surface_impl->glDescription.target;
5776 if(texttarget == GL_TEXTURE_2D) {
5777 target = GL_TEXTURE_2D;
5778 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5779 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5780 target = GL_TEXTURE_RECTANGLE_ARB;
5781 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5783 target = GL_TEXTURE_CUBE_MAP_ARB;
5784 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5787 IWineD3DSurface_PreLoad(surface);
5789 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5790 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5791 glBindTexture(target, old_binding);
5793 /* Update base texture states array */
5794 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5795 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5796 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5797 if (texture_impl->baseTexture.bindCount) {
5798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5801 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5804 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5805 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5807 checkGLcall("attach_surface_fbo");
5810 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5812 IWineD3DSwapChain *swapchain;
5814 swapchain = get_swapchain(surface);
5818 TRACE("Surface %p is onscreen\n", surface);
5820 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5821 buffer = surface_get_gl_buffer(surface, swapchain);
5822 glDrawBuffer(buffer);
5823 checkGLcall("glDrawBuffer()");
5825 TRACE("Surface %p is offscreen\n", surface);
5826 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5827 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5831 glEnable(GL_SCISSOR_TEST);
5833 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5835 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5836 rect->x2 - rect->x1, rect->y2 - rect->y1);
5838 checkGLcall("glScissor");
5840 glDisable(GL_SCISSOR_TEST);
5842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5844 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5847 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5848 glClear(GL_COLOR_BUFFER_BIT);
5849 checkGLcall("glClear");
5851 if (This->render_offscreen) {
5852 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5854 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5855 checkGLcall("glBindFramebuffer()");
5858 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5859 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5860 glDrawBuffer(GL_BACK);
5861 checkGLcall("glDrawBuffer()");
5865 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5866 unsigned int r, g, b, a;
5869 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5870 destfmt == WINED3DFMT_R8G8B8)
5873 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5875 a = (color & 0xff000000) >> 24;
5876 r = (color & 0x00ff0000) >> 16;
5877 g = (color & 0x0000ff00) >> 8;
5878 b = (color & 0x000000ff) >> 0;
5882 case WINED3DFMT_R5G6B5:
5883 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5890 TRACE("Returning %08x\n", ret);
5893 case WINED3DFMT_X1R5G5B5:
5894 case WINED3DFMT_A1R5G5B5:
5903 TRACE("Returning %08x\n", ret);
5907 TRACE("Returning %08x\n", a);
5910 case WINED3DFMT_X4R4G4B4:
5911 case WINED3DFMT_A4R4G4B4:
5920 TRACE("Returning %08x\n", ret);
5923 case WINED3DFMT_R3G3B2:
5930 TRACE("Returning %08x\n", ret);
5933 case WINED3DFMT_X8B8G8R8:
5934 case WINED3DFMT_A8B8G8R8:
5939 TRACE("Returning %08x\n", ret);
5942 case WINED3DFMT_A2R10G10B10:
5944 r = (r * 1024) / 256;
5945 g = (g * 1024) / 256;
5946 b = (b * 1024) / 256;
5951 TRACE("Returning %08x\n", ret);
5954 case WINED3DFMT_A2B10G10R10:
5956 r = (r * 1024) / 256;
5957 g = (g * 1024) / 256;
5958 b = (b * 1024) / 256;
5963 TRACE("Returning %08x\n", ret);
5967 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5972 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5974 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5976 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5978 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5979 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5980 return WINED3DERR_INVALIDCALL;
5983 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5984 color_fill_fbo(iface, pSurface, pRect, color);
5987 /* Just forward this to the DirectDraw blitting engine */
5988 memset(&BltFx, 0, sizeof(BltFx));
5989 BltFx.dwSize = sizeof(BltFx);
5990 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5991 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5995 /* rendertarget and deptth stencil functions */
5996 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5999 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6000 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6001 return WINED3DERR_INVALIDCALL;
6004 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6005 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6006 /* Note inc ref on returned surface */
6007 if(*ppRenderTarget != NULL)
6008 IWineD3DSurface_AddRef(*ppRenderTarget);
6012 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6014 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6015 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6016 IWineD3DSwapChainImpl *Swapchain;
6019 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6021 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6022 if(hr != WINED3D_OK) {
6023 ERR("Can't get the swapchain\n");
6027 /* Make sure to release the swapchain */
6028 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6030 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6031 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6032 return WINED3DERR_INVALIDCALL;
6034 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6035 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6036 return WINED3DERR_INVALIDCALL;
6039 if(Swapchain->frontBuffer != Front) {
6040 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6042 if(Swapchain->frontBuffer)
6043 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6044 Swapchain->frontBuffer = Front;
6046 if(Swapchain->frontBuffer) {
6047 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6051 if(Back && !Swapchain->backBuffer) {
6052 /* We need memory for the back buffer array - only one back buffer this way */
6053 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6054 if(!Swapchain->backBuffer) {
6055 ERR("Out of memory\n");
6056 return E_OUTOFMEMORY;
6060 if(Swapchain->backBuffer[0] != Back) {
6061 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6063 /* What to do about the context here in the case of multithreading? Not sure.
6064 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6067 if(!Swapchain->backBuffer[0]) {
6068 /* GL was told to draw to the front buffer at creation,
6071 glDrawBuffer(GL_BACK);
6072 checkGLcall("glDrawBuffer(GL_BACK)");
6073 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6074 Swapchain->presentParms.BackBufferCount = 1;
6076 /* That makes problems - disable for now */
6077 /* glDrawBuffer(GL_FRONT); */
6078 checkGLcall("glDrawBuffer(GL_FRONT)");
6079 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6080 Swapchain->presentParms.BackBufferCount = 0;
6084 if(Swapchain->backBuffer[0])
6085 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6086 Swapchain->backBuffer[0] = Back;
6088 if(Swapchain->backBuffer[0]) {
6089 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6091 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6092 Swapchain->backBuffer = NULL;
6100 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6102 *ppZStencilSurface = This->stencilBufferTarget;
6103 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6105 if(*ppZStencilSurface != NULL) {
6106 /* Note inc ref on returned surface */
6107 IWineD3DSurface_AddRef(*ppZStencilSurface);
6110 return WINED3DERR_NOTFOUND;
6114 /* TODO: Handle stencil attachments */
6115 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6117 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6119 TRACE("Set depth stencil to %p\n", depth_stencil);
6121 if (depth_stencil_impl) {
6122 if (depth_stencil_impl->current_renderbuffer) {
6123 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6124 checkGLcall("glFramebufferRenderbufferEXT()");
6126 IWineD3DBaseTextureImpl *texture_impl;
6127 GLenum texttarget, target;
6128 GLint old_binding = 0;
6130 texttarget = depth_stencil_impl->glDescription.target;
6131 if(texttarget == GL_TEXTURE_2D) {
6132 target = GL_TEXTURE_2D;
6133 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6134 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6135 target = GL_TEXTURE_RECTANGLE_ARB;
6136 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6138 target = GL_TEXTURE_CUBE_MAP_ARB;
6139 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6142 IWineD3DSurface_PreLoad(depth_stencil);
6144 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6145 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6146 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6147 glBindTexture(target, old_binding);
6149 /* Update base texture states array */
6150 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6151 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6152 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6153 if (texture_impl->baseTexture.bindCount) {
6154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6157 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6160 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6161 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6162 checkGLcall("glFramebufferTexture2DEXT()");
6165 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6166 checkGLcall("glFramebufferTexture2DEXT()");
6170 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6172 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6174 TRACE("Set render target %u to %p\n", idx, render_target);
6177 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6178 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6180 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6181 checkGLcall("glFramebufferTexture2DEXT()");
6183 This->draw_buffers[idx] = GL_NONE;
6187 static void check_fbo_status(IWineD3DDevice *iface) {
6188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6191 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6192 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6193 TRACE("FBO complete\n");
6195 IWineD3DSurfaceImpl *attachment;
6197 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6199 /* Dump the FBO attachments */
6200 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6201 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6203 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6204 attachment->pow2Width, attachment->pow2Height);
6207 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6209 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6210 attachment->pow2Width, attachment->pow2Height);
6215 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6217 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6218 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6220 if (!ds_impl) return FALSE;
6222 if (ds_impl->current_renderbuffer) {
6223 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6224 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6227 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6228 rt_impl->pow2Height != ds_impl->pow2Height);
6231 void apply_fbo_state(IWineD3DDevice *iface) {
6232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6235 if (This->render_offscreen) {
6236 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6238 /* Apply render targets */
6239 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6240 IWineD3DSurface *render_target = This->render_targets[i];
6241 if (This->fbo_color_attachments[i] != render_target) {
6242 set_render_target_fbo(iface, i, render_target);
6243 This->fbo_color_attachments[i] = render_target;
6247 /* Apply depth targets */
6248 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6249 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6250 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6252 if (This->stencilBufferTarget) {
6253 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6255 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6256 This->fbo_depth_attachment = This->stencilBufferTarget;
6259 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6260 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6261 checkGLcall("glDrawBuffers()");
6263 glDrawBuffer(This->draw_buffers[0]);
6264 checkGLcall("glDrawBuffer()");
6267 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6270 check_fbo_status(iface);
6273 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6274 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6276 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6277 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6280 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6281 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6282 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6283 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6286 case WINED3DTEXF_LINEAR:
6287 gl_filter = GL_LINEAR;
6291 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6292 case WINED3DTEXF_NONE:
6293 case WINED3DTEXF_POINT:
6294 gl_filter = GL_NEAREST;
6298 /* Attach src surface to src fbo */
6299 src_swapchain = get_swapchain(src_surface);
6300 if (src_swapchain) {
6303 TRACE("Source surface %p is onscreen\n", src_surface);
6304 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6307 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6308 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6309 glReadBuffer(buffer);
6310 checkGLcall("glReadBuffer()");
6312 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6313 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6315 TRACE("Source surface %p is offscreen\n", src_surface);
6317 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6318 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6319 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6320 checkGLcall("glReadBuffer()");
6324 /* Attach dst surface to dst fbo */
6325 dst_swapchain = get_swapchain(dst_surface);
6326 if (dst_swapchain) {
6329 TRACE("Destination surface %p is onscreen\n", dst_surface);
6330 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6333 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6334 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6335 glDrawBuffer(buffer);
6336 checkGLcall("glDrawBuffer()");
6338 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6339 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6341 TRACE("Destination surface %p is offscreen\n", dst_surface);
6343 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6344 if(!src_swapchain) {
6345 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6349 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6350 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6351 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6352 checkGLcall("glDrawBuffer()");
6354 glDisable(GL_SCISSOR_TEST);
6355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6358 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6359 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6360 checkGLcall("glBlitFramebuffer()");
6362 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6363 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6364 checkGLcall("glBlitFramebuffer()");
6367 if (This->render_offscreen) {
6368 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6370 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6371 checkGLcall("glBindFramebuffer()");
6374 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6375 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6376 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6377 glDrawBuffer(GL_BACK);
6378 checkGLcall("glDrawBuffer()");
6383 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6385 WINED3DVIEWPORT viewport;
6387 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6389 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6390 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6391 This, RenderTargetIndex, GL_LIMITS(buffers));
6392 return WINED3DERR_INVALIDCALL;
6395 /* MSDN says that null disables the render target
6396 but a device must always be associated with a render target
6397 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6399 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6402 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6403 FIXME("Trying to set render target 0 to NULL\n");
6404 return WINED3DERR_INVALIDCALL;
6406 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6407 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);
6408 return WINED3DERR_INVALIDCALL;
6411 /* If we are trying to set what we already have, don't bother */
6412 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6413 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6416 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6417 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6418 This->render_targets[RenderTargetIndex] = pRenderTarget;
6420 /* Render target 0 is special */
6421 if(RenderTargetIndex == 0) {
6422 /* Finally, reset the viewport as the MSDN states. */
6423 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6424 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6427 viewport.MaxZ = 1.0f;
6428 viewport.MinZ = 0.0f;
6429 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6430 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6431 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6435 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6437 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6438 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6440 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6445 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6447 HRESULT hr = WINED3D_OK;
6448 IWineD3DSurface *tmp;
6450 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6452 if (pNewZStencil == This->stencilBufferTarget) {
6453 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6455 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6456 * depending on the renter target implementation being used.
6457 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6458 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6459 * stencil buffer and incure an extra memory overhead
6460 ******************************************************/
6462 tmp = This->stencilBufferTarget;
6463 This->stencilBufferTarget = pNewZStencil;
6464 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6465 /* should we be calling the parent or the wined3d surface? */
6466 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6467 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6470 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6471 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6481 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6482 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6484 /* TODO: the use of Impl is deprecated. */
6485 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6486 WINED3DLOCKED_RECT lockedRect;
6488 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6490 /* some basic validation checks */
6491 if(This->cursorTexture) {
6492 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6494 glDeleteTextures(1, &This->cursorTexture);
6496 This->cursorTexture = 0;
6499 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6500 This->haveHardwareCursor = TRUE;
6502 This->haveHardwareCursor = FALSE;
6505 WINED3DLOCKED_RECT rect;
6507 /* MSDN: Cursor must be A8R8G8B8 */
6508 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6509 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6510 return WINED3DERR_INVALIDCALL;
6513 /* MSDN: Cursor must be smaller than the display mode */
6514 if(pSur->currentDesc.Width > This->ddraw_width ||
6515 pSur->currentDesc.Height > This->ddraw_height) {
6516 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);
6517 return WINED3DERR_INVALIDCALL;
6520 if (!This->haveHardwareCursor) {
6521 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6523 /* Do not store the surface's pointer because the application may
6524 * release it after setting the cursor image. Windows doesn't
6525 * addref the set surface, so we can't do this either without
6526 * creating circular refcount dependencies. Copy out the gl texture
6529 This->cursorWidth = pSur->currentDesc.Width;
6530 This->cursorHeight = pSur->currentDesc.Height;
6531 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6533 const GlPixelFormatDesc *glDesc;
6534 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6535 char *mem, *bits = (char *)rect.pBits;
6536 GLint intfmt = glDesc->glInternal;
6537 GLint format = glDesc->glFormat;
6538 GLint type = glDesc->glType;
6539 INT height = This->cursorHeight;
6540 INT width = This->cursorWidth;
6541 INT bpp = tableEntry->bpp;
6544 /* Reformat the texture memory (pitch and width can be
6546 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6547 for(i = 0; i < height; i++)
6548 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6549 IWineD3DSurface_UnlockRect(pCursorBitmap);
6552 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6553 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6554 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6557 /* Make sure that a proper texture unit is selected */
6558 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6559 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6560 checkGLcall("glActiveTextureARB");
6562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6563 /* Create a new cursor texture */
6564 glGenTextures(1, &This->cursorTexture);
6565 checkGLcall("glGenTextures");
6566 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6567 checkGLcall("glBindTexture");
6568 /* Copy the bitmap memory into the cursor texture */
6569 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6570 HeapFree(GetProcessHeap(), 0, mem);
6571 checkGLcall("glTexImage2D");
6573 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6574 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6575 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6582 FIXME("A cursor texture was not returned.\n");
6583 This->cursorTexture = 0;
6588 /* Draw a hardware cursor */
6589 ICONINFO cursorInfo;
6591 /* Create and clear maskBits because it is not needed for
6592 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6594 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6595 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6596 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6597 WINED3DLOCK_NO_DIRTY_UPDATE |
6598 WINED3DLOCK_READONLY
6600 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6601 pSur->currentDesc.Height);
6603 cursorInfo.fIcon = FALSE;
6604 cursorInfo.xHotspot = XHotSpot;
6605 cursorInfo.yHotspot = YHotSpot;
6606 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6607 pSur->currentDesc.Height, 1,
6609 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6610 pSur->currentDesc.Height, 1,
6611 32, lockedRect.pBits);
6612 IWineD3DSurface_UnlockRect(pCursorBitmap);
6613 /* Create our cursor and clean up. */
6614 cursor = CreateIconIndirect(&cursorInfo);
6616 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6617 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6618 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6619 This->hardwareCursor = cursor;
6620 HeapFree(GetProcessHeap(), 0, maskBits);
6624 This->xHotSpot = XHotSpot;
6625 This->yHotSpot = YHotSpot;
6629 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6631 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6633 This->xScreenSpace = XScreenSpace;
6634 This->yScreenSpace = YScreenSpace;
6640 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6642 BOOL oldVisible = This->bCursorVisible;
6645 TRACE("(%p) : visible(%d)\n", This, bShow);
6648 * When ShowCursor is first called it should make the cursor appear at the OS's last
6649 * known cursor position. Because of this, some applications just repetitively call
6650 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6653 This->xScreenSpace = pt.x;
6654 This->yScreenSpace = pt.y;
6656 if (This->haveHardwareCursor) {
6657 This->bCursorVisible = bShow;
6659 SetCursor(This->hardwareCursor);
6665 if (This->cursorTexture)
6666 This->bCursorVisible = bShow;
6672 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6674 IWineD3DResourceImpl *resource;
6675 TRACE("(%p) : state (%u)\n", This, This->state);
6677 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6678 switch (This->state) {
6681 case WINED3DERR_DEVICELOST:
6683 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6684 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6685 return WINED3DERR_DEVICENOTRESET;
6687 return WINED3DERR_DEVICELOST;
6689 case WINED3DERR_DRIVERINTERNALERROR:
6690 return WINED3DERR_DRIVERINTERNALERROR;
6694 return WINED3DERR_DRIVERINTERNALERROR;
6698 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6700 /** FIXME: Resource tracking needs to be done,
6701 * The closes we can do to this is set the priorities of all managed textures low
6702 * and then reset them.
6703 ***********************************************************/
6704 FIXME("(%p) : stub\n", This);
6708 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6709 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6711 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6712 if(surface->Flags & SFLAG_DIBSECTION) {
6713 /* Release the DC */
6714 SelectObject(surface->hDC, surface->dib.holdbitmap);
6715 DeleteDC(surface->hDC);
6716 /* Release the DIB section */
6717 DeleteObject(surface->dib.DIBsection);
6718 surface->dib.bitmap_data = NULL;
6719 surface->resource.allocatedMemory = NULL;
6720 surface->Flags &= ~SFLAG_DIBSECTION;
6722 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6723 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6724 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6725 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6726 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6728 surface->pow2Width = surface->pow2Height = 1;
6729 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6730 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6732 if(surface->glDescription.textureName) {
6733 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6735 glDeleteTextures(1, &surface->glDescription.textureName);
6737 surface->glDescription.textureName = 0;
6738 surface->Flags &= ~SFLAG_CLIENT;
6740 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6741 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6742 surface->Flags |= SFLAG_NONPOW2;
6744 surface->Flags &= ~SFLAG_NONPOW2;
6746 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6747 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6750 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6752 IWineD3DSwapChainImpl *swapchain;
6754 BOOL DisplayModeChanged = FALSE;
6755 WINED3DDISPLAYMODE mode;
6756 TRACE("(%p)\n", This);
6758 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6760 ERR("Failed to get the first implicit swapchain\n");
6764 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6765 * on an existing gl context, so there's no real need for recreation.
6767 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6769 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6771 TRACE("New params:\n");
6772 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6773 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6774 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6775 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6776 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6777 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6778 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6779 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6780 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6781 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6782 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6783 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6784 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6786 /* No special treatment of these parameters. Just store them */
6787 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6788 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6789 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6790 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6792 /* What to do about these? */
6793 if(pPresentationParameters->BackBufferCount != 0 &&
6794 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6795 ERR("Cannot change the back buffer count yet\n");
6797 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6798 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6799 ERR("Cannot change the back buffer format yet\n");
6801 if(pPresentationParameters->hDeviceWindow != NULL &&
6802 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6803 ERR("Cannot change the device window yet\n");
6805 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6806 ERR("What do do about a changed auto depth stencil parameter?\n");
6809 if(pPresentationParameters->Windowed) {
6810 mode.Width = swapchain->orig_width;
6811 mode.Height = swapchain->orig_height;
6812 mode.RefreshRate = 0;
6813 mode.Format = swapchain->presentParms.BackBufferFormat;
6815 mode.Width = pPresentationParameters->BackBufferWidth;
6816 mode.Height = pPresentationParameters->BackBufferHeight;
6817 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6818 mode.Format = swapchain->presentParms.BackBufferFormat;
6821 /* Should Width == 800 && Height == 0 set 800x600? */
6822 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6823 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6824 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6831 vp.Width = pPresentationParameters->BackBufferWidth;
6832 vp.Height = pPresentationParameters->BackBufferHeight;
6836 if(!pPresentationParameters->Windowed) {
6837 DisplayModeChanged = TRUE;
6839 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6840 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6842 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6843 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6844 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6847 /* Now set the new viewport */
6848 IWineD3DDevice_SetViewport(iface, &vp);
6851 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6852 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6853 DisplayModeChanged) {
6855 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6856 if(!pPresentationParameters->Windowed) {
6857 IWineD3DDevice_SetFullscreen(iface, TRUE);
6860 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6862 /* Switching out of fullscreen mode? First set the original res, then change the window */
6863 if(pPresentationParameters->Windowed) {
6864 IWineD3DDevice_SetFullscreen(iface, FALSE);
6866 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6869 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6873 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6875 /** FIXME: always true at the moment **/
6876 if(!bEnableDialogs) {
6877 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6883 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6885 TRACE("(%p) : pParameters %p\n", This, pParameters);
6887 *pParameters = This->createParms;
6891 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6892 IWineD3DSwapChain *swapchain;
6893 HRESULT hrc = WINED3D_OK;
6895 TRACE("Relaying to swapchain\n");
6897 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6898 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6899 IWineD3DSwapChain_Release(swapchain);
6904 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6905 IWineD3DSwapChain *swapchain;
6906 HRESULT hrc = WINED3D_OK;
6908 TRACE("Relaying to swapchain\n");
6910 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6911 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6912 IWineD3DSwapChain_Release(swapchain);
6918 /** ********************************************************
6919 * Notification functions
6920 ** ********************************************************/
6921 /** This function must be called in the release of a resource when ref == 0,
6922 * the contents of resource must still be correct,
6923 * any handels to other resource held by the caller must be closed
6924 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6925 *****************************************************/
6926 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6929 TRACE("(%p) : Adding Resource %p\n", This, resource);
6930 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6933 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6936 TRACE("(%p) : Removing resource %p\n", This, resource);
6938 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6942 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6946 TRACE("(%p) : resource %p\n", This, resource);
6947 switch(IWineD3DResource_GetType(resource)){
6948 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6949 case WINED3DRTYPE_SURFACE: {
6952 /* Cleanup any FBO attachments if d3d is enabled */
6953 if(This->d3d_initialized) {
6954 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6955 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6957 TRACE("Last active render target destroyed\n");
6958 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6959 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6960 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6961 * and the lastActiveRenderTarget member shouldn't matter
6964 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6965 TRACE("Activating primary back buffer\n");
6966 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6967 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6968 /* Single buffering environment */
6969 TRACE("Activating primary front buffer\n");
6970 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6972 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6973 /* Implicit render target destroyed, that means the device is being destroyed
6974 * whatever we set here, it shouldn't matter
6976 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6979 /* May happen during ddraw uninitialization */
6980 TRACE("Render target set, but swapchain does not exist!\n");
6981 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
6985 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6986 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6987 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6988 set_render_target_fbo(iface, i, NULL);
6989 This->fbo_color_attachments[i] = NULL;
6992 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6993 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6994 set_depth_stencil_fbo(iface, NULL);
6995 This->fbo_depth_attachment = NULL;
7001 case WINED3DRTYPE_TEXTURE:
7002 case WINED3DRTYPE_CUBETEXTURE:
7003 case WINED3DRTYPE_VOLUMETEXTURE:
7004 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7005 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7006 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7007 This->stateBlock->textures[counter] = NULL;
7009 if (This->updateStateBlock != This->stateBlock ){
7010 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7011 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7012 This->updateStateBlock->textures[counter] = NULL;
7017 case WINED3DRTYPE_VOLUME:
7018 /* TODO: nothing really? */
7020 case WINED3DRTYPE_VERTEXBUFFER:
7021 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7024 TRACE("Cleaning up stream pointers\n");
7026 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7027 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7028 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7030 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7031 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7032 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7033 This->updateStateBlock->streamSource[streamNumber] = 0;
7034 /* Set changed flag? */
7037 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) */
7038 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7039 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7040 This->stateBlock->streamSource[streamNumber] = 0;
7043 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7044 else { /* This shouldn't happen */
7045 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7052 case WINED3DRTYPE_INDEXBUFFER:
7053 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7054 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7055 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7056 This->updateStateBlock->pIndexData = NULL;
7059 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7060 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7061 This->stateBlock->pIndexData = NULL;
7067 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7072 /* Remove the resoruce from the resourceStore */
7073 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7075 TRACE("Resource released\n");
7079 /**********************************************************
7080 * IWineD3DDevice VTbl follows
7081 **********************************************************/
7083 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7085 /*** IUnknown methods ***/
7086 IWineD3DDeviceImpl_QueryInterface,
7087 IWineD3DDeviceImpl_AddRef,
7088 IWineD3DDeviceImpl_Release,
7089 /*** IWineD3DDevice methods ***/
7090 IWineD3DDeviceImpl_GetParent,
7091 /*** Creation methods**/
7092 IWineD3DDeviceImpl_CreateVertexBuffer,
7093 IWineD3DDeviceImpl_CreateIndexBuffer,
7094 IWineD3DDeviceImpl_CreateStateBlock,
7095 IWineD3DDeviceImpl_CreateSurface,
7096 IWineD3DDeviceImpl_CreateTexture,
7097 IWineD3DDeviceImpl_CreateVolumeTexture,
7098 IWineD3DDeviceImpl_CreateVolume,
7099 IWineD3DDeviceImpl_CreateCubeTexture,
7100 IWineD3DDeviceImpl_CreateQuery,
7101 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7102 IWineD3DDeviceImpl_CreateVertexDeclaration,
7103 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7104 IWineD3DDeviceImpl_CreateVertexShader,
7105 IWineD3DDeviceImpl_CreatePixelShader,
7106 IWineD3DDeviceImpl_CreatePalette,
7107 /*** Odd functions **/
7108 IWineD3DDeviceImpl_Init3D,
7109 IWineD3DDeviceImpl_Uninit3D,
7110 IWineD3DDeviceImpl_SetFullscreen,
7111 IWineD3DDeviceImpl_SetMultithreaded,
7112 IWineD3DDeviceImpl_EvictManagedResources,
7113 IWineD3DDeviceImpl_GetAvailableTextureMem,
7114 IWineD3DDeviceImpl_GetBackBuffer,
7115 IWineD3DDeviceImpl_GetCreationParameters,
7116 IWineD3DDeviceImpl_GetDeviceCaps,
7117 IWineD3DDeviceImpl_GetDirect3D,
7118 IWineD3DDeviceImpl_GetDisplayMode,
7119 IWineD3DDeviceImpl_SetDisplayMode,
7120 IWineD3DDeviceImpl_GetHWND,
7121 IWineD3DDeviceImpl_SetHWND,
7122 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7123 IWineD3DDeviceImpl_GetRasterStatus,
7124 IWineD3DDeviceImpl_GetSwapChain,
7125 IWineD3DDeviceImpl_Reset,
7126 IWineD3DDeviceImpl_SetDialogBoxMode,
7127 IWineD3DDeviceImpl_SetCursorProperties,
7128 IWineD3DDeviceImpl_SetCursorPosition,
7129 IWineD3DDeviceImpl_ShowCursor,
7130 IWineD3DDeviceImpl_TestCooperativeLevel,
7131 /*** Getters and setters **/
7132 IWineD3DDeviceImpl_SetClipPlane,
7133 IWineD3DDeviceImpl_GetClipPlane,
7134 IWineD3DDeviceImpl_SetClipStatus,
7135 IWineD3DDeviceImpl_GetClipStatus,
7136 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7137 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7138 IWineD3DDeviceImpl_SetDepthStencilSurface,
7139 IWineD3DDeviceImpl_GetDepthStencilSurface,
7140 IWineD3DDeviceImpl_SetFVF,
7141 IWineD3DDeviceImpl_GetFVF,
7142 IWineD3DDeviceImpl_SetGammaRamp,
7143 IWineD3DDeviceImpl_GetGammaRamp,
7144 IWineD3DDeviceImpl_SetIndices,
7145 IWineD3DDeviceImpl_GetIndices,
7146 IWineD3DDeviceImpl_SetBaseVertexIndex,
7147 IWineD3DDeviceImpl_GetBaseVertexIndex,
7148 IWineD3DDeviceImpl_SetLight,
7149 IWineD3DDeviceImpl_GetLight,
7150 IWineD3DDeviceImpl_SetLightEnable,
7151 IWineD3DDeviceImpl_GetLightEnable,
7152 IWineD3DDeviceImpl_SetMaterial,
7153 IWineD3DDeviceImpl_GetMaterial,
7154 IWineD3DDeviceImpl_SetNPatchMode,
7155 IWineD3DDeviceImpl_GetNPatchMode,
7156 IWineD3DDeviceImpl_SetPaletteEntries,
7157 IWineD3DDeviceImpl_GetPaletteEntries,
7158 IWineD3DDeviceImpl_SetPixelShader,
7159 IWineD3DDeviceImpl_GetPixelShader,
7160 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7161 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7162 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7163 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7164 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7165 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7166 IWineD3DDeviceImpl_SetRenderState,
7167 IWineD3DDeviceImpl_GetRenderState,
7168 IWineD3DDeviceImpl_SetRenderTarget,
7169 IWineD3DDeviceImpl_GetRenderTarget,
7170 IWineD3DDeviceImpl_SetFrontBackBuffers,
7171 IWineD3DDeviceImpl_SetSamplerState,
7172 IWineD3DDeviceImpl_GetSamplerState,
7173 IWineD3DDeviceImpl_SetScissorRect,
7174 IWineD3DDeviceImpl_GetScissorRect,
7175 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7176 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7177 IWineD3DDeviceImpl_SetStreamSource,
7178 IWineD3DDeviceImpl_GetStreamSource,
7179 IWineD3DDeviceImpl_SetStreamSourceFreq,
7180 IWineD3DDeviceImpl_GetStreamSourceFreq,
7181 IWineD3DDeviceImpl_SetTexture,
7182 IWineD3DDeviceImpl_GetTexture,
7183 IWineD3DDeviceImpl_SetTextureStageState,
7184 IWineD3DDeviceImpl_GetTextureStageState,
7185 IWineD3DDeviceImpl_SetTransform,
7186 IWineD3DDeviceImpl_GetTransform,
7187 IWineD3DDeviceImpl_SetVertexDeclaration,
7188 IWineD3DDeviceImpl_GetVertexDeclaration,
7189 IWineD3DDeviceImpl_SetVertexShader,
7190 IWineD3DDeviceImpl_GetVertexShader,
7191 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7192 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7193 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7194 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7195 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7196 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7197 IWineD3DDeviceImpl_SetViewport,
7198 IWineD3DDeviceImpl_GetViewport,
7199 IWineD3DDeviceImpl_MultiplyTransform,
7200 IWineD3DDeviceImpl_ValidateDevice,
7201 IWineD3DDeviceImpl_ProcessVertices,
7202 /*** State block ***/
7203 IWineD3DDeviceImpl_BeginStateBlock,
7204 IWineD3DDeviceImpl_EndStateBlock,
7205 /*** Scene management ***/
7206 IWineD3DDeviceImpl_BeginScene,
7207 IWineD3DDeviceImpl_EndScene,
7208 IWineD3DDeviceImpl_Present,
7209 IWineD3DDeviceImpl_Clear,
7211 IWineD3DDeviceImpl_DrawPrimitive,
7212 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7213 IWineD3DDeviceImpl_DrawPrimitiveUP,
7214 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7215 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7216 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7217 IWineD3DDeviceImpl_DrawRectPatch,
7218 IWineD3DDeviceImpl_DrawTriPatch,
7219 IWineD3DDeviceImpl_DeletePatch,
7220 IWineD3DDeviceImpl_ColorFill,
7221 IWineD3DDeviceImpl_UpdateTexture,
7222 IWineD3DDeviceImpl_UpdateSurface,
7223 IWineD3DDeviceImpl_GetFrontBufferData,
7224 /*** object tracking ***/
7225 IWineD3DDeviceImpl_ResourceReleased
7229 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7230 WINED3DRS_ALPHABLENDENABLE ,
7231 WINED3DRS_ALPHAFUNC ,
7232 WINED3DRS_ALPHAREF ,
7233 WINED3DRS_ALPHATESTENABLE ,
7235 WINED3DRS_COLORWRITEENABLE ,
7236 WINED3DRS_DESTBLEND ,
7237 WINED3DRS_DITHERENABLE ,
7238 WINED3DRS_FILLMODE ,
7239 WINED3DRS_FOGDENSITY ,
7241 WINED3DRS_FOGSTART ,
7242 WINED3DRS_LASTPIXEL ,
7243 WINED3DRS_SHADEMODE ,
7244 WINED3DRS_SRCBLEND ,
7245 WINED3DRS_STENCILENABLE ,
7246 WINED3DRS_STENCILFAIL ,
7247 WINED3DRS_STENCILFUNC ,
7248 WINED3DRS_STENCILMASK ,
7249 WINED3DRS_STENCILPASS ,
7250 WINED3DRS_STENCILREF ,
7251 WINED3DRS_STENCILWRITEMASK ,
7252 WINED3DRS_STENCILZFAIL ,
7253 WINED3DRS_TEXTUREFACTOR ,
7264 WINED3DRS_ZWRITEENABLE
7267 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7268 WINED3DTSS_ADDRESSW ,
7269 WINED3DTSS_ALPHAARG0 ,
7270 WINED3DTSS_ALPHAARG1 ,
7271 WINED3DTSS_ALPHAARG2 ,
7272 WINED3DTSS_ALPHAOP ,
7273 WINED3DTSS_BUMPENVLOFFSET ,
7274 WINED3DTSS_BUMPENVLSCALE ,
7275 WINED3DTSS_BUMPENVMAT00 ,
7276 WINED3DTSS_BUMPENVMAT01 ,
7277 WINED3DTSS_BUMPENVMAT10 ,
7278 WINED3DTSS_BUMPENVMAT11 ,
7279 WINED3DTSS_COLORARG0 ,
7280 WINED3DTSS_COLORARG1 ,
7281 WINED3DTSS_COLORARG2 ,
7282 WINED3DTSS_COLOROP ,
7283 WINED3DTSS_RESULTARG ,
7284 WINED3DTSS_TEXCOORDINDEX ,
7285 WINED3DTSS_TEXTURETRANSFORMFLAGS
7288 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7289 WINED3DSAMP_ADDRESSU ,
7290 WINED3DSAMP_ADDRESSV ,
7291 WINED3DSAMP_ADDRESSW ,
7292 WINED3DSAMP_BORDERCOLOR ,
7293 WINED3DSAMP_MAGFILTER ,
7294 WINED3DSAMP_MINFILTER ,
7295 WINED3DSAMP_MIPFILTER ,
7296 WINED3DSAMP_MIPMAPLODBIAS ,
7297 WINED3DSAMP_MAXMIPLEVEL ,
7298 WINED3DSAMP_MAXANISOTROPY ,
7299 WINED3DSAMP_SRGBTEXTURE ,
7300 WINED3DSAMP_ELEMENTINDEX
7303 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7305 WINED3DRS_AMBIENTMATERIALSOURCE ,
7306 WINED3DRS_CLIPPING ,
7307 WINED3DRS_CLIPPLANEENABLE ,
7308 WINED3DRS_COLORVERTEX ,
7309 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7310 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7311 WINED3DRS_FOGDENSITY ,
7313 WINED3DRS_FOGSTART ,
7314 WINED3DRS_FOGTABLEMODE ,
7315 WINED3DRS_FOGVERTEXMODE ,
7316 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7317 WINED3DRS_LIGHTING ,
7318 WINED3DRS_LOCALVIEWER ,
7319 WINED3DRS_MULTISAMPLEANTIALIAS ,
7320 WINED3DRS_MULTISAMPLEMASK ,
7321 WINED3DRS_NORMALIZENORMALS ,
7322 WINED3DRS_PATCHEDGESTYLE ,
7323 WINED3DRS_POINTSCALE_A ,
7324 WINED3DRS_POINTSCALE_B ,
7325 WINED3DRS_POINTSCALE_C ,
7326 WINED3DRS_POINTSCALEENABLE ,
7327 WINED3DRS_POINTSIZE ,
7328 WINED3DRS_POINTSIZE_MAX ,
7329 WINED3DRS_POINTSIZE_MIN ,
7330 WINED3DRS_POINTSPRITEENABLE ,
7331 WINED3DRS_RANGEFOGENABLE ,
7332 WINED3DRS_SPECULARMATERIALSOURCE ,
7333 WINED3DRS_TWEENFACTOR ,
7334 WINED3DRS_VERTEXBLEND ,
7335 WINED3DRS_CULLMODE ,
7339 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7340 WINED3DTSS_TEXCOORDINDEX ,
7341 WINED3DTSS_TEXTURETRANSFORMFLAGS
7344 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7345 WINED3DSAMP_DMAPOFFSET
7348 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7349 DWORD rep = StateTable[state].representative;
7353 WineD3DContext *context;
7356 for(i = 0; i < This->numContexts; i++) {
7357 context = This->contexts[i];
7358 if(isStateDirty(context, rep)) continue;
7360 context->dirtyArray[context->numDirtyEntries++] = rep;
7363 context->isStateDirty[idx] |= (1 << shift);
7367 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7368 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7369 /* The drawable size of a pbuffer render target is the current pbuffer size
7371 *width = dev->pbufferWidth;
7372 *height = dev->pbufferHeight;
7375 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7376 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7378 *width = This->pow2Width;
7379 *height = This->pow2Height;
7382 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7383 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7384 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7385 * current context's drawable, which is the size of the back buffer of the swapchain
7386 * the active context belongs to. The back buffer of the swapchain is stored as the
7387 * surface the context belongs to.
7389 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7390 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;