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; \
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 (This->resources != NULL ) {
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;
881 /** FIXME: add support for real non-power-two if it's provided by the video card **/
882 /* Precalculated scaling for 'faked' non power of two texture coords */
883 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
884 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
885 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
887 /* Calculate levels for mip mapping */
888 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
889 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
890 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
891 return WINED3DERR_INVALIDCALL;
894 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
895 return WINED3DERR_INVALIDCALL;
897 object->baseTexture.levels = 1;
898 } else if (Levels == 0) {
899 TRACE("calculating levels %d\n", object->baseTexture.levels);
900 object->baseTexture.levels++;
903 while (tmpW > 1 || tmpH > 1) {
904 tmpW = max(1, tmpW >> 1);
905 tmpH = max(1, tmpH >> 1);
906 object->baseTexture.levels++;
908 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
911 /* Generate all the surfaces */
914 for (i = 0; i < object->baseTexture.levels; i++)
916 /* use the callback to create the texture surface */
917 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
918 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
919 FIXME("Failed to create surface %p\n", object);
921 object->surfaces[i] = NULL;
922 IWineD3DTexture_Release((IWineD3DTexture *)object);
928 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
929 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
930 /* calculate the next mipmap level */
931 tmpW = max(1, tmpW >> 1);
932 tmpH = max(1, tmpH >> 1);
934 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
936 TRACE("(%p) : Created texture %p\n", This, object);
940 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
941 UINT Width, UINT Height, UINT Depth,
942 UINT Levels, DWORD Usage,
943 WINED3DFORMAT Format, WINED3DPOOL Pool,
944 IWineD3DVolumeTexture **ppVolumeTexture,
945 HANDLE *pSharedHandle, IUnknown *parent,
946 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
949 IWineD3DVolumeTextureImpl *object;
954 const GlPixelFormatDesc *glDesc;
955 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
957 /* TODO: It should only be possible to create textures for formats
958 that are reported as supported */
959 if (WINED3DFMT_UNKNOWN >= Format) {
960 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
961 return WINED3DERR_INVALIDCALL;
964 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
965 D3DINITIALIZEBASETEXTURE(object->baseTexture);
967 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
968 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
970 object->width = Width;
971 object->height = Height;
972 object->depth = Depth;
974 /* Calculate levels for mip mapping */
975 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
976 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
977 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
978 return WINED3DERR_INVALIDCALL;
981 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
982 return WINED3DERR_INVALIDCALL;
985 } else if (Levels == 0) {
986 object->baseTexture.levels++;
990 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
991 tmpW = max(1, tmpW >> 1);
992 tmpH = max(1, tmpH >> 1);
993 tmpD = max(1, tmpD >> 1);
994 object->baseTexture.levels++;
996 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
999 /* Generate all the surfaces */
1004 for (i = 0; i < object->baseTexture.levels; i++)
1007 /* Create the volume */
1008 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1009 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1012 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1013 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1014 *ppVolumeTexture = NULL;
1018 /* Set its container to this object */
1019 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1021 /* calcualte the next mipmap level */
1022 tmpW = max(1, tmpW >> 1);
1023 tmpH = max(1, tmpH >> 1);
1024 tmpD = max(1, tmpD >> 1);
1026 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1028 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1029 TRACE("(%p) : Created volume texture %p\n", This, object);
1033 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1034 UINT Width, UINT Height, UINT Depth,
1036 WINED3DFORMAT Format, WINED3DPOOL Pool,
1037 IWineD3DVolume** ppVolume,
1038 HANDLE* pSharedHandle, IUnknown *parent) {
1040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1041 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1042 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1044 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1046 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1047 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1049 object->currentDesc.Width = Width;
1050 object->currentDesc.Height = Height;
1051 object->currentDesc.Depth = Depth;
1052 object->bytesPerPixel = formatDesc->bpp;
1054 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1055 object->lockable = TRUE;
1056 object->locked = FALSE;
1057 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1058 object->dirty = TRUE;
1060 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1063 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1064 UINT Levels, DWORD Usage,
1065 WINED3DFORMAT Format, WINED3DPOOL Pool,
1066 IWineD3DCubeTexture **ppCubeTexture,
1067 HANDLE *pSharedHandle, IUnknown *parent,
1068 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1071 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1075 unsigned int pow2EdgeLength = EdgeLength;
1076 const GlPixelFormatDesc *glDesc;
1077 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1079 /* TODO: It should only be possible to create textures for formats
1080 that are reported as supported */
1081 if (WINED3DFMT_UNKNOWN >= Format) {
1082 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1083 return WINED3DERR_INVALIDCALL;
1086 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1087 WARN("(%p) : Tried to create not supported cube texture\n", This);
1088 return WINED3DERR_INVALIDCALL;
1091 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1092 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1094 TRACE("(%p) Create Cube Texture\n", This);
1096 /** Non-power2 support **/
1098 /* Find the nearest pow2 match */
1100 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1102 object->edgeLength = EdgeLength;
1103 /* TODO: support for native non-power 2 */
1104 /* Precalculated scaling for 'faked' non power of two texture coords */
1105 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1107 /* Calculate levels for mip mapping */
1108 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1109 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1110 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1111 HeapFree(GetProcessHeap(), 0, object);
1112 *ppCubeTexture = NULL;
1114 return WINED3DERR_INVALIDCALL;
1117 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1118 HeapFree(GetProcessHeap(), 0, object);
1119 *ppCubeTexture = NULL;
1121 return WINED3DERR_INVALIDCALL;
1124 } else if (Levels == 0) {
1125 object->baseTexture.levels++;
1128 tmpW = max(1, tmpW >> 1);
1129 object->baseTexture.levels++;
1131 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1134 /* Generate all the surfaces */
1136 for (i = 0; i < object->baseTexture.levels; i++) {
1138 /* Create the 6 faces */
1139 for (j = 0; j < 6; j++) {
1141 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1142 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1144 if(hr!= WINED3D_OK) {
1148 for (l = 0; l < j; l++) {
1149 IWineD3DSurface_Release(object->surfaces[l][i]);
1151 for (k = 0; k < i; k++) {
1152 for (l = 0; l < 6; l++) {
1153 IWineD3DSurface_Release(object->surfaces[l][k]);
1157 FIXME("(%p) Failed to create surface\n",object);
1158 HeapFree(GetProcessHeap(),0,object);
1159 *ppCubeTexture = NULL;
1162 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1163 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1165 tmpW = max(1, tmpW >> 1);
1167 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1169 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1170 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1174 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1176 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1177 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1179 /* Just a check to see if we support this type of query */
1181 case WINED3DQUERYTYPE_OCCLUSION:
1182 TRACE("(%p) occlusion query\n", This);
1183 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1186 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1189 case WINED3DQUERYTYPE_EVENT:
1190 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1191 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1192 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1194 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1199 case WINED3DQUERYTYPE_VCACHE:
1200 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1201 case WINED3DQUERYTYPE_VERTEXSTATS:
1202 case WINED3DQUERYTYPE_TIMESTAMP:
1203 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1204 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1205 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1206 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1207 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1208 case WINED3DQUERYTYPE_PIXELTIMINGS:
1209 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1210 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1212 FIXME("(%p) Unhandled query type %d\n", This, Type);
1214 if(NULL == ppQuery || hr != WINED3D_OK) {
1218 D3DCREATEOBJECTINSTANCE(object, Query)
1219 object->type = Type;
1220 /* allocated the 'extended' data based on the type of query requested */
1222 case WINED3DQUERYTYPE_OCCLUSION:
1223 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1224 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1226 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1227 TRACE("(%p) Allocating data for an occlusion query\n", This);
1228 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1231 case WINED3DQUERYTYPE_EVENT:
1232 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1233 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1235 if(GL_SUPPORT(APPLE_FENCE)) {
1236 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1237 checkGLcall("glGenFencesAPPLE");
1238 } else if(GL_SUPPORT(NV_FENCE)) {
1239 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1240 checkGLcall("glGenFencesNV");
1244 case WINED3DQUERYTYPE_VCACHE:
1245 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1246 case WINED3DQUERYTYPE_VERTEXSTATS:
1247 case WINED3DQUERYTYPE_TIMESTAMP:
1248 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1249 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1250 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1251 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1252 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1253 case WINED3DQUERYTYPE_PIXELTIMINGS:
1254 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1255 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1257 object->extendedData = 0;
1258 FIXME("(%p) Unhandled query type %d\n",This , Type);
1260 TRACE("(%p) : Created Query %p\n", This, object);
1264 /*****************************************************************************
1265 * IWineD3DDeviceImpl_SetupFullscreenWindow
1267 * Helper function that modifies a HWND's Style and ExStyle for proper
1271 * iface: Pointer to the IWineD3DDevice interface
1272 * window: Window to setup
1274 *****************************************************************************/
1275 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1278 LONG style, exStyle;
1279 /* Don't do anything if an original style is stored.
1280 * That shouldn't happen
1282 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1283 if (This->style || This->exStyle) {
1284 ERR("(%p): Want to change the window parameters of HWND %p, but "
1285 "another style is stored for restoration afterwards\n", This, window);
1288 /* Get the parameters and save them */
1289 style = GetWindowLongW(window, GWL_STYLE);
1290 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1291 This->style = style;
1292 This->exStyle = exStyle;
1294 /* Filter out window decorations */
1295 style &= ~WS_CAPTION;
1296 style &= ~WS_THICKFRAME;
1297 exStyle &= ~WS_EX_WINDOWEDGE;
1298 exStyle &= ~WS_EX_CLIENTEDGE;
1300 /* Make sure the window is managed, otherwise we won't get keyboard input */
1301 style |= WS_POPUP | WS_SYSMENU;
1303 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1304 This->style, This->exStyle, style, exStyle);
1306 SetWindowLongW(window, GWL_STYLE, style);
1307 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1309 /* Inform the window about the update. */
1310 SetWindowPos(window, HWND_TOP, 0, 0,
1311 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1312 ShowWindow(window, SW_NORMAL);
1315 /*****************************************************************************
1316 * IWineD3DDeviceImpl_RestoreWindow
1318 * Helper function that restores a windows' properties when taking it out
1319 * of fullscreen mode
1322 * iface: Pointer to the IWineD3DDevice interface
1323 * window: Window to setup
1325 *****************************************************************************/
1326 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1329 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1330 * switch, do nothing
1332 if (!This->style && !This->exStyle) return;
1334 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1335 This, window, This->style, This->exStyle);
1337 SetWindowLongW(window, GWL_STYLE, This->style);
1338 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1340 /* Delete the old values */
1344 /* Inform the window about the update */
1345 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1346 0, 0, 0, 0, /* Pos, Size, ignored */
1347 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1350 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1351 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1353 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1354 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1358 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1359 HRESULT hr = WINED3D_OK;
1360 IUnknown *bufferParent;
1362 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1364 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1365 * does a device hold a reference to a swap chain giving them a lifetime of the device
1366 * or does the swap chain notify the device of its destruction.
1367 *******************************/
1369 /* Check the params */
1370 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1371 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1372 return WINED3DERR_INVALIDCALL;
1373 } else if (pPresentationParameters->BackBufferCount > 1) {
1374 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");
1377 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1379 /*********************
1380 * Lookup the window Handle and the relating X window handle
1381 ********************/
1383 /* Setup hwnd we are using, plus which display this equates to */
1384 object->win_handle = pPresentationParameters->hDeviceWindow;
1385 if (!object->win_handle) {
1386 object->win_handle = This->createParms.hFocusWindow;
1389 hDc = GetDC(object->win_handle);
1390 TRACE("Using hDc %p\n", hDc);
1393 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1394 return WINED3DERR_NOTAVAILABLE;
1397 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1398 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1399 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1400 ReleaseDC(object->win_handle, hDc);
1402 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1403 * then the corresponding dimension of the client area of the hDeviceWindow
1404 * (or the focus window, if hDeviceWindow is NULL) is taken.
1405 **********************/
1407 if (pPresentationParameters->Windowed &&
1408 ((pPresentationParameters->BackBufferWidth == 0) ||
1409 (pPresentationParameters->BackBufferHeight == 0) ||
1410 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1413 GetClientRect(object->win_handle, &Rect);
1415 if (pPresentationParameters->BackBufferWidth == 0) {
1416 pPresentationParameters->BackBufferWidth = Rect.right;
1417 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1419 if (pPresentationParameters->BackBufferHeight == 0) {
1420 pPresentationParameters->BackBufferHeight = Rect.bottom;
1421 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1423 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1424 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1425 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1429 /* Put the correct figures in the presentation parameters */
1430 TRACE("Copying across presentation parameters\n");
1431 object->presentParms = *pPresentationParameters;
1433 TRACE("calling rendertarget CB\n");
1434 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1436 object->presentParms.BackBufferWidth,
1437 object->presentParms.BackBufferHeight,
1438 object->presentParms.BackBufferFormat,
1439 object->presentParms.MultiSampleType,
1440 object->presentParms.MultiSampleQuality,
1441 TRUE /* Lockable */,
1442 &object->frontBuffer,
1443 NULL /* pShared (always null)*/);
1444 if (object->frontBuffer != NULL) {
1445 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1446 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1448 ERR("Failed to create the front buffer\n");
1453 * Create an opengl context for the display visual
1454 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1455 * use different properties after that point in time. FIXME: How to handle when requested format
1456 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1457 * it chooses is identical to the one already being used!
1458 **********************************/
1459 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1461 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1462 if(!object->context)
1463 return E_OUTOFMEMORY;
1464 object->num_contexts = 1;
1466 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1467 if (!object->context[0]) {
1468 ERR("Failed to create a new context\n");
1469 hr = WINED3DERR_NOTAVAILABLE;
1472 TRACE("Context created (HWND=%p, glContext=%p)\n",
1473 object->win_handle, object->context[0]->glCtx);
1476 /*********************
1477 * Windowed / Fullscreen
1478 *******************/
1481 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1482 * so we should really check to see if there is a fullscreen swapchain already
1483 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1484 **************************************/
1486 if (!pPresentationParameters->Windowed) {
1493 /* Get info on the current display setup */
1495 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1498 /* Change the display settings */
1499 memset(&devmode, 0, sizeof(devmode));
1500 devmode.dmSize = sizeof(devmode);
1501 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1502 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1503 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1504 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1505 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1507 /* For GetDisplayMode */
1508 This->ddraw_width = devmode.dmPelsWidth;
1509 This->ddraw_height = devmode.dmPelsHeight;
1510 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1512 IWineD3DDevice_SetFullscreen(iface, TRUE);
1514 /* And finally clip mouse to our screen */
1515 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1516 ClipCursor(&clip_rc);
1519 /*********************
1520 * Create the back, front and stencil buffers
1521 *******************/
1522 if(object->presentParms.BackBufferCount > 0) {
1525 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1526 if(!object->backBuffer) {
1527 ERR("Out of memory\n");
1532 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1533 TRACE("calling rendertarget CB\n");
1534 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1536 object->presentParms.BackBufferWidth,
1537 object->presentParms.BackBufferHeight,
1538 object->presentParms.BackBufferFormat,
1539 object->presentParms.MultiSampleType,
1540 object->presentParms.MultiSampleQuality,
1541 TRUE /* Lockable */,
1542 &object->backBuffer[i],
1543 NULL /* pShared (always null)*/);
1544 if(hr == WINED3D_OK && object->backBuffer[i]) {
1545 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1547 ERR("Cannot create new back buffer\n");
1551 glDrawBuffer(GL_BACK);
1552 checkGLcall("glDrawBuffer(GL_BACK)");
1556 object->backBuffer = NULL;
1558 /* Single buffering - draw to front buffer */
1560 glDrawBuffer(GL_FRONT);
1561 checkGLcall("glDrawBuffer(GL_FRONT)");
1565 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1566 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1567 TRACE("Creating depth stencil buffer\n");
1568 if (This->depthStencilBuffer == NULL ) {
1569 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1571 object->presentParms.BackBufferWidth,
1572 object->presentParms.BackBufferHeight,
1573 object->presentParms.AutoDepthStencilFormat,
1574 object->presentParms.MultiSampleType,
1575 object->presentParms.MultiSampleQuality,
1576 FALSE /* FIXME: Discard */,
1577 &This->depthStencilBuffer,
1578 NULL /* pShared (always null)*/ );
1579 if (This->depthStencilBuffer != NULL)
1580 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1583 /** TODO: A check on width, height and multisample types
1584 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1585 ****************************/
1586 object->wantsDepthStencilBuffer = TRUE;
1588 object->wantsDepthStencilBuffer = FALSE;
1591 TRACE("Created swapchain %p\n", object);
1592 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1596 if (object->backBuffer) {
1598 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1599 if(object->backBuffer[i]) {
1600 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1601 IUnknown_Release(bufferParent); /* once for the get parent */
1602 if (IUnknown_Release(bufferParent) > 0) {
1603 FIXME("(%p) Something's still holding the back buffer\n",This);
1607 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1608 object->backBuffer = NULL;
1610 if(object->context[0])
1611 DestroyContext(This, object->context[0]);
1612 if(object->frontBuffer) {
1613 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1614 IUnknown_Release(bufferParent); /* once for the get parent */
1615 if (IUnknown_Release(bufferParent) > 0) {
1616 FIXME("(%p) Something's still holding the front buffer\n",This);
1619 HeapFree(GetProcessHeap(), 0, object);
1623 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1624 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1626 TRACE("(%p)\n", This);
1628 return This->NumberOfSwapChains;
1631 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1633 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1635 if(iSwapChain < This->NumberOfSwapChains) {
1636 *pSwapChain = This->swapchains[iSwapChain];
1637 IWineD3DSwapChain_AddRef(*pSwapChain);
1638 TRACE("(%p) returning %p\n", This, *pSwapChain);
1641 TRACE("Swapchain out of range\n");
1643 return WINED3DERR_INVALIDCALL;
1648 * Vertex Declaration
1650 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1651 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1653 IWineD3DVertexDeclarationImpl *object = NULL;
1654 HRESULT hr = WINED3D_OK;
1656 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1657 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1659 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1661 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1666 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1668 unsigned int idx, idx2;
1669 unsigned int offset;
1670 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1671 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1672 BOOL has_blend_idx = has_blend &&
1673 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1674 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1675 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1676 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1677 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1678 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1679 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1681 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1682 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1684 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1685 WINED3DVERTEXELEMENT *elements = NULL;
1688 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1689 if (has_blend_idx) num_blends--;
1691 /* Compute declaration size */
1692 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1693 has_psize + has_diffuse + has_specular + num_textures + 1;
1695 /* convert the declaration */
1696 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1700 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1703 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1704 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1705 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1708 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1709 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1711 elements[idx].UsageIndex = 0;
1714 if (has_blend && (num_blends > 0)) {
1715 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1716 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1718 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1719 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1720 elements[idx].UsageIndex = 0;
1723 if (has_blend_idx) {
1724 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1725 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1726 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1727 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1728 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1730 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1731 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1732 elements[idx].UsageIndex = 0;
1736 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1737 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1738 elements[idx].UsageIndex = 0;
1742 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1743 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1744 elements[idx].UsageIndex = 0;
1748 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1749 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1750 elements[idx].UsageIndex = 0;
1754 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1755 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1756 elements[idx].UsageIndex = 1;
1759 for (idx2 = 0; idx2 < num_textures; idx2++) {
1760 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1761 switch (numcoords) {
1762 case WINED3DFVF_TEXTUREFORMAT1:
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1765 case WINED3DFVF_TEXTUREFORMAT2:
1766 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1768 case WINED3DFVF_TEXTUREFORMAT3:
1769 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1771 case WINED3DFVF_TEXTUREFORMAT4:
1772 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1775 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1776 elements[idx].UsageIndex = idx2;
1780 /* Now compute offsets, and initialize the rest of the fields */
1781 for (idx = 0, offset = 0; idx < size-1; idx++) {
1782 elements[idx].Stream = 0;
1783 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1784 elements[idx].Offset = offset;
1785 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1788 *ppVertexElements = elements;
1792 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1793 WINED3DVERTEXELEMENT* elements = NULL;
1797 size = ConvertFvfToDeclaration(Fvf, &elements);
1798 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1800 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1801 HeapFree(GetProcessHeap(), 0, elements);
1802 if (hr != S_OK) return hr;
1807 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1808 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1810 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1811 HRESULT hr = WINED3D_OK;
1812 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1813 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1815 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1817 if (vertex_declaration) {
1818 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1821 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1823 if (WINED3D_OK != hr) {
1824 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1825 IWineD3DVertexShader_Release(*ppVertexShader);
1826 return WINED3DERR_INVALIDCALL;
1832 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1834 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1835 HRESULT hr = WINED3D_OK;
1837 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1838 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1839 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1840 if (WINED3D_OK == hr) {
1841 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1843 WARN("(%p) : Failed to create pixel shader\n", This);
1849 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1851 IWineD3DPaletteImpl *object;
1853 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1855 /* Create the new object */
1856 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1858 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1859 return E_OUTOFMEMORY;
1862 object->lpVtbl = &IWineD3DPalette_Vtbl;
1864 object->Flags = Flags;
1865 object->parent = Parent;
1866 object->wineD3DDevice = This;
1867 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1869 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1872 HeapFree( GetProcessHeap(), 0, object);
1873 return E_OUTOFMEMORY;
1876 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1878 IWineD3DPalette_Release((IWineD3DPalette *) object);
1882 *Palette = (IWineD3DPalette *) object;
1887 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1891 HDC dcb = NULL, dcs = NULL;
1892 WINEDDCOLORKEY colorkey;
1894 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1897 GetObjectA(hbm, sizeof(BITMAP), &bm);
1898 dcb = CreateCompatibleDC(NULL);
1900 SelectObject(dcb, hbm);
1904 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1905 * couldn't be loaded
1907 memset(&bm, 0, sizeof(bm));
1912 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1913 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1914 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1916 ERR("Wine logo requested, but failed to create surface\n");
1921 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1922 if(FAILED(hr)) goto out;
1923 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1924 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1926 colorkey.dwColorSpaceLowValue = 0;
1927 colorkey.dwColorSpaceHighValue = 0;
1928 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1930 /* Fill the surface with a white color to show that wined3d is there */
1931 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1944 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1946 IWineD3DSwapChainImpl *swapchain;
1950 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1951 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1953 /* TODO: Test if OpenGL is compiled in and loaded */
1955 TRACE("(%p) : Creating stateblock\n", This);
1956 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1957 hr = IWineD3DDevice_CreateStateBlock(iface,
1959 (IWineD3DStateBlock **)&This->stateBlock,
1961 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1962 WARN("Failed to create stateblock\n");
1965 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1966 This->updateStateBlock = This->stateBlock;
1967 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1969 hr = allocate_shader_constants(This->updateStateBlock);
1970 if (WINED3D_OK != hr) {
1974 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1975 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1976 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1978 /* Initialize the texture unit mapping to a 1:1 mapping */
1979 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1980 if (state < GL_LIMITS(fragment_samplers)) {
1981 This->texUnitMap[state] = state;
1982 This->rev_tex_unit_map[state] = state;
1984 This->texUnitMap[state] = -1;
1985 This->rev_tex_unit_map[state] = -1;
1989 /* Setup the implicit swapchain */
1990 TRACE("Creating implicit swapchain\n");
1991 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1992 if (FAILED(hr) || !swapchain) {
1993 WARN("Failed to create implicit swapchain\n");
1997 This->NumberOfSwapChains = 1;
1998 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1999 if(!This->swapchains) {
2000 ERR("Out of memory!\n");
2003 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2005 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
2007 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2008 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2009 This->render_targets[0] = swapchain->backBuffer[0];
2010 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2013 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2014 This->render_targets[0] = swapchain->frontBuffer;
2015 This->lastActiveRenderTarget = swapchain->frontBuffer;
2017 IWineD3DSurface_AddRef(This->render_targets[0]);
2018 This->activeContext = swapchain->context[0];
2019 This->lastThread = GetCurrentThreadId();
2021 /* Depth Stencil support */
2022 This->stencilBufferTarget = This->depthStencilBuffer;
2023 if (NULL != This->stencilBufferTarget) {
2024 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2027 /* Set up some starting GL setup */
2030 /* Setup all the devices defaults */
2031 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2033 IWineD3DImpl_CheckGraphicsMemory();
2036 { /* Set a default viewport */
2040 vp.Width = pPresentationParameters->BackBufferWidth;
2041 vp.Height = pPresentationParameters->BackBufferHeight;
2044 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2047 /* Initialize the current view state */
2048 This->view_ident = 1;
2049 This->contexts[0]->last_was_rhw = 0;
2050 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2051 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2053 switch(wined3d_settings.offscreen_rendering_mode) {
2056 This->offscreenBuffer = GL_BACK;
2059 case ORM_BACKBUFFER:
2061 if(GL_LIMITS(aux_buffers) > 0) {
2062 TRACE("Using auxilliary buffer for offscreen rendering\n");
2063 This->offscreenBuffer = GL_AUX0;
2065 TRACE("Using back buffer for offscreen rendering\n");
2066 This->offscreenBuffer = GL_BACK;
2071 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2074 /* Clear the screen */
2075 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2076 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2079 This->d3d_initialized = TRUE;
2081 if(wined3d_settings.logo) {
2082 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2087 HeapFree(GetProcessHeap(), 0, This->render_targets);
2088 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2089 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2090 HeapFree(GetProcessHeap(), 0, This->swapchains);
2091 This->NumberOfSwapChains = 0;
2093 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2095 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2096 if(This->stateBlock) {
2097 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2098 This->stateBlock = NULL;
2103 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2107 TRACE("(%p)\n", This);
2109 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2111 /* I don't think that the interface guarants that the device is destroyed from the same thread
2112 * it was created. Thus make sure a context is active for the glDelete* calls
2114 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2116 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2118 TRACE("Deleting high order patches\n");
2119 for(i = 0; i < PATCHMAP_SIZE; i++) {
2120 struct list *e1, *e2;
2121 struct WineD3DRectPatch *patch;
2122 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2123 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2124 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2128 /* Delete the palette conversion shader if it is around */
2129 if(This->paletteConversionShader) {
2130 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2133 /* Delete the pbuffer context if there is any */
2134 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2136 /* Delete the mouse cursor texture */
2137 if(This->cursorTexture) {
2139 glDeleteTextures(1, &This->cursorTexture);
2141 This->cursorTexture = 0;
2144 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2145 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2147 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2148 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2151 /* Release the update stateblock */
2152 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2153 if(This->updateStateBlock != This->stateBlock)
2154 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2156 This->updateStateBlock = NULL;
2158 { /* because were not doing proper internal refcounts releasing the primary state block
2159 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2160 to set this->stateBlock = NULL; first */
2161 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2162 This->stateBlock = NULL;
2164 /* Release the stateblock */
2165 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2166 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2170 /* Release the buffers (with sanity checks)*/
2171 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2172 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2173 if(This->depthStencilBuffer != This->stencilBufferTarget)
2174 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2176 This->stencilBufferTarget = NULL;
2178 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2179 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2180 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2182 TRACE("Setting rendertarget to NULL\n");
2183 This->render_targets[0] = NULL;
2185 if (This->depthStencilBuffer) {
2186 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2187 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2189 This->depthStencilBuffer = NULL;
2192 for(i=0; i < This->NumberOfSwapChains; i++) {
2193 TRACE("Releasing the implicit swapchain %d\n", i);
2194 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2195 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2199 HeapFree(GetProcessHeap(), 0, This->swapchains);
2200 This->swapchains = NULL;
2201 This->NumberOfSwapChains = 0;
2203 HeapFree(GetProcessHeap(), 0, This->render_targets);
2204 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2205 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2206 This->render_targets = NULL;
2207 This->fbo_color_attachments = NULL;
2208 This->draw_buffers = NULL;
2211 This->d3d_initialized = FALSE;
2215 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2217 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2219 /* Setup the window for fullscreen mode */
2220 if(fullscreen && !This->ddraw_fullscreen) {
2221 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2222 } else if(!fullscreen && This->ddraw_fullscreen) {
2223 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2226 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2227 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2228 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2231 This->ddraw_fullscreen = fullscreen;
2234 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2235 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2236 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2238 * There is no way to deactivate thread safety once it is enabled.
2240 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2243 /*For now just store the flag(needed in case of ddraw) */
2244 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2249 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2256 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2258 /* Resize the screen even without a window:
2259 * The app could have unset it with SetCooperativeLevel, but not called
2260 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2261 * but we don't have any hwnd
2264 memset(&devmode, 0, sizeof(devmode));
2265 devmode.dmSize = sizeof(devmode);
2266 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2267 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2268 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2269 devmode.dmPelsWidth = pMode->Width;
2270 devmode.dmPelsHeight = pMode->Height;
2272 devmode.dmDisplayFrequency = pMode->RefreshRate;
2273 if (pMode->RefreshRate != 0) {
2274 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2277 /* Only change the mode if necessary */
2278 if( (This->ddraw_width == pMode->Width) &&
2279 (This->ddraw_height == pMode->Height) &&
2280 (This->ddraw_format == pMode->Format) &&
2281 (pMode->RefreshRate == 0) ) {
2285 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2286 if (ret != DISP_CHANGE_SUCCESSFUL) {
2287 if(devmode.dmDisplayFrequency != 0) {
2288 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2289 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2290 devmode.dmDisplayFrequency = 0;
2291 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2293 if(ret != DISP_CHANGE_SUCCESSFUL) {
2294 return WINED3DERR_NOTAVAILABLE;
2298 /* Store the new values */
2299 This->ddraw_width = pMode->Width;
2300 This->ddraw_height = pMode->Height;
2301 This->ddraw_format = pMode->Format;
2303 /* Only do this with a window of course */
2304 if(This->ddraw_window)
2305 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2307 /* And finally clip mouse to our screen */
2308 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2309 ClipCursor(&clip_rc);
2314 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2316 *ppD3D= This->wineD3D;
2317 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2318 IWineD3D_AddRef(*ppD3D);
2322 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2325 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2326 (This->adapter->TextureRam/(1024*1024)),
2327 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2328 /* return simulated texture memory left */
2329 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2337 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2340 /* Update the current state block */
2341 This->updateStateBlock->changed.fvf = TRUE;
2343 if(This->updateStateBlock->fvf == fvf) {
2344 TRACE("Application is setting the old fvf over, nothing to do\n");
2348 This->updateStateBlock->fvf = fvf;
2349 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2355 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2357 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2358 *pfvf = This->stateBlock->fvf;
2363 * Get / Set Stream Source
2365 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2367 IWineD3DVertexBuffer *oldSrc;
2369 if (StreamNumber >= MAX_STREAMS) {
2370 WARN("Stream out of range %d\n", StreamNumber);
2371 return WINED3DERR_INVALIDCALL;
2374 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2375 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2377 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2379 if(oldSrc == pStreamData &&
2380 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2381 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2382 TRACE("Application is setting the old values over, nothing to do\n");
2386 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2388 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2389 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2392 /* Handle recording of state blocks */
2393 if (This->isRecordingState) {
2394 TRACE("Recording... not performing anything\n");
2395 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2396 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2400 /* Need to do a getParent and pass the reffs up */
2401 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2402 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2403 so for now, just count internally */
2404 if (pStreamData != NULL) {
2405 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2406 InterlockedIncrement(&vbImpl->bindCount);
2407 IWineD3DVertexBuffer_AddRef(pStreamData);
2409 if (oldSrc != NULL) {
2410 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2411 IWineD3DVertexBuffer_Release(oldSrc);
2414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2419 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2422 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2423 This->stateBlock->streamSource[StreamNumber],
2424 This->stateBlock->streamOffset[StreamNumber],
2425 This->stateBlock->streamStride[StreamNumber]);
2427 if (StreamNumber >= MAX_STREAMS) {
2428 WARN("Stream out of range %d\n", StreamNumber);
2429 return WINED3DERR_INVALIDCALL;
2431 *pStream = This->stateBlock->streamSource[StreamNumber];
2432 *pStride = This->stateBlock->streamStride[StreamNumber];
2434 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2437 if (*pStream != NULL) {
2438 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2443 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2445 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2446 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2448 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2449 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2451 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2452 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2454 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2455 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2462 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2466 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2468 TRACE("(%p) : returning %d\n", This, *Divider);
2474 * Get / Set & Multiply Transform
2476 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 /* Most of this routine, comments included copied from ddraw tree initially: */
2480 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2482 /* Handle recording of state blocks */
2483 if (This->isRecordingState) {
2484 TRACE("Recording... not performing anything\n");
2485 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2486 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2491 * If the new matrix is the same as the current one,
2492 * we cut off any further processing. this seems to be a reasonable
2493 * optimization because as was noticed, some apps (warcraft3 for example)
2494 * tend towards setting the same matrix repeatedly for some reason.
2496 * From here on we assume that the new matrix is different, wherever it matters.
2498 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2499 TRACE("The app is setting the same matrix over again\n");
2502 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2506 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2507 where ViewMat = Camera space, WorldMat = world space.
2509 In OpenGL, camera and world space is combined into GL_MODELVIEW
2510 matrix. The Projection matrix stay projection matrix.
2513 /* Capture the times we can just ignore the change for now */
2514 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2515 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2516 /* Handled by the state manager */
2519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2523 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2525 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2526 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2530 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2531 WINED3DMATRIX *mat = NULL;
2534 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2535 * below means it will be recorded in a state block change, but it
2536 * works regardless where it is recorded.
2537 * If this is found to be wrong, change to StateBlock.
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2542 if (State < HIGHEST_TRANSFORMSTATE)
2544 mat = &This->updateStateBlock->transforms[State];
2546 FIXME("Unhandled transform state!!\n");
2549 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2551 /* Apply change via set transform - will reapply to eg. lights this way */
2552 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2558 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2559 you can reference any indexes you want as long as that number max are enabled at any
2560 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2561 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2562 but when recording, just build a chain pretty much of commands to be replayed. */
2564 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2566 PLIGHTINFOEL *object = NULL;
2567 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2573 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2577 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2578 return WINED3DERR_INVALIDCALL;
2581 switch(pLight->Type) {
2582 case WINED3DLIGHT_POINT:
2583 case WINED3DLIGHT_SPOT:
2584 case WINED3DLIGHT_PARALLELPOINT:
2585 case WINED3DLIGHT_GLSPOT:
2586 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2589 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2590 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2591 return WINED3DERR_INVALIDCALL;
2595 case WINED3DLIGHT_DIRECTIONAL:
2596 /* Ignores attenuation */
2600 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2601 return WINED3DERR_INVALIDCALL;
2604 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2605 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2606 if(object->OriginalIndex == Index) break;
2611 TRACE("Adding new light\n");
2612 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2614 ERR("Out of memory error when allocating a light\n");
2615 return E_OUTOFMEMORY;
2617 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2618 object->glIndex = -1;
2619 object->OriginalIndex = Index;
2620 object->changed = TRUE;
2623 /* Initialize the object */
2624 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,
2625 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2626 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2627 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2628 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2629 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2630 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2632 /* Save away the information */
2633 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2635 switch (pLight->Type) {
2636 case WINED3DLIGHT_POINT:
2638 object->lightPosn[0] = pLight->Position.x;
2639 object->lightPosn[1] = pLight->Position.y;
2640 object->lightPosn[2] = pLight->Position.z;
2641 object->lightPosn[3] = 1.0f;
2642 object->cutoff = 180.0f;
2646 case WINED3DLIGHT_DIRECTIONAL:
2648 object->lightPosn[0] = -pLight->Direction.x;
2649 object->lightPosn[1] = -pLight->Direction.y;
2650 object->lightPosn[2] = -pLight->Direction.z;
2651 object->lightPosn[3] = 0.0;
2652 object->exponent = 0.0f;
2653 object->cutoff = 180.0f;
2656 case WINED3DLIGHT_SPOT:
2658 object->lightPosn[0] = pLight->Position.x;
2659 object->lightPosn[1] = pLight->Position.y;
2660 object->lightPosn[2] = pLight->Position.z;
2661 object->lightPosn[3] = 1.0;
2664 object->lightDirn[0] = pLight->Direction.x;
2665 object->lightDirn[1] = pLight->Direction.y;
2666 object->lightDirn[2] = pLight->Direction.z;
2667 object->lightDirn[3] = 1.0;
2670 * opengl-ish and d3d-ish spot lights use too different models for the
2671 * light "intensity" as a function of the angle towards the main light direction,
2672 * so we only can approximate very roughly.
2673 * however spot lights are rather rarely used in games (if ever used at all).
2674 * furthermore if still used, probably nobody pays attention to such details.
2676 if (pLight->Falloff == 0) {
2677 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2678 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2679 * will always be 1.0 for both of them, and we don't have to care for the
2680 * rest of the rather complex calculation
2682 object->exponent = 0;
2684 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2685 if (rho < 0.0001) rho = 0.0001f;
2686 object->exponent = -0.3/log(cos(rho/2));
2688 if (object->exponent > 128.0) {
2689 object->exponent = 128.0;
2691 object->cutoff = pLight->Phi*90/M_PI;
2697 FIXME("Unrecognized light type %d\n", pLight->Type);
2700 /* Update the live definitions if the light is currently assigned a glIndex */
2701 if (object->glIndex != -1 && !This->isRecordingState) {
2702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2707 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2708 PLIGHTINFOEL *lightInfo = NULL;
2709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2710 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2712 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2714 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2715 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2716 if(lightInfo->OriginalIndex == Index) break;
2720 if (lightInfo == NULL) {
2721 TRACE("Light information requested but light not defined\n");
2722 return WINED3DERR_INVALIDCALL;
2725 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2730 * Get / Set Light Enable
2731 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2733 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2734 PLIGHTINFOEL *lightInfo = NULL;
2735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2738 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2740 /* Tests show true = 128...not clear why */
2741 Enable = Enable? 128: 0;
2743 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2744 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2745 if(lightInfo->OriginalIndex == Index) break;
2748 TRACE("Found light: %p\n", lightInfo);
2750 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2751 if (lightInfo == NULL) {
2753 TRACE("Light enabled requested but light not defined, so defining one!\n");
2754 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2756 /* Search for it again! Should be fairly quick as near head of list */
2757 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2758 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2759 if(lightInfo->OriginalIndex == Index) break;
2762 if (lightInfo == NULL) {
2763 FIXME("Adding default lights has failed dismally\n");
2764 return WINED3DERR_INVALIDCALL;
2768 lightInfo->enabledChanged = TRUE;
2770 if(lightInfo->glIndex != -1) {
2771 if(!This->isRecordingState) {
2772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2775 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2776 lightInfo->glIndex = -1;
2778 TRACE("Light already disabled, nothing to do\n");
2781 if (lightInfo->glIndex != -1) {
2783 TRACE("Nothing to do as light was enabled\n");
2786 /* Find a free gl light */
2787 for(i = 0; i < This->maxConcurrentLights; i++) {
2788 if(This->stateBlock->activeLights[i] == NULL) {
2789 This->stateBlock->activeLights[i] = lightInfo;
2790 lightInfo->glIndex = i;
2794 if(lightInfo->glIndex == -1) {
2795 ERR("Too many concurrently active lights\n");
2796 return WINED3DERR_INVALIDCALL;
2799 /* i == lightInfo->glIndex */
2800 if(!This->isRecordingState) {
2801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2809 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2811 PLIGHTINFOEL *lightInfo = NULL;
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2815 TRACE("(%p) : for idx(%d)\n", This, Index);
2817 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2818 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2819 if(lightInfo->OriginalIndex == Index) break;
2823 if (lightInfo == NULL) {
2824 TRACE("Light enabled state requested but light not defined\n");
2825 return WINED3DERR_INVALIDCALL;
2827 /* true is 128 according to SetLightEnable */
2828 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2833 * Get / Set Clip Planes
2835 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2837 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2839 /* Validate Index */
2840 if (Index >= GL_LIMITS(clipplanes)) {
2841 TRACE("Application has requested clipplane this device doesn't support\n");
2842 return WINED3DERR_INVALIDCALL;
2845 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2847 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2848 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2849 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2850 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2851 TRACE("Application is setting old values over, nothing to do\n");
2855 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2856 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2857 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2858 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2860 /* Handle recording of state blocks */
2861 if (This->isRecordingState) {
2862 TRACE("Recording... not performing anything\n");
2866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2871 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2873 TRACE("(%p) : for idx %d\n", This, Index);
2875 /* Validate Index */
2876 if (Index >= GL_LIMITS(clipplanes)) {
2877 TRACE("Application has requested clipplane this device doesn't support\n");
2878 return WINED3DERR_INVALIDCALL;
2881 pPlane[0] = This->stateBlock->clipplane[Index][0];
2882 pPlane[1] = This->stateBlock->clipplane[Index][1];
2883 pPlane[2] = This->stateBlock->clipplane[Index][2];
2884 pPlane[3] = This->stateBlock->clipplane[Index][3];
2889 * Get / Set Clip Plane Status
2890 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2892 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2894 FIXME("(%p) : stub\n", This);
2895 if (NULL == pClipStatus) {
2896 return WINED3DERR_INVALIDCALL;
2898 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2899 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2903 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2905 FIXME("(%p) : stub\n", This);
2906 if (NULL == pClipStatus) {
2907 return WINED3DERR_INVALIDCALL;
2909 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2910 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2915 * Get / Set Material
2917 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 This->updateStateBlock->changed.material = TRUE;
2921 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2923 /* Handle recording of state blocks */
2924 if (This->isRecordingState) {
2925 TRACE("Recording... not performing anything\n");
2929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2933 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2936 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2937 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2938 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2939 pMaterial->Ambient.b, pMaterial->Ambient.a);
2940 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2941 pMaterial->Specular.b, pMaterial->Specular.a);
2942 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2943 pMaterial->Emissive.b, pMaterial->Emissive.a);
2944 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2952 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2954 IWineD3DIndexBuffer *oldIdxs;
2956 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2957 oldIdxs = This->updateStateBlock->pIndexData;
2959 This->updateStateBlock->changed.indices = TRUE;
2960 This->updateStateBlock->pIndexData = pIndexData;
2962 /* Handle recording of state blocks */
2963 if (This->isRecordingState) {
2964 TRACE("Recording... not performing anything\n");
2965 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2966 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2970 if(oldIdxs != pIndexData) {
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2972 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2973 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2981 *ppIndexData = This->stateBlock->pIndexData;
2983 /* up ref count on ppindexdata */
2985 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2986 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2988 TRACE("(%p) No index data set\n", This);
2990 TRACE("Returning %p\n", *ppIndexData);
2995 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2996 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 TRACE("(%p)->(%d)\n", This, BaseIndex);
3000 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3001 TRACE("Application is setting the old value over, nothing to do\n");
3005 This->updateStateBlock->baseVertexIndex = BaseIndex;
3007 if (This->isRecordingState) {
3008 TRACE("Recording... not performing anything\n");
3011 /* The base vertex index affects the stream sources */
3012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3016 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 TRACE("(%p) : base_index %p\n", This, base_index);
3020 *base_index = This->stateBlock->baseVertexIndex;
3022 TRACE("Returning %u\n", *base_index);
3028 * Get / Set Viewports
3030 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3033 TRACE("(%p)\n", This);
3034 This->updateStateBlock->changed.viewport = TRUE;
3035 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3037 /* Handle recording of state blocks */
3038 if (This->isRecordingState) {
3039 TRACE("Recording... not performing anything\n");
3043 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3044 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3046 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3051 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 TRACE("(%p)\n", This);
3054 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3059 * Get / Set Render States
3060 * TODO: Verify against dx9 definitions
3062 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 DWORD oldValue = This->stateBlock->renderState[State];
3067 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3069 This->updateStateBlock->changed.renderState[State] = TRUE;
3070 This->updateStateBlock->renderState[State] = Value;
3072 /* Handle recording of state blocks */
3073 if (This->isRecordingState) {
3074 TRACE("Recording... not performing anything\n");
3078 /* Compared here and not before the assignment to allow proper stateblock recording */
3079 if(Value == oldValue) {
3080 TRACE("Application is setting the old value over, nothing to do\n");
3082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3088 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3090 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3091 *pValue = This->stateBlock->renderState[State];
3096 * Get / Set Sampler States
3097 * TODO: Verify against dx9 definitions
3100 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3105 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3107 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3108 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3112 * SetSampler is designed to allow for more than the standard up to 8 textures
3113 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3114 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3116 * http://developer.nvidia.com/object/General_FAQ.html#t6
3118 * There are two new settings for GForce
3120 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3121 * and the texture one:
3122 * GL_MAX_TEXTURE_COORDS_ARB.
3123 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3126 oldValue = This->stateBlock->samplerState[Sampler][Type];
3127 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3128 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3130 /* Handle recording of state blocks */
3131 if (This->isRecordingState) {
3132 TRACE("Recording... not performing anything\n");
3136 if(oldValue == Value) {
3137 TRACE("Application is setting the old value over, nothing to do\n");
3141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3146 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3149 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3150 This, Sampler, debug_d3dsamplerstate(Type), Type);
3152 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3153 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3156 *Value = This->stateBlock->samplerState[Sampler][Type];
3157 TRACE("(%p) : Returning %#x\n", This, *Value);
3162 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3165 This->updateStateBlock->changed.scissorRect = TRUE;
3166 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3167 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3170 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3172 if(This->isRecordingState) {
3173 TRACE("Recording... not performing anything\n");
3177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3182 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3185 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3186 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3190 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3192 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3194 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3196 This->updateStateBlock->vertexDecl = pDecl;
3197 This->updateStateBlock->changed.vertexDecl = TRUE;
3199 if (This->isRecordingState) {
3200 TRACE("Recording... not performing anything\n");
3202 } else if(pDecl == oldDecl) {
3203 /* Checked after the assignment to allow proper stateblock recording */
3204 TRACE("Application is setting the old declaration over, nothing to do\n");
3208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3212 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3215 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3217 *ppDecl = This->stateBlock->vertexDecl;
3218 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3222 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3226 This->updateStateBlock->vertexShader = pShader;
3227 This->updateStateBlock->changed.vertexShader = TRUE;
3229 if (This->isRecordingState) {
3230 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3231 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3232 TRACE("Recording... not performing anything\n");
3234 } else if(oldShader == pShader) {
3235 /* Checked here to allow proper stateblock recording */
3236 TRACE("App is setting the old shader over, nothing to do\n");
3240 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3241 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3242 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3249 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 if (NULL == ppShader) {
3253 return WINED3DERR_INVALIDCALL;
3255 *ppShader = This->stateBlock->vertexShader;
3256 if( NULL != *ppShader)
3257 IWineD3DVertexShader_AddRef(*ppShader);
3259 TRACE("(%p) : returning %p\n", This, *ppShader);
3263 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3264 IWineD3DDevice *iface,
3266 CONST BOOL *srcData,
3269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3270 int i, cnt = min(count, MAX_CONST_B - start);
3272 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3273 iface, srcData, start, count);
3275 if (srcData == NULL || cnt < 0)
3276 return WINED3DERR_INVALIDCALL;
3278 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3279 for (i = 0; i < cnt; i++)
3280 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3282 for (i = start; i < cnt + start; ++i) {
3283 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3286 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3292 IWineD3DDevice *iface,
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 int cnt = min(count, MAX_CONST_B - start);
3300 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3301 iface, dstData, start, count);
3303 if (dstData == NULL || cnt < 0)
3304 return WINED3DERR_INVALIDCALL;
3306 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3310 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3311 IWineD3DDevice *iface,
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3317 int i, cnt = min(count, MAX_CONST_I - start);
3319 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3320 iface, srcData, start, count);
3322 if (srcData == NULL || cnt < 0)
3323 return WINED3DERR_INVALIDCALL;
3325 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3326 for (i = 0; i < cnt; i++)
3327 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3328 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3330 for (i = start; i < cnt + start; ++i) {
3331 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3339 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3340 IWineD3DDevice *iface,
3345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 int cnt = min(count, MAX_CONST_I - start);
3348 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3349 iface, dstData, start, count);
3351 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3352 return WINED3DERR_INVALIDCALL;
3354 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3358 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3359 IWineD3DDevice *iface,
3361 CONST float *srcData,
3364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3367 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3368 iface, srcData, start, count);
3370 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3371 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3372 return WINED3DERR_INVALIDCALL;
3374 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3376 for (i = 0; i < count; i++)
3377 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3378 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3381 for (i = start; i < count + start; ++i) {
3382 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3383 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3384 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3385 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3386 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3388 ptr->idx[ptr->count++] = i;
3389 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3398 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3399 IWineD3DDevice *iface,
3404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3405 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3407 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3408 iface, dstData, start, count);
3410 if (dstData == NULL || cnt < 0)
3411 return WINED3DERR_INVALIDCALL;
3413 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3417 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3419 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3424 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3425 int i = This->rev_tex_unit_map[unit];
3426 int j = This->texUnitMap[stage];
3428 This->texUnitMap[stage] = unit;
3429 if (i != -1 && i != stage) {
3430 This->texUnitMap[i] = -1;
3433 This->rev_tex_unit_map[unit] = stage;
3434 if (j != -1 && j != unit) {
3435 This->rev_tex_unit_map[j] = -1;
3439 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3442 for (i = 0; i < MAX_TEXTURES; ++i) {
3443 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3444 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3445 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3446 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3447 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3448 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3449 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3450 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3452 if (color_op == WINED3DTOP_DISABLE) {
3453 /* Not used, and disable higher stages */
3454 while (i < MAX_TEXTURES) {
3455 This->fixed_function_usage_map[i] = FALSE;
3461 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3462 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3463 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3464 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3465 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3466 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3467 This->fixed_function_usage_map[i] = TRUE;
3469 This->fixed_function_usage_map[i] = FALSE;
3472 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3473 This->fixed_function_usage_map[i+1] = TRUE;
3478 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3481 device_update_fixed_function_usage_map(This);
3483 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3484 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3485 if (!This->fixed_function_usage_map[i]) continue;
3487 if (This->texUnitMap[i] != i) {
3488 device_map_stage(This, i, i);
3489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3490 markTextureStagesDirty(This, i);
3496 /* Now work out the mapping */
3498 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3499 if (!This->fixed_function_usage_map[i]) continue;
3501 if (This->texUnitMap[i] != tex) {
3502 device_map_stage(This, i, tex);
3503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3504 markTextureStagesDirty(This, i);
3511 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3512 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3515 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3516 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3517 device_map_stage(This, i, i);
3518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3519 if (i < MAX_TEXTURES) {
3520 markTextureStagesDirty(This, i);
3526 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3527 int current_mapping = This->rev_tex_unit_map[unit];
3529 if (current_mapping == -1) {
3530 /* Not currently used */
3534 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3535 /* Used by a fragment sampler */
3537 if (!pshader_sampler_tokens) {
3538 /* No pixel shader, check fixed function */
3539 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3542 /* Pixel shader, check the shader's sampler map */
3543 return !pshader_sampler_tokens[current_mapping];
3546 /* Used by a vertex sampler */
3547 return !vshader_sampler_tokens[current_mapping];
3550 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3551 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3552 DWORD *pshader_sampler_tokens = NULL;
3553 int start = GL_LIMITS(combined_samplers) - 1;
3557 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3559 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3560 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3561 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3564 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3565 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3566 if (vshader_sampler_tokens[i]) {
3567 if (This->texUnitMap[vsampler_idx] != -1) {
3568 /* Already mapped somewhere */
3572 while (start >= 0) {
3573 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3574 device_map_stage(This, vsampler_idx, start);
3575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3587 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3588 BOOL vs = use_vs(This);
3589 BOOL ps = use_ps(This);
3592 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3593 * that would be really messy and require shader recompilation
3594 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3595 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3598 device_map_psamplers(This);
3600 device_map_fixed_function_samplers(This);
3604 device_map_vsamplers(This, ps);
3608 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3610 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3611 This->updateStateBlock->pixelShader = pShader;
3612 This->updateStateBlock->changed.pixelShader = TRUE;
3614 /* Handle recording of state blocks */
3615 if (This->isRecordingState) {
3616 TRACE("Recording... not performing anything\n");
3619 if (This->isRecordingState) {
3620 TRACE("Recording... not performing anything\n");
3621 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3622 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3626 if(pShader == oldShader) {
3627 TRACE("App is setting the old pixel shader over, nothing to do\n");
3631 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3632 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3634 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3640 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3643 if (NULL == ppShader) {
3644 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3645 return WINED3DERR_INVALIDCALL;
3648 *ppShader = This->stateBlock->pixelShader;
3649 if (NULL != *ppShader) {
3650 IWineD3DPixelShader_AddRef(*ppShader);
3652 TRACE("(%p) : returning %p\n", This, *ppShader);
3656 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3657 IWineD3DDevice *iface,
3659 CONST BOOL *srcData,
3662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3663 int i, cnt = min(count, MAX_CONST_B - start);
3665 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3666 iface, srcData, start, count);
3668 if (srcData == NULL || cnt < 0)
3669 return WINED3DERR_INVALIDCALL;
3671 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3672 for (i = 0; i < cnt; i++)
3673 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3675 for (i = start; i < cnt + start; ++i) {
3676 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3684 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3685 IWineD3DDevice *iface,
3690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3691 int cnt = min(count, MAX_CONST_B - start);
3693 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3694 iface, dstData, start, count);
3696 if (dstData == NULL || cnt < 0)
3697 return WINED3DERR_INVALIDCALL;
3699 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3703 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3704 IWineD3DDevice *iface,
3709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3710 int i, cnt = min(count, MAX_CONST_I - start);
3712 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3713 iface, srcData, start, count);
3715 if (srcData == NULL || cnt < 0)
3716 return WINED3DERR_INVALIDCALL;
3718 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3719 for (i = 0; i < cnt; i++)
3720 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3721 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3723 for (i = start; i < cnt + start; ++i) {
3724 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3732 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3733 IWineD3DDevice *iface,
3738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3739 int cnt = min(count, MAX_CONST_I - start);
3741 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3742 iface, dstData, start, count);
3744 if (dstData == NULL || cnt < 0)
3745 return WINED3DERR_INVALIDCALL;
3747 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3751 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3752 IWineD3DDevice *iface,
3754 CONST float *srcData,
3757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3760 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3761 iface, srcData, start, count);
3763 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3764 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3765 return WINED3DERR_INVALIDCALL;
3767 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3769 for (i = 0; i < count; i++)
3770 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3771 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3774 for (i = start; i < count + start; ++i) {
3775 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3776 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3777 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3778 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3779 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3781 ptr->idx[ptr->count++] = i;
3782 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3791 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3792 IWineD3DDevice *iface,
3797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3798 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3800 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3801 iface, dstData, start, count);
3803 if (dstData == NULL || cnt < 0)
3804 return WINED3DERR_INVALIDCALL;
3806 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3810 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3812 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3813 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3815 DWORD DestFVF = dest->fvf;
3817 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3821 if (lpStrideData->u.s.normal.lpData) {
3822 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3825 if (lpStrideData->u.s.position.lpData == NULL) {
3826 ERR("Source has no position mask\n");
3827 return WINED3DERR_INVALIDCALL;
3830 /* We might access VBOs from this code, so hold the lock */
3833 if (dest->resource.allocatedMemory == NULL) {
3834 /* This may happen if we do direct locking into a vbo. Unlikely,
3835 * but theoretically possible(ddraw processvertices test)
3837 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3838 if(!dest->resource.allocatedMemory) {
3840 ERR("Out of memory\n");
3841 return E_OUTOFMEMORY;
3845 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3846 checkGLcall("glBindBufferARB");
3847 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3849 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3851 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3852 checkGLcall("glUnmapBufferARB");
3856 /* Get a pointer into the destination vbo(create one if none exists) and
3857 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3859 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3864 unsigned char extrabytes = 0;
3865 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3866 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3867 * this may write 4 extra bytes beyond the area that should be written
3869 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3870 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3871 if(!dest_conv_addr) {
3872 ERR("Out of memory\n");
3873 /* Continue without storing converted vertices */
3875 dest_conv = dest_conv_addr;
3879 * a) WINED3DRS_CLIPPING is enabled
3880 * b) WINED3DVOP_CLIP is passed
3882 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3883 static BOOL warned = FALSE;
3885 * The clipping code is not quite correct. Some things need
3886 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3887 * so disable clipping for now.
3888 * (The graphics in Half-Life are broken, and my processvertices
3889 * test crashes with IDirect3DDevice3)
3895 FIXME("Clipping is broken and disabled for now\n");
3897 } else doClip = FALSE;
3898 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3900 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3903 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3904 WINED3DTS_PROJECTION,
3906 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3907 WINED3DTS_WORLDMATRIX(0),
3910 TRACE("View mat:\n");
3911 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);
3912 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);
3913 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);
3914 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);
3916 TRACE("Proj mat:\n");
3917 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);
3918 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);
3919 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);
3920 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);
3922 TRACE("World mat:\n");
3923 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);
3924 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);
3925 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);
3926 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);
3928 /* Get the viewport */
3929 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3930 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3931 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3933 multiply_matrix(&mat,&view_mat,&world_mat);
3934 multiply_matrix(&mat,&proj_mat,&mat);
3936 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3938 for (i = 0; i < dwCount; i+= 1) {
3939 unsigned int tex_index;
3941 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3942 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3943 /* The position first */
3945 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3947 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3949 /* Multiplication with world, view and projection matrix */
3950 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);
3951 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);
3952 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);
3953 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);
3955 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3957 /* WARNING: The following things are taken from d3d7 and were not yet checked
3958 * against d3d8 or d3d9!
3961 /* Clipping conditions: From
3962 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3964 * A vertex is clipped if it does not match the following requirements
3968 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3970 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3971 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3976 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3977 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3980 /* "Normal" viewport transformation (not clipped)
3981 * 1) The values are divided by rhw
3982 * 2) The y axis is negative, so multiply it with -1
3983 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3984 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3985 * 4) Multiply x with Width/2 and add Width/2
3986 * 5) The same for the height
3987 * 6) Add the viewpoint X and Y to the 2D coordinates and
3988 * The minimum Z value to z
3989 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3991 * Well, basically it's simply a linear transformation into viewport
4003 z *= vp.MaxZ - vp.MinZ;
4005 x += vp.Width / 2 + vp.X;
4006 y += vp.Height / 2 + vp.Y;
4011 /* That vertex got clipped
4012 * Contrary to OpenGL it is not dropped completely, it just
4013 * undergoes a different calculation.
4015 TRACE("Vertex got clipped\n");
4022 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4023 * outside of the main vertex buffer memory. That needs some more
4028 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4031 ( (float *) dest_ptr)[0] = x;
4032 ( (float *) dest_ptr)[1] = y;
4033 ( (float *) dest_ptr)[2] = z;
4034 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4036 dest_ptr += 3 * sizeof(float);
4038 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4039 dest_ptr += sizeof(float);
4044 ( (float *) dest_conv)[0] = x * w;
4045 ( (float *) dest_conv)[1] = y * w;
4046 ( (float *) dest_conv)[2] = z * w;
4047 ( (float *) dest_conv)[3] = w;
4049 dest_conv += 3 * sizeof(float);
4051 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4052 dest_conv += sizeof(float);
4056 if (DestFVF & WINED3DFVF_PSIZE) {
4057 dest_ptr += sizeof(DWORD);
4058 if(dest_conv) dest_conv += sizeof(DWORD);
4060 if (DestFVF & WINED3DFVF_NORMAL) {
4062 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4063 /* AFAIK this should go into the lighting information */
4064 FIXME("Didn't expect the destination to have a normal\n");
4065 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4067 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4071 if (DestFVF & WINED3DFVF_DIFFUSE) {
4073 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4075 static BOOL warned = FALSE;
4078 ERR("No diffuse color in source, but destination has one\n");
4082 *( (DWORD *) dest_ptr) = 0xffffffff;
4083 dest_ptr += sizeof(DWORD);
4086 *( (DWORD *) dest_conv) = 0xffffffff;
4087 dest_conv += sizeof(DWORD);
4091 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4093 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4094 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4095 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4096 dest_conv += sizeof(DWORD);
4101 if (DestFVF & WINED3DFVF_SPECULAR) {
4102 /* What's the color value in the feedback buffer? */
4104 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4106 static BOOL warned = FALSE;
4109 ERR("No specular color in source, but destination has one\n");
4113 *( (DWORD *) dest_ptr) = 0xFF000000;
4114 dest_ptr += sizeof(DWORD);
4117 *( (DWORD *) dest_conv) = 0xFF000000;
4118 dest_conv += sizeof(DWORD);
4122 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4124 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4125 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4126 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4127 dest_conv += sizeof(DWORD);
4132 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4134 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4135 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4137 ERR("No source texture, but destination requests one\n");
4138 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4139 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4142 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4144 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4151 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4152 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4153 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4154 dwCount * get_flexible_vertex_size(DestFVF),
4156 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4157 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4164 #undef copy_and_next
4166 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4168 WineDirect3DVertexStridedData strided;
4169 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4170 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4173 ERR("Output vertex declaration not implemented yet\n");
4176 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4177 * and this call is quite performance critical, so don't call needlessly
4179 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4180 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4183 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4184 * control the streamIsUP flag, thus restore it afterwards.
4186 This->stateBlock->streamIsUP = FALSE;
4187 memset(&strided, 0, sizeof(strided));
4188 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4189 This->stateBlock->streamIsUP = streamWasUP;
4191 if(vbo || SrcStartIndex) {
4193 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4194 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4196 * Also get the start index in, but only loop over all elements if there's something to add at all.
4198 #define FIXSRC(type) \
4199 if(strided.u.s.type.VBO) { \
4200 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4201 strided.u.s.type.VBO = 0; \
4202 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4204 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4208 if(strided.u.s.type.lpData) { \
4209 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4212 FIXSRC(blendWeights);
4213 FIXSRC(blendMatrixIndices);
4218 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4219 FIXSRC(texCoords[i]);
4232 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4236 * Get / Set Texture Stage States
4237 * TODO: Verify against dx9 definitions
4239 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4241 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4243 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4245 if (Stage >= MAX_TEXTURES) {
4246 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4250 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4251 This->updateStateBlock->textureState[Stage][Type] = Value;
4253 if (This->isRecordingState) {
4254 TRACE("Recording... not performing anything\n");
4258 /* Checked after the assignments to allow proper stateblock recording */
4259 if(oldValue == Value) {
4260 TRACE("App is setting the old value over, nothing to do\n");
4264 if(Stage > This->stateBlock->lowest_disabled_stage &&
4265 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4266 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4267 * Changes in other states are important on disabled stages too
4272 if(Type == WINED3DTSS_COLOROP) {
4275 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4276 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4277 * they have to be disabled
4279 * The current stage is dirtified below.
4281 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4282 TRACE("Additionally dirtifying stage %d\n", i);
4283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4285 This->stateBlock->lowest_disabled_stage = Stage;
4286 TRACE("New lowest disabled: %d\n", Stage);
4287 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4288 /* Previously disabled stage enabled. Stages above it may need enabling
4289 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4290 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4292 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4295 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4296 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4299 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4300 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4302 This->stateBlock->lowest_disabled_stage = i;
4303 TRACE("New lowest disabled: %d\n", i);
4305 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4306 /* TODO: Built a stage -> texture unit mapping for register combiners */
4310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4315 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4317 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4318 *pValue = This->updateStateBlock->textureState[Stage][Type];
4325 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4327 IWineD3DBaseTexture *oldTexture;
4329 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4331 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4332 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4335 oldTexture = This->updateStateBlock->textures[Stage];
4337 if(pTexture != NULL) {
4338 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4340 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4341 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4342 return WINED3DERR_INVALIDCALL;
4344 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4347 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4348 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4350 This->updateStateBlock->changed.textures[Stage] = TRUE;
4351 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4352 This->updateStateBlock->textures[Stage] = pTexture;
4354 /* Handle recording of state blocks */
4355 if (This->isRecordingState) {
4356 TRACE("Recording... not performing anything\n");
4360 if(oldTexture == pTexture) {
4361 TRACE("App is setting the same texture again, nothing to do\n");
4365 /** NOTE: MSDN says that setTexture increases the reference count,
4366 * and that the application must set the texture back to null (or have a leaky application),
4367 * This means we should pass the refcount up to the parent
4368 *******************************/
4369 if (NULL != This->updateStateBlock->textures[Stage]) {
4370 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4371 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4373 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4374 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4375 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4376 * so the COLOROP and ALPHAOP have to be dirtified.
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4381 if(bindCount == 1) {
4382 new->baseTexture.sampler = Stage;
4384 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4388 if (NULL != oldTexture) {
4389 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4390 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4392 IWineD3DBaseTexture_Release(oldTexture);
4393 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4395 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4398 if(bindCount && old->baseTexture.sampler == Stage) {
4400 /* Have to do a search for the other sampler(s) where the texture is bound to
4401 * Shouldn't happen as long as apps bind a texture only to one stage
4403 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4404 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4405 if(This->updateStateBlock->textures[i] == oldTexture) {
4406 old->baseTexture.sampler = i;
4413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4418 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4421 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4423 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4424 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4427 *ppTexture=This->stateBlock->textures[Stage];
4429 IWineD3DBaseTexture_AddRef(*ppTexture);
4431 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4439 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4440 IWineD3DSurface **ppBackBuffer) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 IWineD3DSwapChain *swapChain;
4445 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4447 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4448 if (hr == WINED3D_OK) {
4449 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4450 IWineD3DSwapChain_Release(swapChain);
4452 *ppBackBuffer = NULL;
4457 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4459 WARN("(%p) : stub, calling idirect3d for now\n", This);
4460 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4463 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4465 IWineD3DSwapChain *swapChain;
4468 if(iSwapChain > 0) {
4469 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4470 if (hr == WINED3D_OK) {
4471 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4472 IWineD3DSwapChain_Release(swapChain);
4474 FIXME("(%p) Error getting display mode\n", This);
4477 /* Don't read the real display mode,
4478 but return the stored mode instead. X11 can't change the color
4479 depth, and some apps are pretty angry if they SetDisplayMode from
4480 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4482 Also don't relay to the swapchain because with ddraw it's possible
4483 that there isn't a swapchain at all */
4484 pMode->Width = This->ddraw_width;
4485 pMode->Height = This->ddraw_height;
4486 pMode->Format = This->ddraw_format;
4487 pMode->RefreshRate = 0;
4494 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4496 TRACE("(%p)->(%p)\n", This, hWnd);
4498 if(This->ddraw_fullscreen) {
4499 if(This->ddraw_window && This->ddraw_window != hWnd) {
4500 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4502 if(hWnd && This->ddraw_window != hWnd) {
4503 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4507 This->ddraw_window = hWnd;
4511 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4513 TRACE("(%p)->(%p)\n", This, hWnd);
4515 *hWnd = This->ddraw_window;
4520 * Stateblock related functions
4523 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 IWineD3DStateBlockImpl *object;
4526 HRESULT temp_result;
4529 TRACE("(%p)\n", This);
4531 if (This->isRecordingState) {
4532 return WINED3DERR_INVALIDCALL;
4535 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4536 if (NULL == object ) {
4537 FIXME("(%p)Error allocating memory for stateblock\n", This);
4538 return E_OUTOFMEMORY;
4540 TRACE("(%p) created object %p\n", This, object);
4541 object->wineD3DDevice= This;
4542 /** FIXME: object->parent = parent; **/
4543 object->parent = NULL;
4544 object->blockType = WINED3DSBT_RECORDED;
4546 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4548 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4549 list_init(&object->lightMap[i]);
4552 temp_result = allocate_shader_constants(object);
4553 if (WINED3D_OK != temp_result)
4556 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4557 This->updateStateBlock = object;
4558 This->isRecordingState = TRUE;
4560 TRACE("(%p) recording stateblock %p\n",This , object);
4564 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4567 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4569 if (!This->isRecordingState) {
4570 FIXME("(%p) not recording! returning error\n", This);
4571 *ppStateBlock = NULL;
4572 return WINED3DERR_INVALIDCALL;
4575 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4576 if(object->changed.renderState[i]) {
4577 object->contained_render_states[object->num_contained_render_states] = i;
4578 object->num_contained_render_states++;
4581 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4582 if(object->changed.transform[i]) {
4583 object->contained_transform_states[object->num_contained_transform_states] = i;
4584 object->num_contained_transform_states++;
4587 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4588 if(object->changed.vertexShaderConstantsF[i]) {
4589 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4590 object->num_contained_vs_consts_f++;
4593 for(i = 0; i < MAX_CONST_I; i++) {
4594 if(object->changed.vertexShaderConstantsI[i]) {
4595 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4596 object->num_contained_vs_consts_i++;
4599 for(i = 0; i < MAX_CONST_B; i++) {
4600 if(object->changed.vertexShaderConstantsB[i]) {
4601 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4602 object->num_contained_vs_consts_b++;
4605 for(i = 0; i < MAX_CONST_I; i++) {
4606 if(object->changed.pixelShaderConstantsI[i]) {
4607 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4608 object->num_contained_ps_consts_i++;
4611 for(i = 0; i < MAX_CONST_B; i++) {
4612 if(object->changed.pixelShaderConstantsB[i]) {
4613 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4614 object->num_contained_ps_consts_b++;
4617 for(i = 0; i < MAX_TEXTURES; i++) {
4618 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4619 if(object->changed.textureState[i][j]) {
4620 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4621 object->contained_tss_states[object->num_contained_tss_states].state = j;
4622 object->num_contained_tss_states++;
4626 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4627 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4628 if(object->changed.samplerState[i][j]) {
4629 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4630 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4631 object->num_contained_sampler_states++;
4636 *ppStateBlock = (IWineD3DStateBlock*) object;
4637 This->isRecordingState = FALSE;
4638 This->updateStateBlock = This->stateBlock;
4639 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4640 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4641 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4646 * Scene related functions
4648 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4649 /* At the moment we have no need for any functionality at the beginning
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4652 TRACE("(%p)\n", This);
4655 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4656 return WINED3DERR_INVALIDCALL;
4658 This->inScene = TRUE;
4662 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 TRACE("(%p)\n", This);
4666 if(!This->inScene) {
4667 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4668 return WINED3DERR_INVALIDCALL;
4671 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4672 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4674 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4677 checkGLcall("glFlush");
4680 This->inScene = FALSE;
4684 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4685 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4686 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4688 IWineD3DSwapChain *swapChain = NULL;
4690 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4692 TRACE("(%p) Presenting the frame\n", This);
4694 for(i = 0 ; i < swapchains ; i ++) {
4696 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4697 TRACE("presentinng chain %d, %p\n", i, swapChain);
4698 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4699 IWineD3DSwapChain_Release(swapChain);
4705 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4706 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4710 GLbitfield glMask = 0;
4712 CONST WINED3DRECT* curRect;
4714 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4715 Count, pRects, Flags, Color, Z, Stencil);
4717 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4718 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4719 /* TODO: What about depth stencil buffers without stencil bits? */
4720 return WINED3DERR_INVALIDCALL;
4723 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4724 * and not the last active one.
4726 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4729 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4730 apply_fbo_state(iface);
4733 if (Count > 0 && pRects) {
4739 /* Only set the values up once, as they are not changing */
4740 if (Flags & WINED3DCLEAR_STENCIL) {
4741 glClearStencil(Stencil);
4742 checkGLcall("glClearStencil");
4743 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4744 glStencilMask(0xFFFFFFFF);
4747 if (Flags & WINED3DCLEAR_ZBUFFER) {
4748 glDepthMask(GL_TRUE);
4750 checkGLcall("glClearDepth");
4751 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4755 if (Flags & WINED3DCLEAR_TARGET) {
4756 TRACE("Clearing screen with glClear to color %x\n", Color);
4757 glClearColor(D3DCOLOR_R(Color),
4761 checkGLcall("glClearColor");
4763 /* Clear ALL colors! */
4764 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4765 glMask = glMask | GL_COLOR_BUFFER_BIT;
4769 /* In drawable flag is set below */
4771 if (This->render_offscreen) {
4772 glScissor(This->stateBlock->viewport.X,
4773 This->stateBlock->viewport.Y,
4774 This->stateBlock->viewport.Width,
4775 This->stateBlock->viewport.Height);
4777 glScissor(This->stateBlock->viewport.X,
4778 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4779 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4780 This->stateBlock->viewport.Width,
4781 This->stateBlock->viewport.Height);
4783 checkGLcall("glScissor");
4785 checkGLcall("glClear");
4787 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4788 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4790 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4791 curRect[0].x2 < target->currentDesc.Width ||
4792 curRect[0].y2 < target->currentDesc.Height) {
4793 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4794 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4798 /* Now process each rect in turn */
4799 for (i = 0; i < Count; i++) {
4800 /* Note gl uses lower left, width/height */
4801 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4802 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4803 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4804 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4806 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4807 * The rectangle is not cleared, no error is returned, but further rectanlges are
4808 * still cleared if they are valid
4810 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4811 TRACE("Rectangle with negative dimensions, ignoring\n");
4815 if(This->render_offscreen) {
4816 glScissor(curRect[i].x1, curRect[i].y1,
4817 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4819 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4820 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4822 checkGLcall("glScissor");
4825 checkGLcall("glClear");
4829 /* Restore the old values (why..?) */
4830 if (Flags & WINED3DCLEAR_STENCIL) {
4831 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4833 if (Flags & WINED3DCLEAR_TARGET) {
4834 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4835 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4836 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4837 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4838 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4843 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4844 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4846 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4847 /* TODO: Move the fbo logic into ModifyLocation() */
4848 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4849 target->Flags |= SFLAG_INTEXTURE;
4857 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4858 UINT PrimitiveCount) {
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4862 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4863 debug_d3dprimitivetype(PrimitiveType),
4864 StartVertex, PrimitiveCount);
4866 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4867 if(This->stateBlock->streamIsUP) {
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4869 This->stateBlock->streamIsUP = FALSE;
4872 if(This->stateBlock->loadBaseVertexIndex != 0) {
4873 This->stateBlock->loadBaseVertexIndex = 0;
4874 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4876 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4877 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4878 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4882 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4883 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4884 WINED3DPRIMITIVETYPE PrimitiveType,
4885 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4889 IWineD3DIndexBuffer *pIB;
4890 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4893 pIB = This->stateBlock->pIndexData;
4895 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4896 * without an index buffer set. (The first time at least...)
4897 * D3D8 simply dies, but I doubt it can do much harm to return
4898 * D3DERR_INVALIDCALL there as well. */
4899 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4900 return WINED3DERR_INVALIDCALL;
4903 if(This->stateBlock->streamIsUP) {
4904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4905 This->stateBlock->streamIsUP = FALSE;
4907 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4909 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4910 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4911 minIndex, NumVertices, startIndex, primCount);
4913 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4914 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4920 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4921 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4925 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4926 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4931 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4932 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4933 UINT VertexStreamZeroStride) {
4934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4935 IWineD3DVertexBuffer *vb;
4937 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4938 debug_d3dprimitivetype(PrimitiveType),
4939 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4941 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4942 vb = This->stateBlock->streamSource[0];
4943 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4944 if(vb) IWineD3DVertexBuffer_Release(vb);
4945 This->stateBlock->streamOffset[0] = 0;
4946 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4947 This->stateBlock->streamIsUP = TRUE;
4948 This->stateBlock->loadBaseVertexIndex = 0;
4950 /* TODO: Only mark dirty if drawing from a different UP address */
4951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4953 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4954 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4956 /* MSDN specifies stream zero settings must be set to NULL */
4957 This->stateBlock->streamStride[0] = 0;
4958 This->stateBlock->streamSource[0] = NULL;
4960 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4961 * the new stream sources or use UP drawing again
4966 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4967 UINT MinVertexIndex, UINT NumVertices,
4968 UINT PrimitiveCount, CONST void* pIndexData,
4969 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4970 UINT VertexStreamZeroStride) {
4972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4973 IWineD3DVertexBuffer *vb;
4974 IWineD3DIndexBuffer *ib;
4976 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4977 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4978 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4979 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4981 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4987 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4988 vb = This->stateBlock->streamSource[0];
4989 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4990 if(vb) IWineD3DVertexBuffer_Release(vb);
4991 This->stateBlock->streamIsUP = TRUE;
4992 This->stateBlock->streamOffset[0] = 0;
4993 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4995 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4996 This->stateBlock->baseVertexIndex = 0;
4997 This->stateBlock->loadBaseVertexIndex = 0;
4998 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5002 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5004 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5005 This->stateBlock->streamSource[0] = NULL;
5006 This->stateBlock->streamStride[0] = 0;
5007 ib = This->stateBlock->pIndexData;
5009 IWineD3DIndexBuffer_Release(ib);
5010 This->stateBlock->pIndexData = NULL;
5012 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5013 * SetStreamSource to specify a vertex buffer
5019 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5022 /* Mark the state dirty until we have nicer tracking
5023 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5028 This->stateBlock->baseVertexIndex = 0;
5029 This->up_strided = DrawPrimStrideData;
5030 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5031 This->up_strided = NULL;
5035 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5037 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5039 /* Mark the state dirty until we have nicer tracking
5040 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5045 This->stateBlock->streamIsUP = TRUE;
5046 This->stateBlock->baseVertexIndex = 0;
5047 This->up_strided = DrawPrimStrideData;
5048 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5049 This->up_strided = NULL;
5053 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5054 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5055 * not callable by the app directly no parameter validation checks are needed here.
5057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5058 WINED3DLOCKED_BOX src;
5059 WINED3DLOCKED_BOX dst;
5061 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5063 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5064 * dirtification to improve loading performance.
5066 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5067 if(FAILED(hr)) return hr;
5068 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5070 IWineD3DVolume_UnlockBox(pSourceVolume);
5074 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5076 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5078 IWineD3DVolume_UnlockBox(pSourceVolume);
5080 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5085 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5086 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5088 HRESULT hr = WINED3D_OK;
5089 WINED3DRESOURCETYPE sourceType;
5090 WINED3DRESOURCETYPE destinationType;
5093 /* TODO: think about moving the code into IWineD3DBaseTexture */
5095 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5097 /* verify that the source and destination textures aren't NULL */
5098 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5099 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5100 This, pSourceTexture, pDestinationTexture);
5101 hr = WINED3DERR_INVALIDCALL;
5104 if (pSourceTexture == pDestinationTexture) {
5105 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5106 This, pSourceTexture, pDestinationTexture);
5107 hr = WINED3DERR_INVALIDCALL;
5109 /* Verify that the source and destination textures are the same type */
5110 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5111 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5113 if (sourceType != destinationType) {
5114 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5116 hr = WINED3DERR_INVALIDCALL;
5119 /* check that both textures have the identical numbers of levels */
5120 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5121 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5122 hr = WINED3DERR_INVALIDCALL;
5125 if (WINED3D_OK == hr) {
5127 /* Make sure that the destination texture is loaded */
5128 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5130 /* Update every surface level of the texture */
5131 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5133 switch (sourceType) {
5134 case WINED3DRTYPE_TEXTURE:
5136 IWineD3DSurface *srcSurface;
5137 IWineD3DSurface *destSurface;
5139 for (i = 0 ; i < levels ; ++i) {
5140 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5141 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5142 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5143 IWineD3DSurface_Release(srcSurface);
5144 IWineD3DSurface_Release(destSurface);
5145 if (WINED3D_OK != hr) {
5146 WARN("(%p) : Call to update surface failed\n", This);
5152 case WINED3DRTYPE_CUBETEXTURE:
5154 IWineD3DSurface *srcSurface;
5155 IWineD3DSurface *destSurface;
5156 WINED3DCUBEMAP_FACES faceType;
5158 for (i = 0 ; i < levels ; ++i) {
5159 /* Update each cube face */
5160 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5161 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5162 if (WINED3D_OK != hr) {
5163 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5165 TRACE("Got srcSurface %p\n", srcSurface);
5167 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5168 if (WINED3D_OK != hr) {
5169 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5171 TRACE("Got desrSurface %p\n", destSurface);
5173 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5174 IWineD3DSurface_Release(srcSurface);
5175 IWineD3DSurface_Release(destSurface);
5176 if (WINED3D_OK != hr) {
5177 WARN("(%p) : Call to update surface failed\n", This);
5185 case WINED3DRTYPE_VOLUMETEXTURE:
5187 IWineD3DVolume *srcVolume = NULL;
5188 IWineD3DVolume *destVolume = NULL;
5190 for (i = 0 ; i < levels ; ++i) {
5191 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5192 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5193 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5194 IWineD3DVolume_Release(srcVolume);
5195 IWineD3DVolume_Release(destVolume);
5196 if (WINED3D_OK != hr) {
5197 WARN("(%p) : Call to update volume failed\n", This);
5205 FIXME("(%p) : Unsupported source and destination type\n", This);
5206 hr = WINED3DERR_INVALIDCALL;
5213 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5214 IWineD3DSwapChain *swapChain;
5216 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5217 if(hr == WINED3D_OK) {
5218 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5219 IWineD3DSwapChain_Release(swapChain);
5224 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5226 /* return a sensible default */
5228 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5229 FIXME("(%p) : stub\n", This);
5233 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5236 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5237 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5238 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5239 return WINED3DERR_INVALIDCALL;
5241 for (j = 0; j < 256; ++j) {
5242 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5243 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5244 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5245 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5247 TRACE("(%p) : returning\n", This);
5251 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5254 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5255 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5256 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5257 return WINED3DERR_INVALIDCALL;
5259 for (j = 0; j < 256; ++j) {
5260 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5261 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5262 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5263 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5265 TRACE("(%p) : returning\n", This);
5269 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5272 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5273 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5274 return WINED3DERR_INVALIDCALL;
5276 /*TODO: stateblocks */
5277 This->currentPalette = PaletteNumber;
5278 TRACE("(%p) : returning\n", This);
5282 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5284 if (PaletteNumber == NULL) {
5285 WARN("(%p) : returning Invalid Call\n", This);
5286 return WINED3DERR_INVALIDCALL;
5288 /*TODO: stateblocks */
5289 *PaletteNumber = This->currentPalette;
5290 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5294 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5296 static BOOL showFixmes = TRUE;
5298 FIXME("(%p) : stub\n", This);
5302 This->softwareVertexProcessing = bSoftware;
5307 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5309 static BOOL showFixmes = TRUE;
5311 FIXME("(%p) : stub\n", This);
5314 return This->softwareVertexProcessing;
5318 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5320 IWineD3DSwapChain *swapChain;
5323 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5325 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5326 if(hr == WINED3D_OK){
5327 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5328 IWineD3DSwapChain_Release(swapChain);
5330 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5336 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 static BOOL showfixmes = TRUE;
5339 if(nSegments != 0.0f) {
5341 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5348 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 static BOOL showfixmes = TRUE;
5352 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5358 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5360 /** TODO: remove casts to IWineD3DSurfaceImpl
5361 * NOTE: move code to surface to accomplish this
5362 ****************************************/
5363 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5364 int srcWidth, srcHeight;
5365 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5366 WINED3DFORMAT destFormat, srcFormat;
5368 int srcLeft, destLeft, destTop;
5369 WINED3DPOOL srcPool, destPool;
5371 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5372 glDescriptor *glDescription = NULL;
5375 CONVERT_TYPES convert = NO_CONVERSION;
5377 WINED3DSURFACE_DESC winedesc;
5379 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5380 memset(&winedesc, 0, sizeof(winedesc));
5381 winedesc.Width = &srcSurfaceWidth;
5382 winedesc.Height = &srcSurfaceHeight;
5383 winedesc.Pool = &srcPool;
5384 winedesc.Format = &srcFormat;
5386 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5388 winedesc.Width = &destSurfaceWidth;
5389 winedesc.Height = &destSurfaceHeight;
5390 winedesc.Pool = &destPool;
5391 winedesc.Format = &destFormat;
5392 winedesc.Size = &destSize;
5394 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5396 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5397 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5398 return WINED3DERR_INVALIDCALL;
5401 /* This call loads the opengl surface directly, instead of copying the surface to the
5402 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5403 * copy in sysmem and use regular surface loading.
5405 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5406 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5407 if(convert != NO_CONVERSION) {
5408 return IWineD3DSurface_BltFast(pDestinationSurface,
5409 pDestPoint ? pDestPoint->x : 0,
5410 pDestPoint ? pDestPoint->y : 0,
5411 pSourceSurface, (RECT *) pSourceRect, 0);
5414 if (destFormat == WINED3DFMT_UNKNOWN) {
5415 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5416 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5418 /* Get the update surface description */
5419 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5422 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5426 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5427 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5428 checkGLcall("glActiveTextureARB");
5431 /* Make sure the surface is loaded and up to date */
5432 IWineD3DSurface_PreLoad(pDestinationSurface);
5434 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5436 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5437 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5438 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5439 srcLeft = pSourceRect ? pSourceRect->left : 0;
5440 destLeft = pDestPoint ? pDestPoint->x : 0;
5441 destTop = pDestPoint ? pDestPoint->y : 0;
5444 /* This function doesn't support compressed textures
5445 the pitch is just bytesPerPixel * width */
5446 if(srcWidth != srcSurfaceWidth || srcLeft ){
5447 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5448 offset += srcLeft * pSrcSurface->bytesPerPixel;
5449 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5451 /* TODO DXT formats */
5453 if(pSourceRect != NULL && pSourceRect->top != 0){
5454 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5456 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5458 ,glDescription->level
5463 ,glDescription->glFormat
5464 ,glDescription->glType
5465 ,IWineD3DSurface_GetData(pSourceSurface)
5469 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5471 /* need to lock the surface to get the data */
5472 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5475 /* TODO: Cube and volume support */
5477 /* not a whole row so we have to do it a line at a time */
5480 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5481 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5483 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5485 glTexSubImage2D(glDescription->target
5486 ,glDescription->level
5491 ,glDescription->glFormat
5492 ,glDescription->glType
5493 ,data /* could be quicker using */
5498 } else { /* Full width, so just write out the whole texture */
5500 if (WINED3DFMT_DXT1 == destFormat ||
5501 WINED3DFMT_DXT2 == destFormat ||
5502 WINED3DFMT_DXT3 == destFormat ||
5503 WINED3DFMT_DXT4 == destFormat ||
5504 WINED3DFMT_DXT5 == destFormat) {
5505 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5506 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5507 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5508 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5509 } if (destFormat != srcFormat) {
5510 FIXME("Updating mixed format compressed texture is not curretly support\n");
5512 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5513 glDescription->level,
5514 glDescription->glFormatInternal,
5519 IWineD3DSurface_GetData(pSourceSurface));
5522 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5527 glTexSubImage2D(glDescription->target
5528 ,glDescription->level
5533 ,glDescription->glFormat
5534 ,glDescription->glType
5535 ,IWineD3DSurface_GetData(pSourceSurface)
5539 checkGLcall("glTexSubImage2D");
5543 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5549 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5551 struct WineD3DRectPatch *patch;
5555 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5557 if(!(Handle || pRectPatchInfo)) {
5558 /* TODO: Write a test for the return value, thus the FIXME */
5559 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5560 return WINED3DERR_INVALIDCALL;
5564 i = PATCHMAP_HASHFUNC(Handle);
5566 LIST_FOR_EACH(e, &This->patches[i]) {
5567 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5568 if(patch->Handle == Handle) {
5575 TRACE("Patch does not exist. Creating a new one\n");
5576 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5577 patch->Handle = Handle;
5578 list_add_head(&This->patches[i], &patch->entry);
5580 TRACE("Found existing patch %p\n", patch);
5583 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5584 * attributes we have to tesselate, read back, and draw. This needs a patch
5585 * management structure instance. Create one.
5587 * A possible improvement is to check if a vertex shader is used, and if not directly
5590 FIXME("Drawing an uncached patch. This is slow\n");
5591 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5594 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5595 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5596 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5598 TRACE("Tesselation density or patch info changed, retesselating\n");
5600 if(pRectPatchInfo) {
5601 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5603 patch->numSegs[0] = pNumSegs[0];
5604 patch->numSegs[1] = pNumSegs[1];
5605 patch->numSegs[2] = pNumSegs[2];
5606 patch->numSegs[3] = pNumSegs[3];
5608 hr = tesselate_rectpatch(This, patch);
5610 WARN("Patch tesselation failed\n");
5612 /* Do not release the handle to store the params of the patch */
5614 HeapFree(GetProcessHeap(), 0, patch);
5620 This->currentPatch = patch;
5621 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5622 This->currentPatch = NULL;
5624 /* Destroy uncached patches */
5626 HeapFree(GetProcessHeap(), 0, patch->mem);
5627 HeapFree(GetProcessHeap(), 0, patch);
5632 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5633 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5635 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5636 FIXME("(%p) : Stub\n", This);
5640 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5643 struct WineD3DRectPatch *patch;
5645 TRACE("(%p) Handle(%d)\n", This, Handle);
5647 i = PATCHMAP_HASHFUNC(Handle);
5648 LIST_FOR_EACH(e, &This->patches[i]) {
5649 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5650 if(patch->Handle == Handle) {
5651 TRACE("Deleting patch %p\n", patch);
5652 list_remove(&patch->entry);
5653 HeapFree(GetProcessHeap(), 0, patch->mem);
5654 HeapFree(GetProcessHeap(), 0, patch);
5659 /* TODO: Write a test for the return value */
5660 FIXME("Attempt to destroy nonexistant patch\n");
5661 return WINED3DERR_INVALIDCALL;
5664 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5666 IWineD3DSwapChain *swapchain;
5668 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5669 if (SUCCEEDED(hr)) {
5670 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5677 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5681 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5682 checkGLcall("glGenFramebuffersEXT()");
5684 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5685 checkGLcall("glBindFramebuffer()");
5688 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5689 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5690 IWineD3DBaseTextureImpl *texture_impl;
5691 GLenum texttarget, target;
5694 texttarget = surface_impl->glDescription.target;
5695 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5696 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5698 IWineD3DSurface_PreLoad(surface);
5700 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5701 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5702 glBindTexture(target, old_binding);
5704 /* Update base texture states array */
5705 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5706 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5707 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5708 if (texture_impl->baseTexture.bindCount) {
5709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5712 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5715 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5716 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5718 checkGLcall("attach_surface_fbo");
5721 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5723 IWineD3DSwapChain *swapchain;
5725 swapchain = get_swapchain(surface);
5729 TRACE("Surface %p is onscreen\n", surface);
5731 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5732 buffer = surface_get_gl_buffer(surface, swapchain);
5733 glDrawBuffer(buffer);
5734 checkGLcall("glDrawBuffer()");
5736 TRACE("Surface %p is offscreen\n", surface);
5737 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5738 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5742 glEnable(GL_SCISSOR_TEST);
5744 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5746 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5747 rect->x2 - rect->x1, rect->y2 - rect->y1);
5749 checkGLcall("glScissor");
5751 glDisable(GL_SCISSOR_TEST);
5753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5755 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5756 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5758 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5759 glClear(GL_COLOR_BUFFER_BIT);
5760 checkGLcall("glClear");
5762 if (This->render_offscreen) {
5763 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5765 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5766 checkGLcall("glBindFramebuffer()");
5769 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5770 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5771 glDrawBuffer(GL_BACK);
5772 checkGLcall("glDrawBuffer()");
5776 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5777 unsigned int r, g, b, a;
5780 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5781 destfmt == WINED3DFMT_R8G8B8)
5784 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5786 a = (color & 0xff000000) >> 24;
5787 r = (color & 0x00ff0000) >> 16;
5788 g = (color & 0x0000ff00) >> 8;
5789 b = (color & 0x000000ff) >> 0;
5793 case WINED3DFMT_R5G6B5:
5794 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5801 TRACE("Returning %08x\n", ret);
5804 case WINED3DFMT_X1R5G5B5:
5805 case WINED3DFMT_A1R5G5B5:
5814 TRACE("Returning %08x\n", ret);
5818 TRACE("Returning %08x\n", a);
5821 case WINED3DFMT_X4R4G4B4:
5822 case WINED3DFMT_A4R4G4B4:
5831 TRACE("Returning %08x\n", ret);
5834 case WINED3DFMT_R3G3B2:
5841 TRACE("Returning %08x\n", ret);
5844 case WINED3DFMT_X8B8G8R8:
5845 case WINED3DFMT_A8B8G8R8:
5850 TRACE("Returning %08x\n", ret);
5853 case WINED3DFMT_A2R10G10B10:
5855 r = (r * 1024) / 256;
5856 g = (g * 1024) / 256;
5857 b = (b * 1024) / 256;
5862 TRACE("Returning %08x\n", ret);
5865 case WINED3DFMT_A2B10G10R10:
5867 r = (r * 1024) / 256;
5868 g = (g * 1024) / 256;
5869 b = (b * 1024) / 256;
5874 TRACE("Returning %08x\n", ret);
5878 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5883 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5885 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5887 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5889 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5890 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5891 return WINED3DERR_INVALIDCALL;
5894 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5895 color_fill_fbo(iface, pSurface, pRect, color);
5898 /* Just forward this to the DirectDraw blitting engine */
5899 memset(&BltFx, 0, sizeof(BltFx));
5900 BltFx.dwSize = sizeof(BltFx);
5901 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5902 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5906 /* rendertarget and deptth stencil functions */
5907 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5910 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5911 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5912 return WINED3DERR_INVALIDCALL;
5915 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5916 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5917 /* Note inc ref on returned surface */
5918 if(*ppRenderTarget != NULL)
5919 IWineD3DSurface_AddRef(*ppRenderTarget);
5923 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5925 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5926 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5927 IWineD3DSwapChainImpl *Swapchain;
5930 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5932 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5933 if(hr != WINED3D_OK) {
5934 ERR("Can't get the swapchain\n");
5938 /* Make sure to release the swapchain */
5939 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5941 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5942 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5943 return WINED3DERR_INVALIDCALL;
5945 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5946 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5947 return WINED3DERR_INVALIDCALL;
5950 if(Swapchain->frontBuffer != Front) {
5951 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5953 if(Swapchain->frontBuffer)
5954 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5955 Swapchain->frontBuffer = Front;
5957 if(Swapchain->frontBuffer) {
5958 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5962 if(Back && !Swapchain->backBuffer) {
5963 /* We need memory for the back buffer array - only one back buffer this way */
5964 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5965 if(!Swapchain->backBuffer) {
5966 ERR("Out of memory\n");
5967 return E_OUTOFMEMORY;
5971 if(Swapchain->backBuffer[0] != Back) {
5972 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5974 /* What to do about the context here in the case of multithreading? Not sure.
5975 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5978 if(!Swapchain->backBuffer[0]) {
5979 /* GL was told to draw to the front buffer at creation,
5982 glDrawBuffer(GL_BACK);
5983 checkGLcall("glDrawBuffer(GL_BACK)");
5984 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5985 Swapchain->presentParms.BackBufferCount = 1;
5987 /* That makes problems - disable for now */
5988 /* glDrawBuffer(GL_FRONT); */
5989 checkGLcall("glDrawBuffer(GL_FRONT)");
5990 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5991 Swapchain->presentParms.BackBufferCount = 0;
5995 if(Swapchain->backBuffer[0])
5996 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5997 Swapchain->backBuffer[0] = Back;
5999 if(Swapchain->backBuffer[0]) {
6000 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6002 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6010 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6012 *ppZStencilSurface = This->depthStencilBuffer;
6013 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6015 if(*ppZStencilSurface != NULL) {
6016 /* Note inc ref on returned surface */
6017 IWineD3DSurface_AddRef(*ppZStencilSurface);
6020 return WINED3DERR_NOTFOUND;
6024 /* TODO: Handle stencil attachments */
6025 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6027 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6029 TRACE("Set depth stencil to %p\n", depth_stencil);
6031 if (depth_stencil_impl) {
6032 if (depth_stencil_impl->current_renderbuffer) {
6033 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6034 checkGLcall("glFramebufferRenderbufferEXT()");
6036 IWineD3DBaseTextureImpl *texture_impl;
6037 GLenum texttarget, target;
6038 GLint old_binding = 0;
6040 texttarget = depth_stencil_impl->glDescription.target;
6041 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6042 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6044 IWineD3DSurface_PreLoad(depth_stencil);
6046 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6047 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6048 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6049 glBindTexture(target, old_binding);
6051 /* Update base texture states array */
6052 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6053 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6054 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6055 if (texture_impl->baseTexture.bindCount) {
6056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6059 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6062 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6063 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6064 checkGLcall("glFramebufferTexture2DEXT()");
6067 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6068 checkGLcall("glFramebufferTexture2DEXT()");
6072 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6074 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6076 TRACE("Set render target %u to %p\n", idx, render_target);
6079 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6080 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6082 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6083 checkGLcall("glFramebufferTexture2DEXT()");
6085 This->draw_buffers[idx] = GL_NONE;
6089 static void check_fbo_status(IWineD3DDevice *iface) {
6090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6093 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6094 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6095 TRACE("FBO complete\n");
6097 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6099 /* Dump the FBO attachments */
6100 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6101 IWineD3DSurfaceImpl *attachment;
6104 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6105 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6107 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6108 attachment->pow2Width, attachment->pow2Height);
6111 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6113 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6114 attachment->pow2Width, attachment->pow2Height);
6120 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6122 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6123 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6125 if (!ds_impl) return FALSE;
6127 if (ds_impl->current_renderbuffer) {
6128 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6129 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6132 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6133 rt_impl->pow2Height != ds_impl->pow2Height);
6136 void apply_fbo_state(IWineD3DDevice *iface) {
6137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6140 if (This->render_offscreen) {
6141 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6143 /* Apply render targets */
6144 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6145 IWineD3DSurface *render_target = This->render_targets[i];
6146 if (This->fbo_color_attachments[i] != render_target) {
6147 set_render_target_fbo(iface, i, render_target);
6148 This->fbo_color_attachments[i] = render_target;
6152 /* Apply depth targets */
6153 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6154 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6155 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6157 if (This->stencilBufferTarget) {
6158 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6160 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6161 This->fbo_depth_attachment = This->stencilBufferTarget;
6164 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6165 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6166 checkGLcall("glDrawBuffers()");
6168 glDrawBuffer(This->draw_buffers[0]);
6169 checkGLcall("glDrawBuffer()");
6172 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6175 check_fbo_status(iface);
6178 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6179 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6181 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6182 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6185 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6186 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6187 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6188 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6191 case WINED3DTEXF_LINEAR:
6192 gl_filter = GL_LINEAR;
6196 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6197 case WINED3DTEXF_NONE:
6198 case WINED3DTEXF_POINT:
6199 gl_filter = GL_NEAREST;
6203 /* Attach src surface to src fbo */
6204 src_swapchain = get_swapchain(src_surface);
6205 if (src_swapchain) {
6208 TRACE("Source surface %p is onscreen\n", src_surface);
6209 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6212 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6213 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6214 glReadBuffer(buffer);
6215 checkGLcall("glReadBuffer()");
6217 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6218 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6220 TRACE("Source surface %p is offscreen\n", src_surface);
6222 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6223 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6224 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6225 checkGLcall("glReadBuffer()");
6229 /* Attach dst surface to dst fbo */
6230 dst_swapchain = get_swapchain(dst_surface);
6231 if (dst_swapchain) {
6234 TRACE("Destination surface %p is onscreen\n", dst_surface);
6235 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6238 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6239 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6240 glDrawBuffer(buffer);
6241 checkGLcall("glDrawBuffer()");
6243 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6244 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6246 TRACE("Destination surface %p is offscreen\n", dst_surface);
6248 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6249 if(!src_swapchain) {
6250 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6254 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6255 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6256 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6257 checkGLcall("glDrawBuffer()");
6259 glDisable(GL_SCISSOR_TEST);
6260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6263 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6264 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6265 checkGLcall("glBlitFramebuffer()");
6267 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6268 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6269 checkGLcall("glBlitFramebuffer()");
6272 if (This->render_offscreen) {
6273 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6275 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6276 checkGLcall("glBindFramebuffer()");
6279 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6280 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6281 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6282 glDrawBuffer(GL_BACK);
6283 checkGLcall("glDrawBuffer()");
6288 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6290 WINED3DVIEWPORT viewport;
6292 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6294 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6295 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6296 return WINED3DERR_INVALIDCALL;
6299 /* MSDN says that null disables the render target
6300 but a device must always be associated with a render target
6301 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6303 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6306 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6307 FIXME("Trying to set render target 0 to NULL\n");
6308 return WINED3DERR_INVALIDCALL;
6310 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6311 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);
6312 return WINED3DERR_INVALIDCALL;
6315 /* If we are trying to set what we already have, don't bother */
6316 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6317 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6320 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6321 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6322 This->render_targets[RenderTargetIndex] = pRenderTarget;
6324 /* Render target 0 is special */
6325 if(RenderTargetIndex == 0) {
6326 /* Finally, reset the viewport as the MSDN states. */
6327 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6328 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6331 viewport.MaxZ = 1.0f;
6332 viewport.MinZ = 0.0f;
6333 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6334 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6335 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6339 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6341 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6342 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6344 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6349 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6351 HRESULT hr = WINED3D_OK;
6352 IWineD3DSurface *tmp;
6354 TRACE("(%p) Swapping z-buffer\n",This);
6356 if (pNewZStencil == This->stencilBufferTarget) {
6357 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6359 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6360 * depending on the renter target implementation being used.
6361 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6362 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6363 * stencil buffer and incure an extra memory overhead
6364 ******************************************************/
6366 tmp = This->stencilBufferTarget;
6367 This->stencilBufferTarget = pNewZStencil;
6368 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6369 /* should we be calling the parent or the wined3d surface? */
6370 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6371 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6374 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6375 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6385 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6386 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6388 /* TODO: the use of Impl is deprecated. */
6389 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6390 WINED3DLOCKED_RECT lockedRect;
6392 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6394 /* some basic validation checks */
6395 if(This->cursorTexture) {
6396 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6398 glDeleteTextures(1, &This->cursorTexture);
6400 This->cursorTexture = 0;
6403 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6404 This->haveHardwareCursor = TRUE;
6406 This->haveHardwareCursor = FALSE;
6409 WINED3DLOCKED_RECT rect;
6411 /* MSDN: Cursor must be A8R8G8B8 */
6412 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6413 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6414 return WINED3DERR_INVALIDCALL;
6417 /* MSDN: Cursor must be smaller than the display mode */
6418 if(pSur->currentDesc.Width > This->ddraw_width ||
6419 pSur->currentDesc.Height > This->ddraw_height) {
6420 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);
6421 return WINED3DERR_INVALIDCALL;
6424 if (!This->haveHardwareCursor) {
6425 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6427 /* Do not store the surface's pointer because the application may
6428 * release it after setting the cursor image. Windows doesn't
6429 * addref the set surface, so we can't do this either without
6430 * creating circular refcount dependencies. Copy out the gl texture
6433 This->cursorWidth = pSur->currentDesc.Width;
6434 This->cursorHeight = pSur->currentDesc.Height;
6435 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6437 const GlPixelFormatDesc *glDesc;
6438 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6439 char *mem, *bits = (char *)rect.pBits;
6440 GLint intfmt = glDesc->glInternal;
6441 GLint format = glDesc->glFormat;
6442 GLint type = glDesc->glType;
6443 INT height = This->cursorHeight;
6444 INT width = This->cursorWidth;
6445 INT bpp = tableEntry->bpp;
6448 /* Reformat the texture memory (pitch and width can be
6450 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6451 for(i = 0; i < height; i++)
6452 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6453 IWineD3DSurface_UnlockRect(pCursorBitmap);
6456 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6457 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6458 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6461 /* Make sure that a proper texture unit is selected */
6462 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6463 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6464 checkGLcall("glActiveTextureARB");
6466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6467 /* Create a new cursor texture */
6468 glGenTextures(1, &This->cursorTexture);
6469 checkGLcall("glGenTextures");
6470 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6471 checkGLcall("glBindTexture");
6472 /* Copy the bitmap memory into the cursor texture */
6473 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6474 HeapFree(GetProcessHeap(), 0, mem);
6475 checkGLcall("glTexImage2D");
6477 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6478 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6479 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6486 FIXME("A cursor texture was not returned.\n");
6487 This->cursorTexture = 0;
6492 /* Draw a hardware cursor */
6493 ICONINFO cursorInfo;
6495 /* Create and clear maskBits because it is not needed for
6496 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6498 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6499 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6500 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6501 WINED3DLOCK_NO_DIRTY_UPDATE |
6502 WINED3DLOCK_READONLY
6504 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6505 pSur->currentDesc.Height);
6507 cursorInfo.fIcon = FALSE;
6508 cursorInfo.xHotspot = XHotSpot;
6509 cursorInfo.yHotspot = YHotSpot;
6510 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6511 pSur->currentDesc.Height, 1,
6513 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6514 pSur->currentDesc.Height, 1,
6515 32, lockedRect.pBits);
6516 IWineD3DSurface_UnlockRect(pCursorBitmap);
6517 /* Create our cursor and clean up. */
6518 cursor = CreateIconIndirect(&cursorInfo);
6520 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6521 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6522 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6523 This->hardwareCursor = cursor;
6524 HeapFree(GetProcessHeap(), 0, maskBits);
6528 This->xHotSpot = XHotSpot;
6529 This->yHotSpot = YHotSpot;
6533 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6535 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6537 This->xScreenSpace = XScreenSpace;
6538 This->yScreenSpace = YScreenSpace;
6544 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6546 BOOL oldVisible = This->bCursorVisible;
6549 TRACE("(%p) : visible(%d)\n", This, bShow);
6552 * When ShowCursor is first called it should make the cursor appear at the OS's last
6553 * known cursor position. Because of this, some applications just repetitively call
6554 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6557 This->xScreenSpace = pt.x;
6558 This->yScreenSpace = pt.y;
6560 if (This->haveHardwareCursor) {
6561 This->bCursorVisible = bShow;
6563 SetCursor(This->hardwareCursor);
6569 if (This->cursorTexture)
6570 This->bCursorVisible = bShow;
6576 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6578 TRACE("(%p) : state (%u)\n", This, This->state);
6579 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6580 switch (This->state) {
6583 case WINED3DERR_DEVICELOST:
6585 ResourceList *resourceList = This->resources;
6586 while (NULL != resourceList) {
6587 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6588 return WINED3DERR_DEVICENOTRESET;
6589 resourceList = resourceList->next;
6591 return WINED3DERR_DEVICELOST;
6593 case WINED3DERR_DRIVERINTERNALERROR:
6594 return WINED3DERR_DRIVERINTERNALERROR;
6598 return WINED3DERR_DRIVERINTERNALERROR;
6602 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6604 /** FIXME: Resource tracking needs to be done,
6605 * The closes we can do to this is set the priorities of all managed textures low
6606 * and then reset them.
6607 ***********************************************************/
6608 FIXME("(%p) : stub\n", This);
6612 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6613 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6615 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6616 if(surface->Flags & SFLAG_DIBSECTION) {
6617 /* Release the DC */
6618 SelectObject(surface->hDC, surface->dib.holdbitmap);
6619 DeleteDC(surface->hDC);
6620 /* Release the DIB section */
6621 DeleteObject(surface->dib.DIBsection);
6622 surface->dib.bitmap_data = NULL;
6623 surface->resource.allocatedMemory = NULL;
6624 surface->Flags &= ~SFLAG_DIBSECTION;
6626 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6627 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6628 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6629 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6630 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6632 surface->pow2Width = surface->pow2Height = 1;
6633 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6634 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6636 if(surface->glDescription.textureName) {
6637 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6639 glDeleteTextures(1, &surface->glDescription.textureName);
6641 surface->glDescription.textureName = 0;
6642 surface->Flags &= ~SFLAG_CLIENT;
6644 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6645 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6646 surface->Flags |= SFLAG_NONPOW2;
6648 surface->Flags &= ~SFLAG_NONPOW2;
6650 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6651 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6654 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6656 IWineD3DSwapChainImpl *swapchain;
6658 BOOL DisplayModeChanged = FALSE;
6659 WINED3DDISPLAYMODE mode;
6660 TRACE("(%p)\n", This);
6662 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6664 ERR("Failed to get the first implicit swapchain\n");
6668 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6669 * on an existing gl context, so there's no real need for recreation.
6671 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6673 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6675 TRACE("New params:\n");
6676 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6677 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6678 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6679 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6680 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6681 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6682 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6683 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6684 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6685 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6686 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6687 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6688 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6690 /* No special treatment of these parameters. Just store them */
6691 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6692 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6693 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6694 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6696 /* What to do about these? */
6697 if(pPresentationParameters->BackBufferCount != 0 &&
6698 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6699 ERR("Cannot change the back buffer count yet\n");
6701 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6702 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6703 ERR("Cannot change the back buffer format yet\n");
6705 if(pPresentationParameters->hDeviceWindow != NULL &&
6706 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6707 ERR("Cannot change the device window yet\n");
6709 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6710 ERR("What do do about a changed auto depth stencil parameter?\n");
6713 if(pPresentationParameters->Windowed) {
6714 mode.Width = swapchain->orig_width;
6715 mode.Height = swapchain->orig_height;
6716 mode.RefreshRate = 0;
6717 mode.Format = swapchain->presentParms.BackBufferFormat;
6719 mode.Width = pPresentationParameters->BackBufferWidth;
6720 mode.Height = pPresentationParameters->BackBufferHeight;
6721 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6722 mode.Format = swapchain->presentParms.BackBufferFormat;
6725 /* Should Width == 800 && Height == 0 set 800x600? */
6726 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6727 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6728 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6735 vp.Width = pPresentationParameters->BackBufferWidth;
6736 vp.Height = pPresentationParameters->BackBufferHeight;
6740 if(!pPresentationParameters->Windowed) {
6741 DisplayModeChanged = TRUE;
6743 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6744 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6746 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6747 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6748 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6751 /* Now set the new viewport */
6752 IWineD3DDevice_SetViewport(iface, &vp);
6755 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6756 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6757 DisplayModeChanged) {
6759 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6760 if(!pPresentationParameters->Windowed) {
6761 IWineD3DDevice_SetFullscreen(iface, TRUE);
6764 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6766 /* Switching out of fullscreen mode? First set the original res, then change the window */
6767 if(pPresentationParameters->Windowed) {
6768 IWineD3DDevice_SetFullscreen(iface, FALSE);
6770 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6773 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6777 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6779 /** FIXME: always true at the moment **/
6780 if(!bEnableDialogs) {
6781 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6787 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6789 TRACE("(%p) : pParameters %p\n", This, pParameters);
6791 *pParameters = This->createParms;
6795 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6796 IWineD3DSwapChain *swapchain;
6797 HRESULT hrc = WINED3D_OK;
6799 TRACE("Relaying to swapchain\n");
6801 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6802 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6803 IWineD3DSwapChain_Release(swapchain);
6808 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6809 IWineD3DSwapChain *swapchain;
6810 HRESULT hrc = WINED3D_OK;
6812 TRACE("Relaying to swapchain\n");
6814 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6815 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6816 IWineD3DSwapChain_Release(swapchain);
6822 /** ********************************************************
6823 * Notification functions
6824 ** ********************************************************/
6825 /** This function must be called in the release of a resource when ref == 0,
6826 * the contents of resource must still be correct,
6827 * any handels to other resource held by the caller must be closed
6828 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6829 *****************************************************/
6830 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6832 ResourceList* resourceList;
6834 TRACE("(%p) : resource %p\n", This, resource);
6835 /* add a new texture to the frot of the linked list */
6836 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6837 resourceList->resource = resource;
6839 /* Get the old head */
6840 resourceList->next = This->resources;
6842 This->resources = resourceList;
6843 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6848 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6850 ResourceList* resourceList = NULL;
6851 ResourceList* previousResourceList = NULL;
6853 TRACE("(%p) : resource %p\n", This, resource);
6855 resourceList = This->resources;
6857 while (resourceList != NULL) {
6858 if(resourceList->resource == resource) break;
6859 previousResourceList = resourceList;
6860 resourceList = resourceList->next;
6863 if (resourceList == NULL) {
6864 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6867 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6869 /* make sure we don't leave a hole in the list */
6870 if (previousResourceList != NULL) {
6871 previousResourceList->next = resourceList->next;
6873 This->resources = resourceList->next;
6880 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6884 TRACE("(%p) : resource %p\n", This, resource);
6885 switch(IWineD3DResource_GetType(resource)){
6886 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6887 case WINED3DRTYPE_SURFACE: {
6890 /* Cleanup any FBO attachments if d3d is enabled */
6891 if(This->d3d_initialized) {
6892 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6893 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6895 TRACE("Last active render target destroyed\n");
6896 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6897 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6898 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6899 * and the lastActiveRenderTarget member shouldn't matter
6902 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6903 TRACE("Activating primary back buffer\n");
6904 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6905 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6906 /* Single buffering environment */
6907 TRACE("Activating primary front buffer\n");
6908 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6910 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6911 /* Implicit render target destroyed, that means the device is being destroyed
6912 * whatever we set here, it shouldn't matter
6914 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6917 /* May happen during ddraw uninitialization */
6918 TRACE("Render target set, but swapchain does not exist!\n");
6919 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
6923 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6924 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6925 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6926 set_render_target_fbo(iface, i, NULL);
6927 This->fbo_color_attachments[i] = NULL;
6930 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6931 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6932 set_depth_stencil_fbo(iface, NULL);
6933 This->fbo_depth_attachment = NULL;
6939 case WINED3DRTYPE_TEXTURE:
6940 case WINED3DRTYPE_CUBETEXTURE:
6941 case WINED3DRTYPE_VOLUMETEXTURE:
6942 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6943 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6944 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6945 This->stateBlock->textures[counter] = NULL;
6947 if (This->updateStateBlock != This->stateBlock ){
6948 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6949 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6950 This->updateStateBlock->textures[counter] = NULL;
6955 case WINED3DRTYPE_VOLUME:
6956 /* TODO: nothing really? */
6958 case WINED3DRTYPE_VERTEXBUFFER:
6959 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6962 TRACE("Cleaning up stream pointers\n");
6964 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6965 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6966 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6968 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6969 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6970 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6971 This->updateStateBlock->streamSource[streamNumber] = 0;
6972 /* Set changed flag? */
6975 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) */
6976 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6977 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6978 This->stateBlock->streamSource[streamNumber] = 0;
6981 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6982 else { /* This shouldn't happen */
6983 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6990 case WINED3DRTYPE_INDEXBUFFER:
6991 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6992 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6993 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6994 This->updateStateBlock->pIndexData = NULL;
6997 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6998 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6999 This->stateBlock->pIndexData = NULL;
7005 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7010 /* Remove the resoruce from the resourceStore */
7011 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7013 TRACE("Resource released\n");
7017 /**********************************************************
7018 * IWineD3DDevice VTbl follows
7019 **********************************************************/
7021 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7023 /*** IUnknown methods ***/
7024 IWineD3DDeviceImpl_QueryInterface,
7025 IWineD3DDeviceImpl_AddRef,
7026 IWineD3DDeviceImpl_Release,
7027 /*** IWineD3DDevice methods ***/
7028 IWineD3DDeviceImpl_GetParent,
7029 /*** Creation methods**/
7030 IWineD3DDeviceImpl_CreateVertexBuffer,
7031 IWineD3DDeviceImpl_CreateIndexBuffer,
7032 IWineD3DDeviceImpl_CreateStateBlock,
7033 IWineD3DDeviceImpl_CreateSurface,
7034 IWineD3DDeviceImpl_CreateTexture,
7035 IWineD3DDeviceImpl_CreateVolumeTexture,
7036 IWineD3DDeviceImpl_CreateVolume,
7037 IWineD3DDeviceImpl_CreateCubeTexture,
7038 IWineD3DDeviceImpl_CreateQuery,
7039 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7040 IWineD3DDeviceImpl_CreateVertexDeclaration,
7041 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7042 IWineD3DDeviceImpl_CreateVertexShader,
7043 IWineD3DDeviceImpl_CreatePixelShader,
7044 IWineD3DDeviceImpl_CreatePalette,
7045 /*** Odd functions **/
7046 IWineD3DDeviceImpl_Init3D,
7047 IWineD3DDeviceImpl_Uninit3D,
7048 IWineD3DDeviceImpl_SetFullscreen,
7049 IWineD3DDeviceImpl_SetMultithreaded,
7050 IWineD3DDeviceImpl_EvictManagedResources,
7051 IWineD3DDeviceImpl_GetAvailableTextureMem,
7052 IWineD3DDeviceImpl_GetBackBuffer,
7053 IWineD3DDeviceImpl_GetCreationParameters,
7054 IWineD3DDeviceImpl_GetDeviceCaps,
7055 IWineD3DDeviceImpl_GetDirect3D,
7056 IWineD3DDeviceImpl_GetDisplayMode,
7057 IWineD3DDeviceImpl_SetDisplayMode,
7058 IWineD3DDeviceImpl_GetHWND,
7059 IWineD3DDeviceImpl_SetHWND,
7060 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7061 IWineD3DDeviceImpl_GetRasterStatus,
7062 IWineD3DDeviceImpl_GetSwapChain,
7063 IWineD3DDeviceImpl_Reset,
7064 IWineD3DDeviceImpl_SetDialogBoxMode,
7065 IWineD3DDeviceImpl_SetCursorProperties,
7066 IWineD3DDeviceImpl_SetCursorPosition,
7067 IWineD3DDeviceImpl_ShowCursor,
7068 IWineD3DDeviceImpl_TestCooperativeLevel,
7069 /*** Getters and setters **/
7070 IWineD3DDeviceImpl_SetClipPlane,
7071 IWineD3DDeviceImpl_GetClipPlane,
7072 IWineD3DDeviceImpl_SetClipStatus,
7073 IWineD3DDeviceImpl_GetClipStatus,
7074 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7075 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7076 IWineD3DDeviceImpl_SetDepthStencilSurface,
7077 IWineD3DDeviceImpl_GetDepthStencilSurface,
7078 IWineD3DDeviceImpl_SetFVF,
7079 IWineD3DDeviceImpl_GetFVF,
7080 IWineD3DDeviceImpl_SetGammaRamp,
7081 IWineD3DDeviceImpl_GetGammaRamp,
7082 IWineD3DDeviceImpl_SetIndices,
7083 IWineD3DDeviceImpl_GetIndices,
7084 IWineD3DDeviceImpl_SetBaseVertexIndex,
7085 IWineD3DDeviceImpl_GetBaseVertexIndex,
7086 IWineD3DDeviceImpl_SetLight,
7087 IWineD3DDeviceImpl_GetLight,
7088 IWineD3DDeviceImpl_SetLightEnable,
7089 IWineD3DDeviceImpl_GetLightEnable,
7090 IWineD3DDeviceImpl_SetMaterial,
7091 IWineD3DDeviceImpl_GetMaterial,
7092 IWineD3DDeviceImpl_SetNPatchMode,
7093 IWineD3DDeviceImpl_GetNPatchMode,
7094 IWineD3DDeviceImpl_SetPaletteEntries,
7095 IWineD3DDeviceImpl_GetPaletteEntries,
7096 IWineD3DDeviceImpl_SetPixelShader,
7097 IWineD3DDeviceImpl_GetPixelShader,
7098 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7099 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7100 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7101 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7102 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7103 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7104 IWineD3DDeviceImpl_SetRenderState,
7105 IWineD3DDeviceImpl_GetRenderState,
7106 IWineD3DDeviceImpl_SetRenderTarget,
7107 IWineD3DDeviceImpl_GetRenderTarget,
7108 IWineD3DDeviceImpl_SetFrontBackBuffers,
7109 IWineD3DDeviceImpl_SetSamplerState,
7110 IWineD3DDeviceImpl_GetSamplerState,
7111 IWineD3DDeviceImpl_SetScissorRect,
7112 IWineD3DDeviceImpl_GetScissorRect,
7113 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7114 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7115 IWineD3DDeviceImpl_SetStreamSource,
7116 IWineD3DDeviceImpl_GetStreamSource,
7117 IWineD3DDeviceImpl_SetStreamSourceFreq,
7118 IWineD3DDeviceImpl_GetStreamSourceFreq,
7119 IWineD3DDeviceImpl_SetTexture,
7120 IWineD3DDeviceImpl_GetTexture,
7121 IWineD3DDeviceImpl_SetTextureStageState,
7122 IWineD3DDeviceImpl_GetTextureStageState,
7123 IWineD3DDeviceImpl_SetTransform,
7124 IWineD3DDeviceImpl_GetTransform,
7125 IWineD3DDeviceImpl_SetVertexDeclaration,
7126 IWineD3DDeviceImpl_GetVertexDeclaration,
7127 IWineD3DDeviceImpl_SetVertexShader,
7128 IWineD3DDeviceImpl_GetVertexShader,
7129 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7130 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7131 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7132 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7133 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7134 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7135 IWineD3DDeviceImpl_SetViewport,
7136 IWineD3DDeviceImpl_GetViewport,
7137 IWineD3DDeviceImpl_MultiplyTransform,
7138 IWineD3DDeviceImpl_ValidateDevice,
7139 IWineD3DDeviceImpl_ProcessVertices,
7140 /*** State block ***/
7141 IWineD3DDeviceImpl_BeginStateBlock,
7142 IWineD3DDeviceImpl_EndStateBlock,
7143 /*** Scene management ***/
7144 IWineD3DDeviceImpl_BeginScene,
7145 IWineD3DDeviceImpl_EndScene,
7146 IWineD3DDeviceImpl_Present,
7147 IWineD3DDeviceImpl_Clear,
7149 IWineD3DDeviceImpl_DrawPrimitive,
7150 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7151 IWineD3DDeviceImpl_DrawPrimitiveUP,
7152 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7153 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7154 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7155 IWineD3DDeviceImpl_DrawRectPatch,
7156 IWineD3DDeviceImpl_DrawTriPatch,
7157 IWineD3DDeviceImpl_DeletePatch,
7158 IWineD3DDeviceImpl_ColorFill,
7159 IWineD3DDeviceImpl_UpdateTexture,
7160 IWineD3DDeviceImpl_UpdateSurface,
7161 IWineD3DDeviceImpl_GetFrontBufferData,
7162 /*** object tracking ***/
7163 IWineD3DDeviceImpl_ResourceReleased
7167 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7168 WINED3DRS_ALPHABLENDENABLE ,
7169 WINED3DRS_ALPHAFUNC ,
7170 WINED3DRS_ALPHAREF ,
7171 WINED3DRS_ALPHATESTENABLE ,
7173 WINED3DRS_COLORWRITEENABLE ,
7174 WINED3DRS_DESTBLEND ,
7175 WINED3DRS_DITHERENABLE ,
7176 WINED3DRS_FILLMODE ,
7177 WINED3DRS_FOGDENSITY ,
7179 WINED3DRS_FOGSTART ,
7180 WINED3DRS_LASTPIXEL ,
7181 WINED3DRS_SHADEMODE ,
7182 WINED3DRS_SRCBLEND ,
7183 WINED3DRS_STENCILENABLE ,
7184 WINED3DRS_STENCILFAIL ,
7185 WINED3DRS_STENCILFUNC ,
7186 WINED3DRS_STENCILMASK ,
7187 WINED3DRS_STENCILPASS ,
7188 WINED3DRS_STENCILREF ,
7189 WINED3DRS_STENCILWRITEMASK ,
7190 WINED3DRS_STENCILZFAIL ,
7191 WINED3DRS_TEXTUREFACTOR ,
7202 WINED3DRS_ZWRITEENABLE
7205 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7206 WINED3DTSS_ADDRESSW ,
7207 WINED3DTSS_ALPHAARG0 ,
7208 WINED3DTSS_ALPHAARG1 ,
7209 WINED3DTSS_ALPHAARG2 ,
7210 WINED3DTSS_ALPHAOP ,
7211 WINED3DTSS_BUMPENVLOFFSET ,
7212 WINED3DTSS_BUMPENVLSCALE ,
7213 WINED3DTSS_BUMPENVMAT00 ,
7214 WINED3DTSS_BUMPENVMAT01 ,
7215 WINED3DTSS_BUMPENVMAT10 ,
7216 WINED3DTSS_BUMPENVMAT11 ,
7217 WINED3DTSS_COLORARG0 ,
7218 WINED3DTSS_COLORARG1 ,
7219 WINED3DTSS_COLORARG2 ,
7220 WINED3DTSS_COLOROP ,
7221 WINED3DTSS_RESULTARG ,
7222 WINED3DTSS_TEXCOORDINDEX ,
7223 WINED3DTSS_TEXTURETRANSFORMFLAGS
7226 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7227 WINED3DSAMP_ADDRESSU ,
7228 WINED3DSAMP_ADDRESSV ,
7229 WINED3DSAMP_ADDRESSW ,
7230 WINED3DSAMP_BORDERCOLOR ,
7231 WINED3DSAMP_MAGFILTER ,
7232 WINED3DSAMP_MINFILTER ,
7233 WINED3DSAMP_MIPFILTER ,
7234 WINED3DSAMP_MIPMAPLODBIAS ,
7235 WINED3DSAMP_MAXMIPLEVEL ,
7236 WINED3DSAMP_MAXANISOTROPY ,
7237 WINED3DSAMP_SRGBTEXTURE ,
7238 WINED3DSAMP_ELEMENTINDEX
7241 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7243 WINED3DRS_AMBIENTMATERIALSOURCE ,
7244 WINED3DRS_CLIPPING ,
7245 WINED3DRS_CLIPPLANEENABLE ,
7246 WINED3DRS_COLORVERTEX ,
7247 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7248 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7249 WINED3DRS_FOGDENSITY ,
7251 WINED3DRS_FOGSTART ,
7252 WINED3DRS_FOGTABLEMODE ,
7253 WINED3DRS_FOGVERTEXMODE ,
7254 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7255 WINED3DRS_LIGHTING ,
7256 WINED3DRS_LOCALVIEWER ,
7257 WINED3DRS_MULTISAMPLEANTIALIAS ,
7258 WINED3DRS_MULTISAMPLEMASK ,
7259 WINED3DRS_NORMALIZENORMALS ,
7260 WINED3DRS_PATCHEDGESTYLE ,
7261 WINED3DRS_POINTSCALE_A ,
7262 WINED3DRS_POINTSCALE_B ,
7263 WINED3DRS_POINTSCALE_C ,
7264 WINED3DRS_POINTSCALEENABLE ,
7265 WINED3DRS_POINTSIZE ,
7266 WINED3DRS_POINTSIZE_MAX ,
7267 WINED3DRS_POINTSIZE_MIN ,
7268 WINED3DRS_POINTSPRITEENABLE ,
7269 WINED3DRS_RANGEFOGENABLE ,
7270 WINED3DRS_SPECULARMATERIALSOURCE ,
7271 WINED3DRS_TWEENFACTOR ,
7272 WINED3DRS_VERTEXBLEND ,
7273 WINED3DRS_CULLMODE ,
7277 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7278 WINED3DTSS_TEXCOORDINDEX ,
7279 WINED3DTSS_TEXTURETRANSFORMFLAGS
7282 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7283 WINED3DSAMP_DMAPOFFSET
7286 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7287 DWORD rep = StateTable[state].representative;
7291 WineD3DContext *context;
7294 for(i = 0; i < This->numContexts; i++) {
7295 context = This->contexts[i];
7296 if(isStateDirty(context, rep)) continue;
7298 context->dirtyArray[context->numDirtyEntries++] = rep;
7301 context->isStateDirty[idx] |= (1 << shift);