wined3d: Add a few missing checkGLcall calls.
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blob61e388866fc46bb5028388ce296f6cc2455cb886
1 /*
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 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
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->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 */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
143 /**********************************************************
144 * Global variable / Constants follow
145 **********************************************************/
146 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
148 /**********************************************************
149 * IUnknown parts follows
150 **********************************************************/
152 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
157 if (IsEqualGUID(riid, &IID_IUnknown)
158 || IsEqualGUID(riid, &IID_IWineD3DBase)
159 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
160 IUnknown_AddRef(iface);
161 *ppobj = This;
162 return S_OK;
164 *ppobj = NULL;
165 return E_NOINTERFACE;
168 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
170 ULONG refCount = InterlockedIncrement(&This->ref);
172 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
173 return refCount;
176 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
178 ULONG refCount = InterlockedDecrement(&This->ref);
180 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
182 if (!refCount) {
183 if (This->fbo) {
184 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
186 if (This->src_fbo) {
187 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
189 if (This->dst_fbo) {
190 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
193 HeapFree(GetProcessHeap(), 0, This->render_targets);
194 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
195 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
197 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
199 /* TODO: Clean up all the surfaces and textures! */
200 /* NOTE: You must release the parent if the object was created via a callback
201 ** ***************************/
203 /* Release the update stateblock */
204 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
205 if(This->updateStateBlock != This->stateBlock)
206 FIXME("(%p) Something's still holding the Update stateblock\n",This);
208 This->updateStateBlock = NULL;
209 { /* because were not doing proper internal refcounts releasing the primary state block
210 causes recursion with the extra checks in ResourceReleased, to avoid this we have
211 to set this->stateBlock = NULL; first */
212 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
213 This->stateBlock = NULL;
215 /* Release the stateblock */
216 if(IWineD3DStateBlock_Release(stateBlock) > 0){
217 FIXME("(%p) Something's still holding the Update stateblock\n",This);
221 if (This->resources != NULL ) {
222 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
223 dumpResources(This->resources);
226 if(This->contexts) ERR("Context array not freed!\n");
227 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
228 This->haveHardwareCursor = FALSE;
230 IWineD3D_Release(This->wineD3D);
231 This->wineD3D = NULL;
232 HeapFree(GetProcessHeap(), 0, This);
233 TRACE("Freed device %p\n", This);
234 This = NULL;
236 return refCount;
239 /**********************************************************
240 * IWineD3DDevice implementation follows
241 **********************************************************/
242 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
244 *pParent = This->parent;
245 IUnknown_AddRef(This->parent);
246 return WINED3D_OK;
249 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
250 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
251 GLenum error, glUsage;
252 DWORD vboUsage = object->resource.usage;
253 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
254 WARN("Creating a vbo failed once, not trying again\n");
255 return;
258 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
260 ENTER_GL();
261 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
262 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
264 /* Make sure that the gl error is cleared. Do not use checkGLcall
265 * here because checkGLcall just prints a fixme and continues. However,
266 * if an error during VBO creation occurs we can fall back to non-vbo operation
267 * with full functionality(but performance loss)
269 while(glGetError() != GL_NO_ERROR);
271 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
272 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
273 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
274 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
275 * to check if the rhw and color values are in the correct format.
278 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
279 error = glGetError();
280 if(object->vbo == 0 || error != GL_NO_ERROR) {
281 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
282 goto error;
285 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
286 error = glGetError();
287 if(error != GL_NO_ERROR) {
288 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
289 goto error;
292 /* Don't use static, because dx apps tend to update the buffer
293 * quite often even if they specify 0 usage. Because we always keep the local copy
294 * we never read from the vbo and can create a write only opengl buffer.
296 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
297 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
298 case WINED3DUSAGE_DYNAMIC:
299 TRACE("Gl usage = GL_STREAM_DRAW\n");
300 glUsage = GL_STREAM_DRAW_ARB;
301 break;
302 case WINED3DUSAGE_WRITEONLY:
303 default:
304 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
305 glUsage = GL_DYNAMIC_DRAW_ARB;
306 break;
309 /* Reserve memory for the buffer. The amount of data won't change
310 * so we are safe with calling glBufferData once with a NULL ptr and
311 * calling glBufferSubData on updates
313 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
314 error = glGetError();
315 if(error != GL_NO_ERROR) {
316 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
317 goto error;
320 LEAVE_GL();
322 return;
323 error:
324 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
325 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
326 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
327 object->vbo = 0;
328 object->Flags |= VBFLAG_VBOCREATEFAIL;
329 LEAVE_GL();
330 return;
333 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
334 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
335 IUnknown *parent) {
336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
337 IWineD3DVertexBufferImpl *object;
338 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
339 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
340 BOOL conv;
342 if(Size == 0) {
343 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
344 *ppVertexBuffer = NULL;
345 return WINED3DERR_INVALIDCALL;
348 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
350 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
351 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
353 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
354 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
356 object->fvf = FVF;
358 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
359 * drawStridedFast (half-life 2).
361 * Basically converting the vertices in the buffer is quite expensive, and observations
362 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
363 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
365 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
366 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
367 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
368 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
369 * dx7 apps.
370 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
371 * more. In this call we can convert dx7 buffers too.
373 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
374 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
375 (dxVersion > 7 || !conv) ) {
376 CreateVBO(object);
378 return WINED3D_OK;
381 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
382 GLenum error, glUsage;
383 TRACE("Creating VBO for Index Buffer %p\n", object);
385 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
386 * restored on the next draw
388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
390 ENTER_GL();
391 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
392 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
394 while(glGetError());
396 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
397 error = glGetError();
398 if(error != GL_NO_ERROR || object->vbo == 0) {
399 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
400 goto out;
403 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
404 error = glGetError();
405 if(error != GL_NO_ERROR) {
406 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
407 goto out;
410 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
411 * copy no readback will be needed
413 glUsage = GL_STATIC_DRAW_ARB;
414 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
415 error = glGetError();
416 if(error != GL_NO_ERROR) {
417 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
418 goto out;
420 LEAVE_GL();
421 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
422 return;
424 out:
425 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
426 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
427 LEAVE_GL();
428 object->vbo = 0;
431 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
432 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
433 HANDLE *sharedHandle, IUnknown *parent) {
434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
435 IWineD3DIndexBufferImpl *object;
436 TRACE("(%p) Creating index buffer\n", This);
438 /* Allocate the storage for the device */
439 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
441 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
442 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
445 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
446 CreateIndexBufferVBO(This, object);
449 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
450 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
451 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
453 return WINED3D_OK;
456 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
459 IWineD3DStateBlockImpl *object;
460 int i, j;
461 HRESULT temp_result;
463 D3DCREATEOBJECTINSTANCE(object, StateBlock)
464 object->blockType = Type;
466 for(i = 0; i < LIGHTMAP_SIZE; i++) {
467 list_init(&object->lightMap[i]);
470 /* Special case - Used during initialization to produce a placeholder stateblock
471 so other functions called can update a state block */
472 if (Type == WINED3DSBT_INIT) {
473 /* Don't bother increasing the reference count otherwise a device will never
474 be freed due to circular dependencies */
475 return WINED3D_OK;
478 temp_result = allocate_shader_constants(object);
479 if (WINED3D_OK != temp_result)
480 return temp_result;
482 /* Otherwise, might as well set the whole state block to the appropriate values */
483 if (This->stateBlock != NULL)
484 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
485 else
486 memset(object->streamFreq, 1, sizeof(object->streamFreq));
488 /* Reset the ref and type after kludging it */
489 object->wineD3DDevice = This;
490 object->ref = 1;
491 object->blockType = Type;
493 TRACE("Updating changed flags appropriate for type %d\n", Type);
495 if (Type == WINED3DSBT_ALL) {
497 TRACE("ALL => Pretend everything has changed\n");
498 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
500 /* Lights are not part of the changed / set structure */
501 for(j = 0; j < LIGHTMAP_SIZE; j++) {
502 struct list *e;
503 LIST_FOR_EACH(e, &object->lightMap[j]) {
504 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
505 light->changed = TRUE;
506 light->enabledChanged = TRUE;
509 } else if (Type == WINED3DSBT_PIXELSTATE) {
511 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
512 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
514 object->changed.pixelShader = TRUE;
516 /* Pixel Shader Constants */
517 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
518 object->changed.pixelShaderConstantsF[i] = TRUE;
519 for (i = 0; i < MAX_CONST_B; ++i)
520 object->changed.pixelShaderConstantsB[i] = TRUE;
521 for (i = 0; i < MAX_CONST_I; ++i)
522 object->changed.pixelShaderConstantsI[i] = TRUE;
524 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
525 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
527 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
528 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
529 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
532 for (j = 0 ; j < 16; j++) {
533 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
535 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
539 } else if (Type == WINED3DSBT_VERTEXSTATE) {
541 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
542 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
544 object->changed.vertexShader = TRUE;
546 /* Vertex Shader Constants */
547 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
548 object->changed.vertexShaderConstantsF[i] = TRUE;
549 for (i = 0; i < MAX_CONST_B; ++i)
550 object->changed.vertexShaderConstantsB[i] = TRUE;
551 for (i = 0; i < MAX_CONST_I; ++i)
552 object->changed.vertexShaderConstantsI[i] = TRUE;
554 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
555 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
557 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
558 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
559 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
562 for (j = 0 ; j < 16; j++){
563 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
564 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
568 for(j = 0; j < LIGHTMAP_SIZE; j++) {
569 struct list *e;
570 LIST_FOR_EACH(e, &object->lightMap[j]) {
571 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
572 light->changed = TRUE;
573 light->enabledChanged = TRUE;
576 } else {
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
581 return WINED3D_OK;
584 /* ************************************
585 MSDN:
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
588 Discard
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
593 ******************************** */
595 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int pow2Width, pow2Height;
599 unsigned int Size = 1;
600 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
601 TRACE("(%p) Create surface\n",This);
603 /** FIXME: Check ranges on the inputs are valid
604 * MSDN
605 * MultisampleQuality
606 * [in] Quality level. The valid range is between zero and one less than the level
607 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
608 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
609 * values of paired render targets, depth stencil surfaces, and the MultiSample type
610 * must all match.
611 *******************************/
615 * TODO: Discard MSDN
616 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
618 * If this flag is set, the contents of the depth stencil buffer will be
619 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
620 * with a different depth surface.
622 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
623 ***************************/
625 if(MultisampleQuality < 0) {
626 FIXME("Invalid multisample level %d\n", MultisampleQuality);
627 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
630 if(MultisampleQuality > 0) {
631 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
632 MultisampleQuality=0;
635 /** FIXME: Check that the format is supported
636 * by the device.
637 *******************************/
639 /* Non-power2 support */
640 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
641 pow2Width = Width;
642 pow2Height = Height;
643 } else {
644 /* Find the nearest pow2 match */
645 pow2Width = pow2Height = 1;
646 while (pow2Width < Width) pow2Width <<= 1;
647 while (pow2Height < Height) pow2Height <<= 1;
650 if (pow2Width > Width || pow2Height > Height) {
651 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
652 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
653 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
654 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
655 This, Width, Height);
656 return WINED3DERR_NOTAVAILABLE;
660 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
661 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
662 * space!
663 *********************************/
664 if (WINED3DFMT_UNKNOWN == Format) {
665 Size = 0;
666 } else if (Format == WINED3DFMT_DXT1) {
667 /* DXT1 is half byte per pixel */
668 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
670 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
671 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
672 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
673 } else {
674 /* The pitch is a multiple of 4 bytes */
675 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
676 Size *= Height;
679 /** Create and initialise the surface resource **/
680 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
681 /* "Standalone" surface */
682 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
684 object->currentDesc.Width = Width;
685 object->currentDesc.Height = Height;
686 object->currentDesc.MultiSampleType = MultiSample;
687 object->currentDesc.MultiSampleQuality = MultisampleQuality;
689 /* Setup some glformat defaults */
690 object->glDescription.glFormat = tableEntry->glFormat;
691 object->glDescription.glFormatInternal = tableEntry->glInternal;
692 object->glDescription.glType = tableEntry->glType;
694 object->glDescription.textureName = 0;
695 object->glDescription.level = Level;
696 object->glDescription.target = GL_TEXTURE_2D;
698 /* Internal data */
699 object->pow2Width = pow2Width;
700 object->pow2Height = pow2Height;
702 /* Flags */
703 object->Flags = SFLAG_DYNLOCK;
704 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
705 object->Flags |= Discard ? SFLAG_DISCARD : 0;
706 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
707 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
710 if (WINED3DFMT_UNKNOWN != Format) {
711 object->bytesPerPixel = tableEntry->bpp;
712 } else {
713 object->bytesPerPixel = 0;
716 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
718 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
720 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
721 * this function is too deep to need to care about things like this.
722 * Levels need to be checked too, and possibly Type since they all affect what can be done.
723 * ****************************************/
724 switch(Pool) {
725 case WINED3DPOOL_SCRATCH:
726 if(!Lockable)
727 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
728 "which are mutually exclusive, setting lockable to TRUE\n");
729 Lockable = TRUE;
730 break;
731 case WINED3DPOOL_SYSTEMMEM:
732 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
733 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
734 case WINED3DPOOL_MANAGED:
735 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
736 "Usage of DYNAMIC which are mutually exclusive, not doing "
737 "anything just telling you.\n");
738 break;
739 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
740 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
741 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
742 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
743 break;
744 default:
745 FIXME("(%p) Unknown pool %d\n", This, Pool);
746 break;
749 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
750 FIXME("Trying to create a render target that isn't in the default pool\n");
753 /* mark the texture as dirty so that it gets loaded first time around*/
754 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
755 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
756 This, Width, Height, Format, debug_d3dformat(Format),
757 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
759 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
760 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
761 This->ddraw_primary = (IWineD3DSurface *) object;
763 /* Look at the implementation and set the correct Vtable */
764 switch(Impl) {
765 case SURFACE_OPENGL:
766 /* Nothing to do, it's set already */
767 break;
769 case SURFACE_GDI:
770 object->lpVtbl = &IWineGDISurface_Vtbl;
771 break;
773 default:
774 /* To be sure to catch this */
775 ERR("Unknown requested surface implementation %d!\n", Impl);
776 IWineD3DSurface_Release((IWineD3DSurface *) object);
777 return WINED3DERR_INVALIDCALL;
780 list_init(&object->renderbuffers);
782 /* Call the private setup routine */
783 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
788 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
789 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
790 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
793 IWineD3DTextureImpl *object;
794 unsigned int i;
795 UINT tmpW;
796 UINT tmpH;
797 HRESULT hr;
798 unsigned int pow2Width;
799 unsigned int pow2Height;
802 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
803 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
804 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
806 /* TODO: It should only be possible to create textures for formats
807 that are reported as supported */
808 if (WINED3DFMT_UNKNOWN >= Format) {
809 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
810 return WINED3DERR_INVALIDCALL;
813 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
814 D3DINITIALIZEBASETEXTURE(object->baseTexture);
815 object->width = Width;
816 object->height = Height;
818 /** Non-power2 support **/
819 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
820 pow2Width = Width;
821 pow2Height = Height;
822 } else {
823 /* Find the nearest pow2 match */
824 pow2Width = pow2Height = 1;
825 while (pow2Width < Width) pow2Width <<= 1;
826 while (pow2Height < Height) pow2Height <<= 1;
829 /** FIXME: add support for real non-power-two if it's provided by the video card **/
830 /* Precalculated scaling for 'faked' non power of two texture coords */
831 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
832 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
833 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
835 /* Calculate levels for mip mapping */
836 if (Levels == 0) {
837 TRACE("calculating levels %d\n", object->baseTexture.levels);
838 object->baseTexture.levels++;
839 tmpW = Width;
840 tmpH = Height;
841 while (tmpW > 1 || tmpH > 1) {
842 tmpW = max(1, tmpW >> 1);
843 tmpH = max(1, tmpH >> 1);
844 object->baseTexture.levels++;
846 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
849 /* Generate all the surfaces */
850 tmpW = Width;
851 tmpH = Height;
852 for (i = 0; i < object->baseTexture.levels; i++)
854 /* use the callback to create the texture surface */
855 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
856 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
857 FIXME("Failed to create surface %p\n", object);
858 /* clean up */
859 object->surfaces[i] = NULL;
860 IWineD3DTexture_Release((IWineD3DTexture *)object);
862 *ppTexture = NULL;
863 return hr;
866 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
867 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
868 /* calculate the next mipmap level */
869 tmpW = max(1, tmpW >> 1);
870 tmpH = max(1, tmpH >> 1);
873 TRACE("(%p) : Created texture %p\n", This, object);
874 return WINED3D_OK;
877 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
878 UINT Width, UINT Height, UINT Depth,
879 UINT Levels, DWORD Usage,
880 WINED3DFORMAT Format, WINED3DPOOL Pool,
881 IWineD3DVolumeTexture **ppVolumeTexture,
882 HANDLE *pSharedHandle, IUnknown *parent,
883 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
886 IWineD3DVolumeTextureImpl *object;
887 unsigned int i;
888 UINT tmpW;
889 UINT tmpH;
890 UINT tmpD;
892 /* TODO: It should only be possible to create textures for formats
893 that are reported as supported */
894 if (WINED3DFMT_UNKNOWN >= Format) {
895 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
896 return WINED3DERR_INVALIDCALL;
899 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
900 D3DINITIALIZEBASETEXTURE(object->baseTexture);
902 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
903 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
905 object->width = Width;
906 object->height = Height;
907 object->depth = Depth;
909 /* Calculate levels for mip mapping */
910 if (Levels == 0) {
911 object->baseTexture.levels++;
912 tmpW = Width;
913 tmpH = Height;
914 tmpD = Depth;
915 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
916 tmpW = max(1, tmpW >> 1);
917 tmpH = max(1, tmpH >> 1);
918 tmpD = max(1, tmpD >> 1);
919 object->baseTexture.levels++;
921 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
924 /* Generate all the surfaces */
925 tmpW = Width;
926 tmpH = Height;
927 tmpD = Depth;
929 for (i = 0; i < object->baseTexture.levels; i++)
931 HRESULT hr;
932 /* Create the volume */
933 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
934 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
936 if(FAILED(hr)) {
937 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
938 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
939 *ppVolumeTexture = NULL;
940 return hr;
943 /* Set its container to this object */
944 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
946 /* calcualte the next mipmap level */
947 tmpW = max(1, tmpW >> 1);
948 tmpH = max(1, tmpH >> 1);
949 tmpD = max(1, tmpD >> 1);
952 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
953 TRACE("(%p) : Created volume texture %p\n", This, object);
954 return WINED3D_OK;
957 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
958 UINT Width, UINT Height, UINT Depth,
959 DWORD Usage,
960 WINED3DFORMAT Format, WINED3DPOOL Pool,
961 IWineD3DVolume** ppVolume,
962 HANDLE* pSharedHandle, IUnknown *parent) {
964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
965 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
966 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
968 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
970 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
971 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
973 object->currentDesc.Width = Width;
974 object->currentDesc.Height = Height;
975 object->currentDesc.Depth = Depth;
976 object->bytesPerPixel = formatDesc->bpp;
978 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
979 object->lockable = TRUE;
980 object->locked = FALSE;
981 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
982 object->dirty = TRUE;
984 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
987 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
988 UINT Levels, DWORD Usage,
989 WINED3DFORMAT Format, WINED3DPOOL Pool,
990 IWineD3DCubeTexture **ppCubeTexture,
991 HANDLE *pSharedHandle, IUnknown *parent,
992 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
995 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
996 unsigned int i, j;
997 UINT tmpW;
998 HRESULT hr;
999 unsigned int pow2EdgeLength = EdgeLength;
1001 /* TODO: It should only be possible to create textures for formats
1002 that are reported as supported */
1003 if (WINED3DFMT_UNKNOWN >= Format) {
1004 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1005 return WINED3DERR_INVALIDCALL;
1008 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1009 WARN("(%p) : Tried to create not supported cube texture\n", This);
1010 return WINED3DERR_INVALIDCALL;
1013 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1014 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1016 TRACE("(%p) Create Cube Texture\n", This);
1018 /** Non-power2 support **/
1020 /* Find the nearest pow2 match */
1021 pow2EdgeLength = 1;
1022 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1024 object->edgeLength = EdgeLength;
1025 /* TODO: support for native non-power 2 */
1026 /* Precalculated scaling for 'faked' non power of two texture coords */
1027 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1029 /* Calculate levels for mip mapping */
1030 if (Levels == 0) {
1031 object->baseTexture.levels++;
1032 tmpW = EdgeLength;
1033 while (tmpW > 1) {
1034 tmpW = max(1, tmpW >> 1);
1035 object->baseTexture.levels++;
1037 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1040 /* Generate all the surfaces */
1041 tmpW = EdgeLength;
1042 for (i = 0; i < object->baseTexture.levels; i++) {
1044 /* Create the 6 faces */
1045 for (j = 0; j < 6; j++) {
1047 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1048 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1050 if(hr!= WINED3D_OK) {
1051 /* clean up */
1052 int k;
1053 int l;
1054 for (l = 0; l < j; l++) {
1055 IWineD3DSurface_Release(object->surfaces[j][i]);
1057 for (k = 0; k < i; k++) {
1058 for (l = 0; l < 6; l++) {
1059 IWineD3DSurface_Release(object->surfaces[l][j]);
1063 FIXME("(%p) Failed to create surface\n",object);
1064 HeapFree(GetProcessHeap(),0,object);
1065 *ppCubeTexture = NULL;
1066 return hr;
1068 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1069 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1071 tmpW = max(1, tmpW >> 1);
1074 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1075 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1076 return WINED3D_OK;
1079 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1081 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1082 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1084 /* Just a check to see if we support this type of query */
1085 switch(Type) {
1086 case WINED3DQUERYTYPE_OCCLUSION:
1087 TRACE("(%p) occlusion query\n", This);
1088 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1089 hr = WINED3D_OK;
1090 else
1091 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1092 break;
1094 case WINED3DQUERYTYPE_EVENT:
1095 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1096 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1097 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1099 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1101 hr = WINED3D_OK;
1102 break;
1104 case WINED3DQUERYTYPE_VCACHE:
1105 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1106 case WINED3DQUERYTYPE_VERTEXSTATS:
1107 case WINED3DQUERYTYPE_TIMESTAMP:
1108 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1109 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1110 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1111 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1112 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1113 case WINED3DQUERYTYPE_PIXELTIMINGS:
1114 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1115 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1116 default:
1117 FIXME("(%p) Unhandled query type %d\n", This, Type);
1119 if(NULL == ppQuery || hr != WINED3D_OK) {
1120 return hr;
1123 D3DCREATEOBJECTINSTANCE(object, Query)
1124 object->type = Type;
1125 /* allocated the 'extended' data based on the type of query requested */
1126 switch(Type){
1127 case WINED3DQUERYTYPE_OCCLUSION:
1128 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1129 TRACE("(%p) Allocating data for an occlusion query\n", This);
1130 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1131 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1132 break;
1134 case WINED3DQUERYTYPE_EVENT:
1135 /* TODO: GL_APPLE_fence */
1136 if(GL_SUPPORT(APPLE_FENCE)) {
1137 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1138 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1139 checkGLcall("glGenFencesAPPLE");
1140 } else if(GL_SUPPORT(NV_FENCE)) {
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1142 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1143 checkGLcall("glGenFencesNV");
1145 break;
1147 case WINED3DQUERYTYPE_VCACHE:
1148 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1149 case WINED3DQUERYTYPE_VERTEXSTATS:
1150 case WINED3DQUERYTYPE_TIMESTAMP:
1151 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1152 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1153 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1154 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1155 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1156 case WINED3DQUERYTYPE_PIXELTIMINGS:
1157 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1158 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1159 default:
1160 object->extendedData = 0;
1161 FIXME("(%p) Unhandled query type %d\n",This , Type);
1163 TRACE("(%p) : Created Query %p\n", This, object);
1164 return WINED3D_OK;
1167 /*****************************************************************************
1168 * IWineD3DDeviceImpl_SetupFullscreenWindow
1170 * Helper function that modifies a HWND's Style and ExStyle for proper
1171 * fullscreen use.
1173 * Params:
1174 * iface: Pointer to the IWineD3DDevice interface
1175 * window: Window to setup
1177 *****************************************************************************/
1178 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1181 LONG style, exStyle;
1182 /* Don't do anything if an original style is stored.
1183 * That shouldn't happen
1185 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1186 if (This->style || This->exStyle) {
1187 ERR("(%p): Want to change the window parameters of HWND %p, but "
1188 "another style is stored for restoration afterwards\n", This, window);
1191 /* Get the parameters and save them */
1192 style = GetWindowLongW(window, GWL_STYLE);
1193 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1194 This->style = style;
1195 This->exStyle = exStyle;
1197 /* Filter out window decorations */
1198 style &= ~WS_CAPTION;
1199 style &= ~WS_THICKFRAME;
1200 exStyle &= ~WS_EX_WINDOWEDGE;
1201 exStyle &= ~WS_EX_CLIENTEDGE;
1203 /* Make sure the window is managed, otherwise we won't get keyboard input */
1204 style |= WS_POPUP | WS_SYSMENU;
1206 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1207 This->style, This->exStyle, style, exStyle);
1209 SetWindowLongW(window, GWL_STYLE, style);
1210 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1212 /* Inform the window about the update. */
1213 SetWindowPos(window, HWND_TOP, 0, 0,
1214 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1215 ShowWindow(window, SW_NORMAL);
1218 /*****************************************************************************
1219 * IWineD3DDeviceImpl_RestoreWindow
1221 * Helper function that restores a windows' properties when taking it out
1222 * of fullscreen mode
1224 * Params:
1225 * iface: Pointer to the IWineD3DDevice interface
1226 * window: Window to setup
1228 *****************************************************************************/
1229 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1232 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1233 * switch, do nothing
1235 if (!This->style && !This->exStyle) return;
1237 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1238 This, window, This->style, This->exStyle);
1240 SetWindowLongW(window, GWL_STYLE, This->style);
1241 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1243 /* Delete the old values */
1244 This->style = 0;
1245 This->exStyle = 0;
1247 /* Inform the window about the update */
1248 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1249 0, 0, 0, 0, /* Pos, Size, ignored */
1250 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1253 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1254 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1255 IUnknown* parent,
1256 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1257 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1260 HDC hDc;
1261 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1262 HRESULT hr = WINED3D_OK;
1263 IUnknown *bufferParent;
1264 Display *display;
1266 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1268 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1269 * does a device hold a reference to a swap chain giving them a lifetime of the device
1270 * or does the swap chain notify the device of its destruction.
1271 *******************************/
1273 /* Check the params */
1274 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1275 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1276 return WINED3DERR_INVALIDCALL;
1277 } else if (pPresentationParameters->BackBufferCount > 1) {
1278 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");
1281 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1283 /*********************
1284 * Lookup the window Handle and the relating X window handle
1285 ********************/
1287 /* Setup hwnd we are using, plus which display this equates to */
1288 object->win_handle = pPresentationParameters->hDeviceWindow;
1289 if (!object->win_handle) {
1290 object->win_handle = This->createParms.hFocusWindow;
1293 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1294 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1295 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1296 return WINED3DERR_NOTAVAILABLE;
1298 hDc = GetDC(object->win_handle);
1299 display = get_display(hDc);
1300 ReleaseDC(object->win_handle, hDc);
1301 TRACE("Using a display of %p %p\n", display, hDc);
1303 if (NULL == display || NULL == hDc) {
1304 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1305 return WINED3DERR_NOTAVAILABLE;
1308 if (object->win == 0) {
1309 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1310 return WINED3DERR_NOTAVAILABLE;
1313 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1314 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1315 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1317 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1318 * then the corresponding dimension of the client area of the hDeviceWindow
1319 * (or the focus window, if hDeviceWindow is NULL) is taken.
1320 **********************/
1322 if (pPresentationParameters->Windowed &&
1323 ((pPresentationParameters->BackBufferWidth == 0) ||
1324 (pPresentationParameters->BackBufferHeight == 0))) {
1326 RECT Rect;
1327 GetClientRect(object->win_handle, &Rect);
1329 if (pPresentationParameters->BackBufferWidth == 0) {
1330 pPresentationParameters->BackBufferWidth = Rect.right;
1331 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1333 if (pPresentationParameters->BackBufferHeight == 0) {
1334 pPresentationParameters->BackBufferHeight = Rect.bottom;
1335 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1339 /* Put the correct figures in the presentation parameters */
1340 TRACE("Copying across presentation parameters\n");
1341 object->presentParms = *pPresentationParameters;
1343 TRACE("calling rendertarget CB\n");
1344 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1345 parent,
1346 object->presentParms.BackBufferWidth,
1347 object->presentParms.BackBufferHeight,
1348 object->presentParms.BackBufferFormat,
1349 object->presentParms.MultiSampleType,
1350 object->presentParms.MultiSampleQuality,
1351 TRUE /* Lockable */,
1352 &object->frontBuffer,
1353 NULL /* pShared (always null)*/);
1354 if (object->frontBuffer != NULL) {
1355 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1356 } else {
1357 ERR("Failed to create the front buffer\n");
1358 goto error;
1362 * Create an opengl context for the display visual
1363 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1364 * use different properties after that point in time. FIXME: How to handle when requested format
1365 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1366 * it chooses is identical to the one already being used!
1367 **********************************/
1368 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1370 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1371 if(!object->context)
1372 return E_OUTOFMEMORY;
1373 object->num_contexts = 1;
1375 ENTER_GL();
1376 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1377 LEAVE_GL();
1379 if (!object->context[0]) {
1380 ERR("Failed to create a new context\n");
1381 hr = WINED3DERR_NOTAVAILABLE;
1382 goto error;
1383 } else {
1384 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1385 object->win_handle, object->context[0]->glCtx, object->win);
1388 /*********************
1389 * Windowed / Fullscreen
1390 *******************/
1393 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1394 * so we should really check to see if there is a fullscreen swapchain already
1395 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1396 **************************************/
1398 if (!pPresentationParameters->Windowed) {
1400 DEVMODEW devmode;
1401 HDC hdc;
1402 int bpp = 0;
1403 RECT clip_rc;
1405 /* Get info on the current display setup */
1406 hdc = GetDC(0);
1407 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1408 ReleaseDC(0, hdc);
1410 /* Change the display settings */
1411 memset(&devmode, 0, sizeof(DEVMODEW));
1412 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1413 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1414 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1415 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1416 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1417 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1419 /* For GetDisplayMode */
1420 This->ddraw_width = devmode.dmPelsWidth;
1421 This->ddraw_height = devmode.dmPelsHeight;
1422 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1424 IWineD3DDevice_SetFullscreen(iface, TRUE);
1426 /* And finally clip mouse to our screen */
1427 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1428 ClipCursor(&clip_rc);
1431 /*********************
1432 * Create the back, front and stencil buffers
1433 *******************/
1434 if(object->presentParms.BackBufferCount > 0) {
1435 int i;
1437 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1438 if(!object->backBuffer) {
1439 ERR("Out of memory\n");
1440 hr = E_OUTOFMEMORY;
1441 goto error;
1444 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1445 TRACE("calling rendertarget CB\n");
1446 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1447 parent,
1448 object->presentParms.BackBufferWidth,
1449 object->presentParms.BackBufferHeight,
1450 object->presentParms.BackBufferFormat,
1451 object->presentParms.MultiSampleType,
1452 object->presentParms.MultiSampleQuality,
1453 TRUE /* Lockable */,
1454 &object->backBuffer[i],
1455 NULL /* pShared (always null)*/);
1456 if(hr == WINED3D_OK && object->backBuffer[i]) {
1457 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1458 } else {
1459 ERR("Cannot create new back buffer\n");
1460 goto error;
1462 ENTER_GL();
1463 glDrawBuffer(GL_BACK);
1464 checkGLcall("glDrawBuffer(GL_BACK)");
1465 LEAVE_GL();
1467 } else {
1468 object->backBuffer = NULL;
1470 /* Single buffering - draw to front buffer */
1471 ENTER_GL();
1472 glDrawBuffer(GL_FRONT);
1473 checkGLcall("glDrawBuffer(GL_FRONT)");
1474 LEAVE_GL();
1477 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1478 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1479 TRACE("Creating depth stencil buffer\n");
1480 if (This->depthStencilBuffer == NULL ) {
1481 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1482 parent,
1483 object->presentParms.BackBufferWidth,
1484 object->presentParms.BackBufferHeight,
1485 object->presentParms.AutoDepthStencilFormat,
1486 object->presentParms.MultiSampleType,
1487 object->presentParms.MultiSampleQuality,
1488 FALSE /* FIXME: Discard */,
1489 &This->depthStencilBuffer,
1490 NULL /* pShared (always null)*/ );
1491 if (This->depthStencilBuffer != NULL)
1492 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1495 /** TODO: A check on width, height and multisample types
1496 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1497 ****************************/
1498 object->wantsDepthStencilBuffer = TRUE;
1499 } else {
1500 object->wantsDepthStencilBuffer = FALSE;
1503 TRACE("Created swapchain %p\n", object);
1504 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1505 return WINED3D_OK;
1507 error:
1508 if (object->backBuffer) {
1509 int i;
1510 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1511 if(object->backBuffer[i]) {
1512 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1513 IUnknown_Release(bufferParent); /* once for the get parent */
1514 if (IUnknown_Release(bufferParent) > 0) {
1515 FIXME("(%p) Something's still holding the back buffer\n",This);
1519 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1520 object->backBuffer = NULL;
1522 if(object->context[0])
1523 DestroyContext(This, object->context[0]);
1524 if(object->frontBuffer) {
1525 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1526 IUnknown_Release(bufferParent); /* once for the get parent */
1527 if (IUnknown_Release(bufferParent) > 0) {
1528 FIXME("(%p) Something's still holding the front buffer\n",This);
1531 HeapFree(GetProcessHeap(), 0, object);
1532 return hr;
1535 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1536 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 TRACE("(%p)\n", This);
1540 return This->NumberOfSwapChains;
1543 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1545 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1547 if(iSwapChain < This->NumberOfSwapChains) {
1548 *pSwapChain = This->swapchains[iSwapChain];
1549 IWineD3DSwapChain_AddRef(*pSwapChain);
1550 TRACE("(%p) returning %p\n", This, *pSwapChain);
1551 return WINED3D_OK;
1552 } else {
1553 TRACE("Swapchain out of range\n");
1554 *pSwapChain = NULL;
1555 return WINED3DERR_INVALIDCALL;
1559 /*****
1560 * Vertex Declaration
1561 *****/
1562 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1563 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1565 IWineD3DVertexDeclarationImpl *object = NULL;
1566 HRESULT hr = WINED3D_OK;
1568 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1569 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1571 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1573 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1575 return hr;
1578 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1580 unsigned int idx, idx2;
1581 unsigned int offset;
1582 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1583 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1584 BOOL has_blend_idx = has_blend &&
1585 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1586 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1587 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1588 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1589 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1590 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1591 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1593 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1594 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1596 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1597 WINED3DVERTEXELEMENT *elements = NULL;
1599 unsigned int size;
1600 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1601 if (has_blend_idx) num_blends--;
1603 /* Compute declaration size */
1604 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1605 has_psize + has_diffuse + has_specular + num_textures + 1;
1607 /* convert the declaration */
1608 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1609 if (!elements)
1610 return 0;
1612 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1613 idx = 0;
1614 if (has_pos) {
1615 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1616 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1617 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1619 else {
1620 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1621 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1623 elements[idx].UsageIndex = 0;
1624 idx++;
1626 if (has_blend && (num_blends > 0)) {
1627 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1628 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1629 else
1630 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1631 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1632 elements[idx].UsageIndex = 0;
1633 idx++;
1635 if (has_blend_idx) {
1636 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1637 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1638 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1639 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1640 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1641 else
1642 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1643 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1644 elements[idx].UsageIndex = 0;
1645 idx++;
1647 if (has_normal) {
1648 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1649 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1650 elements[idx].UsageIndex = 0;
1651 idx++;
1653 if (has_psize) {
1654 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1655 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1656 elements[idx].UsageIndex = 0;
1657 idx++;
1659 if (has_diffuse) {
1660 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1661 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1662 elements[idx].UsageIndex = 0;
1663 idx++;
1665 if (has_specular) {
1666 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1667 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1668 elements[idx].UsageIndex = 1;
1669 idx++;
1671 for (idx2 = 0; idx2 < num_textures; idx2++) {
1672 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1673 switch (numcoords) {
1674 case WINED3DFVF_TEXTUREFORMAT1:
1675 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1676 break;
1677 case WINED3DFVF_TEXTUREFORMAT2:
1678 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1679 break;
1680 case WINED3DFVF_TEXTUREFORMAT3:
1681 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1682 break;
1683 case WINED3DFVF_TEXTUREFORMAT4:
1684 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1685 break;
1687 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1688 elements[idx].UsageIndex = idx2;
1689 idx++;
1692 /* Now compute offsets, and initialize the rest of the fields */
1693 for (idx = 0, offset = 0; idx < size-1; idx++) {
1694 elements[idx].Stream = 0;
1695 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1696 elements[idx].Offset = offset;
1697 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1700 *ppVertexElements = elements;
1701 return size;
1704 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1705 WINED3DVERTEXELEMENT* elements = NULL;
1706 size_t size;
1707 DWORD hr;
1709 size = ConvertFvfToDeclaration(Fvf, &elements);
1710 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1712 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1713 HeapFree(GetProcessHeap(), 0, elements);
1714 if (hr != S_OK) return hr;
1716 return WINED3D_OK;
1719 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1723 HRESULT hr = WINED3D_OK;
1724 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1725 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1727 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1729 if (vertex_declaration) {
1730 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1733 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1735 if (WINED3D_OK != hr) {
1736 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1737 IWineD3DVertexShader_Release(*ppVertexShader);
1738 return WINED3DERR_INVALIDCALL;
1741 return WINED3D_OK;
1744 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1746 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1747 HRESULT hr = WINED3D_OK;
1749 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1750 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1751 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1752 if (WINED3D_OK == hr) {
1753 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1754 } else {
1755 WARN("(%p) : Failed to create pixel shader\n", This);
1758 return hr;
1761 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1763 IWineD3DPaletteImpl *object;
1764 HRESULT hr;
1765 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1767 /* Create the new object */
1768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1769 if(!object) {
1770 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1771 return E_OUTOFMEMORY;
1774 object->lpVtbl = &IWineD3DPalette_Vtbl;
1775 object->ref = 1;
1776 object->Flags = Flags;
1777 object->parent = Parent;
1778 object->wineD3DDevice = This;
1779 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1781 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1783 if(!object->hpal) {
1784 HeapFree( GetProcessHeap(), 0, object);
1785 return E_OUTOFMEMORY;
1788 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1789 if(FAILED(hr)) {
1790 IWineD3DPalette_Release((IWineD3DPalette *) object);
1791 return hr;
1794 *Palette = (IWineD3DPalette *) object;
1796 return WINED3D_OK;
1799 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1801 IWineD3DSwapChainImpl *swapchain;
1802 DWORD state;
1804 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1805 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1807 /* TODO: Test if OpenGL is compiled in and loaded */
1809 /* Initialize the texture unit mapping to a 1:1 mapping */
1810 for(state = 0; state < MAX_SAMPLERS; state++) {
1811 This->texUnitMap[state] = state;
1813 This->oneToOneTexUnitMap = TRUE;
1815 /* Setup the implicit swapchain */
1816 TRACE("Creating implicit swapchain\n");
1817 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1818 WARN("Failed to create implicit swapchain\n");
1819 return WINED3DERR_INVALIDCALL;
1822 This->NumberOfSwapChains = 1;
1823 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1824 if(!This->swapchains) {
1825 ERR("Out of memory!\n");
1826 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1827 return E_OUTOFMEMORY;
1829 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1831 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1833 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1834 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1835 This->render_targets[0] = swapchain->backBuffer[0];
1836 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1838 else {
1839 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1840 This->render_targets[0] = swapchain->frontBuffer;
1841 This->lastActiveRenderTarget = swapchain->frontBuffer;
1843 IWineD3DSurface_AddRef(This->render_targets[0]);
1844 This->activeContext = swapchain->context[0];
1846 /* Depth Stencil support */
1847 This->stencilBufferTarget = This->depthStencilBuffer;
1848 if (NULL != This->stencilBufferTarget) {
1849 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1852 /* Set up some starting GL setup */
1853 ENTER_GL();
1855 * Initialize openGL extension related variables
1856 * with Default values
1859 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1860 /* Setup all the devices defaults */
1861 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1862 #if 0
1863 IWineD3DImpl_CheckGraphicsMemory();
1864 #endif
1866 { /* Set a default viewport */
1867 WINED3DVIEWPORT vp;
1868 vp.X = 0;
1869 vp.Y = 0;
1870 vp.Width = pPresentationParameters->BackBufferWidth;
1871 vp.Height = pPresentationParameters->BackBufferHeight;
1872 vp.MinZ = 0.0f;
1873 vp.MaxZ = 1.0f;
1874 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1877 /* Initialize the current view state */
1878 This->view_ident = 1;
1879 This->contexts[0]->last_was_rhw = 0;
1880 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1881 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1883 switch(wined3d_settings.offscreen_rendering_mode) {
1884 case ORM_FBO:
1885 case ORM_PBUFFER:
1886 This->offscreenBuffer = GL_BACK;
1887 break;
1889 case ORM_BACKBUFFER:
1891 if(GL_LIMITS(aux_buffers) > 0) {
1892 TRACE("Using auxilliary buffer for offscreen rendering\n");
1893 This->offscreenBuffer = GL_AUX0;
1894 } else {
1895 TRACE("Using back buffer for offscreen rendering\n");
1896 This->offscreenBuffer = GL_BACK;
1901 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1902 LEAVE_GL();
1904 /* Clear the screen */
1905 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1906 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1907 0x00, 1.0, 0);
1909 This->d3d_initialized = TRUE;
1910 return WINED3D_OK;
1913 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1915 int sampler;
1916 uint i;
1917 TRACE("(%p)\n", This);
1919 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1921 ENTER_GL();
1922 /* I don't think that the interface guarants that the device is destroyed from the same thread
1923 * it was created. Thus make sure a context is active for the glDelete* calls
1925 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1926 LEAVE_GL();
1928 /* Delete the pbuffer context if there is any */
1929 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1931 /* Delete the mouse cursor texture */
1932 if(This->cursorTexture) {
1933 ENTER_GL();
1934 glDeleteTextures(1, &This->cursorTexture);
1935 LEAVE_GL();
1936 This->cursorTexture = 0;
1939 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1940 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1943 /* Release the buffers (with sanity checks)*/
1944 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1945 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1946 if(This->depthStencilBuffer != This->stencilBufferTarget)
1947 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1949 This->stencilBufferTarget = NULL;
1951 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1952 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1953 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1955 TRACE("Setting rendertarget to NULL\n");
1956 This->render_targets[0] = NULL;
1958 if (This->depthStencilBuffer) {
1959 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1960 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1962 This->depthStencilBuffer = NULL;
1965 for(i=0; i < This->NumberOfSwapChains; i++) {
1966 TRACE("Releasing the implicit swapchain %d\n", i);
1967 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1968 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1972 HeapFree(GetProcessHeap(), 0, This->swapchains);
1973 This->swapchains = NULL;
1974 This->NumberOfSwapChains = 0;
1976 This->d3d_initialized = FALSE;
1977 return WINED3D_OK;
1980 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1982 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1984 /* Setup the window for fullscreen mode */
1985 if(fullscreen && !This->ddraw_fullscreen) {
1986 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1987 } else if(!fullscreen && This->ddraw_fullscreen) {
1988 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1991 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1992 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1993 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1994 * separately.
1996 This->ddraw_fullscreen = fullscreen;
1999 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2000 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2001 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2003 * There is no way to deactivate thread safety once it is enabled
2005 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2007 FIXME("No thread safety in wined3d yet\n");
2009 /*For now just store the flag(needed in case of ddraw) */
2010 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2012 return;
2015 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2016 DEVMODEW devmode;
2017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2018 LONG ret;
2019 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2020 RECT clip_rc;
2022 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2024 /* Resize the screen even without a window:
2025 * The app could have unset it with SetCooperativeLevel, but not called
2026 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2027 * but we don't have any hwnd
2030 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2031 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2032 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2033 devmode.dmPelsWidth = pMode->Width;
2034 devmode.dmPelsHeight = pMode->Height;
2036 devmode.dmDisplayFrequency = pMode->RefreshRate;
2037 if (pMode->RefreshRate != 0) {
2038 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2041 /* Only change the mode if necessary */
2042 if( (This->ddraw_width == pMode->Width) &&
2043 (This->ddraw_height == pMode->Height) &&
2044 (This->ddraw_format == pMode->Format) &&
2045 (pMode->RefreshRate == 0) ) {
2046 return WINED3D_OK;
2049 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2050 if (ret != DISP_CHANGE_SUCCESSFUL) {
2051 if(devmode.dmDisplayFrequency != 0) {
2052 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2053 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2054 devmode.dmDisplayFrequency = 0;
2055 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2057 if(ret != DISP_CHANGE_SUCCESSFUL) {
2058 return WINED3DERR_NOTAVAILABLE;
2062 /* Store the new values */
2063 This->ddraw_width = pMode->Width;
2064 This->ddraw_height = pMode->Height;
2065 This->ddraw_format = pMode->Format;
2067 /* Only do this with a window of course */
2068 if(This->ddraw_window)
2069 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2071 /* And finally clip mouse to our screen */
2072 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2073 ClipCursor(&clip_rc);
2075 return WINED3D_OK;
2078 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2080 *ppD3D= This->wineD3D;
2081 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2082 IWineD3D_AddRef(*ppD3D);
2083 return WINED3D_OK;
2086 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2087 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2088 * into the video ram as possible and seeing how many fit
2089 * you can also get the correct initial value from nvidia and ATI's driver via X
2090 * texture memory is video memory + AGP memory
2091 *******************/
2092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 static BOOL showfixmes = TRUE;
2094 if (showfixmes) {
2095 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2096 (wined3d_settings.emulated_textureram/(1024*1024)),
2097 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2098 showfixmes = FALSE;
2100 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2101 (wined3d_settings.emulated_textureram/(1024*1024)),
2102 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2103 /* return simulated texture memory left */
2104 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2109 /*****
2110 * Get / Set FVF
2111 *****/
2112 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2115 /* Update the current state block */
2116 This->updateStateBlock->changed.fvf = TRUE;
2117 This->updateStateBlock->set.fvf = TRUE;
2119 if(This->updateStateBlock->fvf == fvf) {
2120 TRACE("Application is setting the old fvf over, nothing to do\n");
2121 return WINED3D_OK;
2124 This->updateStateBlock->fvf = fvf;
2125 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2127 return WINED3D_OK;
2131 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2133 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2134 *pfvf = This->stateBlock->fvf;
2135 return WINED3D_OK;
2138 /*****
2139 * Get / Set Stream Source
2140 *****/
2141 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2143 IWineD3DVertexBuffer *oldSrc;
2145 if (StreamNumber >= MAX_STREAMS) {
2146 WARN("Stream out of range %d\n", StreamNumber);
2147 return WINED3DERR_INVALIDCALL;
2150 oldSrc = This->stateBlock->streamSource[StreamNumber];
2151 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2153 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2154 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2156 if(oldSrc == pStreamData &&
2157 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2158 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2159 TRACE("Application is setting the old values over, nothing to do\n");
2160 return WINED3D_OK;
2163 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2164 if (pStreamData) {
2165 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2166 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2169 /* Handle recording of state blocks */
2170 if (This->isRecordingState) {
2171 TRACE("Recording... not performing anything\n");
2172 return WINED3D_OK;
2175 /* Need to do a getParent and pass the reffs up */
2176 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2177 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2178 so for now, just count internally */
2179 if (pStreamData != NULL) {
2180 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2181 InterlockedIncrement(&vbImpl->bindCount);
2183 if (oldSrc != NULL) {
2184 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2189 return WINED3D_OK;
2192 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2195 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2196 This->stateBlock->streamSource[StreamNumber],
2197 This->stateBlock->streamOffset[StreamNumber],
2198 This->stateBlock->streamStride[StreamNumber]);
2200 if (StreamNumber >= MAX_STREAMS) {
2201 WARN("Stream out of range %d\n", StreamNumber);
2202 return WINED3DERR_INVALIDCALL;
2204 *pStream = This->stateBlock->streamSource[StreamNumber];
2205 *pStride = This->stateBlock->streamStride[StreamNumber];
2206 if (pOffset) {
2207 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2210 if (*pStream != NULL) {
2211 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2213 return WINED3D_OK;
2216 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2218 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2219 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2221 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2222 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2224 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2225 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2226 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2228 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2229 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2233 return WINED3D_OK;
2236 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2239 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2240 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2242 TRACE("(%p) : returning %d\n", This, *Divider);
2244 return WINED3D_OK;
2247 /*****
2248 * Get / Set & Multiply Transform
2249 *****/
2250 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 /* Most of this routine, comments included copied from ddraw tree initially: */
2254 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2256 /* Handle recording of state blocks */
2257 if (This->isRecordingState) {
2258 TRACE("Recording... not performing anything\n");
2259 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2260 This->updateStateBlock->set.transform[d3dts] = TRUE;
2261 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2262 return WINED3D_OK;
2266 * If the new matrix is the same as the current one,
2267 * we cut off any further processing. this seems to be a reasonable
2268 * optimization because as was noticed, some apps (warcraft3 for example)
2269 * tend towards setting the same matrix repeatedly for some reason.
2271 * From here on we assume that the new matrix is different, wherever it matters.
2273 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2274 TRACE("The app is setting the same matrix over again\n");
2275 return WINED3D_OK;
2276 } else {
2277 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2281 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2282 where ViewMat = Camera space, WorldMat = world space.
2284 In OpenGL, camera and world space is combined into GL_MODELVIEW
2285 matrix. The Projection matrix stay projection matrix.
2288 /* Capture the times we can just ignore the change for now */
2289 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2290 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2291 /* Handled by the state manager */
2294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2295 return WINED3D_OK;
2298 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2300 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2301 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2302 return WINED3D_OK;
2305 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2306 WINED3DMATRIX *mat = NULL;
2307 WINED3DMATRIX temp;
2309 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2310 * below means it will be recorded in a state block change, but it
2311 * works regardless where it is recorded.
2312 * If this is found to be wrong, change to StateBlock.
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2315 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2317 if (State < HIGHEST_TRANSFORMSTATE)
2319 mat = &This->updateStateBlock->transforms[State];
2320 } else {
2321 FIXME("Unhandled transform state!!\n");
2324 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2326 /* Apply change via set transform - will reapply to eg. lights this way */
2327 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2330 /*****
2331 * Get / Set Light
2332 *****/
2333 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2334 you can reference any indexes you want as long as that number max are enabled at any
2335 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2336 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2337 but when recording, just build a chain pretty much of commands to be replayed. */
2339 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2340 float rho;
2341 PLIGHTINFOEL *object = NULL;
2342 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2343 struct list *e;
2345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2346 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2348 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2349 * the gl driver.
2351 if(!pLight) {
2352 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2353 return WINED3DERR_INVALIDCALL;
2356 switch(pLight->Type) {
2357 case WINED3DLIGHT_POINT:
2358 case WINED3DLIGHT_SPOT:
2359 case WINED3DLIGHT_PARALLELPOINT:
2360 case WINED3DLIGHT_GLSPOT:
2361 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2362 * most wanted
2364 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2365 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2368 break;
2370 case WINED3DLIGHT_DIRECTIONAL:
2371 /* Ignores attenuation */
2372 break;
2374 default:
2375 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2376 return WINED3DERR_INVALIDCALL;
2379 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2380 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2381 if(object->OriginalIndex == Index) break;
2382 object = NULL;
2385 if(!object) {
2386 TRACE("Adding new light\n");
2387 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2388 if(!object) {
2389 ERR("Out of memory error when allocating a light\n");
2390 return E_OUTOFMEMORY;
2392 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2393 object->glIndex = -1;
2394 object->OriginalIndex = Index;
2395 object->changed = TRUE;
2398 /* Initialize the object */
2399 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,
2400 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2401 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2402 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2403 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2404 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2405 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2407 /* Save away the information */
2408 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2410 switch (pLight->Type) {
2411 case WINED3DLIGHT_POINT:
2412 /* Position */
2413 object->lightPosn[0] = pLight->Position.x;
2414 object->lightPosn[1] = pLight->Position.y;
2415 object->lightPosn[2] = pLight->Position.z;
2416 object->lightPosn[3] = 1.0f;
2417 object->cutoff = 180.0f;
2418 /* FIXME: Range */
2419 break;
2421 case WINED3DLIGHT_DIRECTIONAL:
2422 /* Direction */
2423 object->lightPosn[0] = -pLight->Direction.x;
2424 object->lightPosn[1] = -pLight->Direction.y;
2425 object->lightPosn[2] = -pLight->Direction.z;
2426 object->lightPosn[3] = 0.0;
2427 object->exponent = 0.0f;
2428 object->cutoff = 180.0f;
2429 break;
2431 case WINED3DLIGHT_SPOT:
2432 /* Position */
2433 object->lightPosn[0] = pLight->Position.x;
2434 object->lightPosn[1] = pLight->Position.y;
2435 object->lightPosn[2] = pLight->Position.z;
2436 object->lightPosn[3] = 1.0;
2438 /* Direction */
2439 object->lightDirn[0] = pLight->Direction.x;
2440 object->lightDirn[1] = pLight->Direction.y;
2441 object->lightDirn[2] = pLight->Direction.z;
2442 object->lightDirn[3] = 1.0;
2445 * opengl-ish and d3d-ish spot lights use too different models for the
2446 * light "intensity" as a function of the angle towards the main light direction,
2447 * so we only can approximate very roughly.
2448 * however spot lights are rather rarely used in games (if ever used at all).
2449 * furthermore if still used, probably nobody pays attention to such details.
2451 if (pLight->Falloff == 0) {
2452 rho = 6.28f;
2453 } else {
2454 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2456 if (rho < 0.0001) rho = 0.0001f;
2457 object->exponent = -0.3/log(cos(rho/2));
2458 if (object->exponent > 128.0) {
2459 object->exponent = 128.0;
2461 object->cutoff = pLight->Phi*90/M_PI;
2463 /* FIXME: Range */
2464 break;
2466 default:
2467 FIXME("Unrecognized light type %d\n", pLight->Type);
2470 /* Update the live definitions if the light is currently assigned a glIndex */
2471 if (object->glIndex != -1 && !This->isRecordingState) {
2472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2474 return WINED3D_OK;
2477 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2478 PLIGHTINFOEL *lightInfo = NULL;
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2480 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2481 struct list *e;
2482 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2484 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2485 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2486 if(lightInfo->OriginalIndex == Index) break;
2487 lightInfo = NULL;
2490 if (lightInfo == NULL) {
2491 TRACE("Light information requested but light not defined\n");
2492 return WINED3DERR_INVALIDCALL;
2495 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2496 return WINED3D_OK;
2499 /*****
2500 * Get / Set Light Enable
2501 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2502 *****/
2503 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2504 PLIGHTINFOEL *lightInfo = NULL;
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2507 struct list *e;
2508 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2510 /* Tests show true = 128...not clear why */
2511 Enable = Enable? 128: 0;
2513 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2514 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2515 if(lightInfo->OriginalIndex == Index) break;
2516 lightInfo = NULL;
2518 TRACE("Found light: %p\n", lightInfo);
2520 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2521 if (lightInfo == NULL) {
2523 TRACE("Light enabled requested but light not defined, so defining one!\n");
2524 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2526 /* Search for it again! Should be fairly quick as near head of list */
2527 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2528 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2529 if(lightInfo->OriginalIndex == Index) break;
2530 lightInfo = NULL;
2532 if (lightInfo == NULL) {
2533 FIXME("Adding default lights has failed dismally\n");
2534 return WINED3DERR_INVALIDCALL;
2538 lightInfo->enabledChanged = TRUE;
2539 if(!Enable) {
2540 if(lightInfo->glIndex != -1) {
2541 if(!This->isRecordingState) {
2542 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2545 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2546 lightInfo->glIndex = -1;
2547 } else {
2548 TRACE("Light already disabled, nothing to do\n");
2550 } else {
2551 if (lightInfo->glIndex != -1) {
2552 /* nop */
2553 TRACE("Nothing to do as light was enabled\n");
2554 } else {
2555 int i;
2556 /* Find a free gl light */
2557 for(i = 0; i < This->maxConcurrentLights; i++) {
2558 if(This->stateBlock->activeLights[i] == NULL) {
2559 This->stateBlock->activeLights[i] = lightInfo;
2560 lightInfo->glIndex = i;
2561 break;
2564 if(lightInfo->glIndex == -1) {
2565 ERR("Too many concurrently active lights\n");
2566 return WINED3DERR_INVALIDCALL;
2569 /* i == lightInfo->glIndex */
2570 if(!This->isRecordingState) {
2571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2576 return WINED3D_OK;
2579 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2581 PLIGHTINFOEL *lightInfo = NULL;
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 struct list *e;
2584 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2585 TRACE("(%p) : for idx(%d)\n", This, Index);
2587 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2588 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2589 if(lightInfo->OriginalIndex == Index) break;
2590 lightInfo = NULL;
2593 if (lightInfo == NULL) {
2594 TRACE("Light enabled state requested but light not defined\n");
2595 return WINED3DERR_INVALIDCALL;
2597 /* true is 128 according to SetLightEnable */
2598 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2599 return WINED3D_OK;
2602 /*****
2603 * Get / Set Clip Planes
2604 *****/
2605 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2609 /* Validate Index */
2610 if (Index >= GL_LIMITS(clipplanes)) {
2611 TRACE("Application has requested clipplane this device doesn't support\n");
2612 return WINED3DERR_INVALIDCALL;
2615 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2616 This->updateStateBlock->set.clipplane[Index] = TRUE;
2618 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2619 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2620 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2621 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2622 TRACE("Application is setting old values over, nothing to do\n");
2623 return WINED3D_OK;
2626 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2627 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2628 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2629 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2631 /* Handle recording of state blocks */
2632 if (This->isRecordingState) {
2633 TRACE("Recording... not performing anything\n");
2634 return WINED3D_OK;
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2639 return WINED3D_OK;
2642 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2644 TRACE("(%p) : for idx %d\n", This, Index);
2646 /* Validate Index */
2647 if (Index >= GL_LIMITS(clipplanes)) {
2648 TRACE("Application has requested clipplane this device doesn't support\n");
2649 return WINED3DERR_INVALIDCALL;
2652 pPlane[0] = This->stateBlock->clipplane[Index][0];
2653 pPlane[1] = This->stateBlock->clipplane[Index][1];
2654 pPlane[2] = This->stateBlock->clipplane[Index][2];
2655 pPlane[3] = This->stateBlock->clipplane[Index][3];
2656 return WINED3D_OK;
2659 /*****
2660 * Get / Set Clip Plane Status
2661 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2662 *****/
2663 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2665 FIXME("(%p) : stub\n", This);
2666 if (NULL == pClipStatus) {
2667 return WINED3DERR_INVALIDCALL;
2669 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2670 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2671 return WINED3D_OK;
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 FIXME("(%p) : stub\n", This);
2677 if (NULL == pClipStatus) {
2678 return WINED3DERR_INVALIDCALL;
2680 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2681 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2682 return WINED3D_OK;
2685 /*****
2686 * Get / Set Material
2687 *****/
2688 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 This->updateStateBlock->changed.material = TRUE;
2692 This->updateStateBlock->set.material = TRUE;
2693 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2695 /* Handle recording of state blocks */
2696 if (This->isRecordingState) {
2697 TRACE("Recording... not performing anything\n");
2698 return WINED3D_OK;
2701 ENTER_GL();
2702 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2703 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2704 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2705 pMaterial->Ambient.b, pMaterial->Ambient.a);
2706 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2707 pMaterial->Specular.b, pMaterial->Specular.a);
2708 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2709 pMaterial->Emissive.b, pMaterial->Emissive.a);
2710 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2712 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2713 checkGLcall("glMaterialfv(GL_AMBIENT)");
2714 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2715 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2717 /* Only change material color if specular is enabled, otherwise it is set to black */
2718 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2719 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2720 checkGLcall("glMaterialfv(GL_SPECULAR");
2721 } else {
2722 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2723 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2724 checkGLcall("glMaterialfv(GL_SPECULAR");
2726 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2727 checkGLcall("glMaterialfv(GL_EMISSION)");
2728 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2729 checkGLcall("glMaterialf(GL_SHININESS");
2731 LEAVE_GL();
2732 return WINED3D_OK;
2735 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2738 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2739 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2740 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2741 pMaterial->Ambient.b, pMaterial->Ambient.a);
2742 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2743 pMaterial->Specular.b, pMaterial->Specular.a);
2744 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2745 pMaterial->Emissive.b, pMaterial->Emissive.a);
2746 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2748 return WINED3D_OK;
2751 /*****
2752 * Get / Set Indices
2753 *****/
2754 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2755 UINT BaseVertexIndex) {
2756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2757 IWineD3DIndexBuffer *oldIdxs;
2758 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2760 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2761 oldIdxs = This->updateStateBlock->pIndexData;
2763 This->updateStateBlock->changed.indices = TRUE;
2764 This->updateStateBlock->set.indices = TRUE;
2765 This->updateStateBlock->pIndexData = pIndexData;
2766 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2768 /* Handle recording of state blocks */
2769 if (This->isRecordingState) {
2770 TRACE("Recording... not performing anything\n");
2771 return WINED3D_OK;
2774 /* The base vertex index affects the stream sources, while
2775 * The index buffer is a seperate index buffer state
2777 if(BaseVertexIndex != oldBaseIndex) {
2778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2780 if(oldIdxs != pIndexData) {
2781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2783 return WINED3D_OK;
2786 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 *ppIndexData = This->stateBlock->pIndexData;
2791 /* up ref count on ppindexdata */
2792 if (*ppIndexData) {
2793 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2794 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2795 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2796 }else{
2797 TRACE("(%p) No index data set\n", This);
2799 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2801 return WINED3D_OK;
2804 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2805 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 TRACE("(%p)->(%d)\n", This, BaseIndex);
2809 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2810 TRACE("Application is setting the old value over, nothing to do\n");
2811 return WINED3D_OK;
2814 This->updateStateBlock->baseVertexIndex = BaseIndex;
2816 if (This->isRecordingState) {
2817 TRACE("Recording... not performing anything\n");
2818 return WINED3D_OK;
2820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2821 return WINED3D_OK;
2824 /*****
2825 * Get / Set Viewports
2826 *****/
2827 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830 TRACE("(%p)\n", This);
2831 This->updateStateBlock->changed.viewport = TRUE;
2832 This->updateStateBlock->set.viewport = TRUE;
2833 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2835 /* Handle recording of state blocks */
2836 if (This->isRecordingState) {
2837 TRACE("Recording... not performing anything\n");
2838 return WINED3D_OK;
2841 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2842 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2845 return WINED3D_OK;
2849 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2851 TRACE("(%p)\n", This);
2852 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2853 return WINED3D_OK;
2856 /*****
2857 * Get / Set Render States
2858 * TODO: Verify against dx9 definitions
2859 *****/
2860 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 DWORD oldValue = This->stateBlock->renderState[State];
2865 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2867 This->updateStateBlock->changed.renderState[State] = TRUE;
2868 This->updateStateBlock->set.renderState[State] = TRUE;
2869 This->updateStateBlock->renderState[State] = Value;
2871 /* Handle recording of state blocks */
2872 if (This->isRecordingState) {
2873 TRACE("Recording... not performing anything\n");
2874 return WINED3D_OK;
2877 /* Compared here and not before the assignment to allow proper stateblock recording */
2878 if(Value == oldValue) {
2879 TRACE("Application is setting the old value over, nothing to do\n");
2880 } else {
2881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2884 return WINED3D_OK;
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2890 *pValue = This->stateBlock->renderState[State];
2891 return WINED3D_OK;
2894 /*****
2895 * Get / Set Sampler States
2896 * TODO: Verify against dx9 definitions
2897 *****/
2899 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2904 * SetSampler is designed to allow for more than the standard up to 8 textures
2905 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2906 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2908 * http://developer.nvidia.com/object/General_FAQ.html#t6
2910 * There are two new settings for GForce
2911 * the sampler one:
2912 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2913 * and the texture one:
2914 * GL_MAX_TEXTURE_COORDS_ARB.
2915 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2916 ******************/
2918 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2919 debug_d3dsamplerstate(Type), Type, Value);
2920 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2921 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2922 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2924 /* Handle recording of state blocks */
2925 if (This->isRecordingState) {
2926 TRACE("Recording... not performing anything\n");
2927 return WINED3D_OK;
2930 if(oldValue == Value) {
2931 TRACE("Application is setting the old value over, nothing to do\n");
2932 return WINED3D_OK;
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2937 return WINED3D_OK;
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2942 *Value = This->stateBlock->samplerState[Sampler][Type];
2943 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2945 return WINED3D_OK;
2948 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 This->updateStateBlock->set.scissorRect = TRUE;
2952 This->updateStateBlock->changed.scissorRect = TRUE;
2953 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2954 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2955 return WINED3D_OK;
2957 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2959 if(This->isRecordingState) {
2960 TRACE("Recording... not performing anything\n");
2961 return WINED3D_OK;
2964 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2966 return WINED3D_OK;
2969 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2973 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2979 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2981 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2983 This->updateStateBlock->vertexDecl = pDecl;
2984 This->updateStateBlock->changed.vertexDecl = TRUE;
2985 This->updateStateBlock->set.vertexDecl = TRUE;
2987 if (This->isRecordingState) {
2988 TRACE("Recording... not performing anything\n");
2989 return WINED3D_OK;
2990 } else if(pDecl == oldDecl) {
2991 /* Checked after the assignment to allow proper stateblock recording */
2992 TRACE("Application is setting the old declaration over, nothing to do\n");
2993 return WINED3D_OK;
2996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2997 return WINED3D_OK;
3000 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3005 *ppDecl = This->stateBlock->vertexDecl;
3006 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3007 return WINED3D_OK;
3010 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3014 This->updateStateBlock->vertexShader = pShader;
3015 This->updateStateBlock->changed.vertexShader = TRUE;
3016 This->updateStateBlock->set.vertexShader = TRUE;
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3020 return WINED3D_OK;
3021 } else if(oldShader == pShader) {
3022 /* Checked here to allow proper stateblock recording */
3023 TRACE("App is setting the old shader over, nothing to do\n");
3024 return WINED3D_OK;
3027 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3031 return WINED3D_OK;
3034 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 if (NULL == ppShader) {
3038 return WINED3DERR_INVALIDCALL;
3040 *ppShader = This->stateBlock->vertexShader;
3041 if( NULL != *ppShader)
3042 IWineD3DVertexShader_AddRef(*ppShader);
3044 TRACE("(%p) : returning %p\n", This, *ppShader);
3045 return WINED3D_OK;
3048 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3049 IWineD3DDevice *iface,
3050 UINT start,
3051 CONST BOOL *srcData,
3052 UINT count) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 int i, cnt = min(count, MAX_CONST_B - start);
3057 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3058 iface, srcData, start, count);
3060 if (srcData == NULL || cnt < 0)
3061 return WINED3DERR_INVALIDCALL;
3063 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3064 for (i = 0; i < cnt; i++)
3065 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3067 for (i = start; i < cnt + start; ++i) {
3068 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3069 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3074 return WINED3D_OK;
3077 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3078 IWineD3DDevice *iface,
3079 UINT start,
3080 BOOL *dstData,
3081 UINT count) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 int cnt = min(count, MAX_CONST_B - start);
3086 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3087 iface, dstData, start, count);
3089 if (dstData == NULL || cnt < 0)
3090 return WINED3DERR_INVALIDCALL;
3092 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3093 return WINED3D_OK;
3096 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3097 IWineD3DDevice *iface,
3098 UINT start,
3099 CONST int *srcData,
3100 UINT count) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 int i, cnt = min(count, MAX_CONST_I - start);
3105 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3106 iface, srcData, start, count);
3108 if (srcData == NULL || cnt < 0)
3109 return WINED3DERR_INVALIDCALL;
3111 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3112 for (i = 0; i < cnt; i++)
3113 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3114 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3116 for (i = start; i < cnt + start; ++i) {
3117 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3118 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3123 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3127 IWineD3DDevice *iface,
3128 UINT start,
3129 int *dstData,
3130 UINT count) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 int cnt = min(count, MAX_CONST_I - start);
3135 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3136 iface, dstData, start, count);
3138 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3139 return WINED3DERR_INVALIDCALL;
3141 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3142 return WINED3D_OK;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3146 IWineD3DDevice *iface,
3147 UINT start,
3148 CONST float *srcData,
3149 UINT count) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 int i;
3154 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3155 iface, srcData, start, count);
3157 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3158 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3159 return WINED3DERR_INVALIDCALL;
3161 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3162 if(TRACE_ON(d3d)) {
3163 for (i = 0; i < count; i++)
3164 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3165 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3168 for (i = start; i < count + start; ++i) {
3169 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3170 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3171 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3172 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3173 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3175 ptr->idx[ptr->count++] = i;
3176 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3178 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3183 return WINED3D_OK;
3186 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3187 IWineD3DDevice *iface,
3188 UINT start,
3189 float *dstData,
3190 UINT count) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3195 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3196 iface, dstData, start, count);
3198 if (dstData == NULL || cnt < 0)
3199 return WINED3DERR_INVALIDCALL;
3201 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3202 return WINED3D_OK;
3205 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3206 DWORD i;
3207 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3212 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3213 DWORD i, tex;
3214 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3215 * it is never called.
3217 * Rules are:
3218 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3219 * that would be really messy and require shader recompilation
3220 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3221 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3222 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3223 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3225 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3226 if(This->oneToOneTexUnitMap) {
3227 TRACE("Not touching 1:1 map\n");
3228 return;
3230 TRACE("Restoring 1:1 texture unit mapping\n");
3231 /* Restore a 1:1 mapping */
3232 for(i = 0; i < MAX_SAMPLERS; i++) {
3233 if(This->texUnitMap[i] != i) {
3234 This->texUnitMap[i] = i;
3235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3236 markTextureStagesDirty(This, i);
3239 This->oneToOneTexUnitMap = TRUE;
3240 return;
3241 } else {
3242 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3243 * First, see if we can succeed at all
3245 tex = 0;
3246 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3247 if(This->stateBlock->textures[i] == NULL) tex++;
3250 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3251 FIXME("Too many bound textures to support the combiner settings\n");
3252 return;
3255 /* Now work out the mapping */
3256 tex = 0;
3257 This->oneToOneTexUnitMap = FALSE;
3258 WARN("Non 1:1 mapping UNTESTED!\n");
3259 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3260 /* Skip NULL textures */
3261 if (!This->stateBlock->textures[i]) {
3262 /* Map to -1, so the check below doesn't fail if a non-NULL
3263 * texture is set on this stage */
3264 TRACE("Mapping texture stage %d to -1\n", i);
3265 This->texUnitMap[i] = -1;
3267 continue;
3270 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3271 if(This->texUnitMap[i] != tex) {
3272 This->texUnitMap[i] = tex;
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3274 markTextureStagesDirty(This, i);
3277 ++tex;
3282 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3284 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3285 This->updateStateBlock->pixelShader = pShader;
3286 This->updateStateBlock->changed.pixelShader = TRUE;
3287 This->updateStateBlock->set.pixelShader = TRUE;
3289 /* Handle recording of state blocks */
3290 if (This->isRecordingState) {
3291 TRACE("Recording... not performing anything\n");
3294 if (This->isRecordingState) {
3295 TRACE("Recording... not performing anything\n");
3296 return WINED3D_OK;
3299 if(pShader == oldShader) {
3300 TRACE("App is setting the old pixel shader over, nothing to do\n");
3301 return WINED3D_OK;
3304 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3307 /* Rebuild the texture unit mapping if nvrc's are supported */
3308 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3309 IWineD3DDeviceImpl_FindTexUnitMap(This);
3312 return WINED3D_OK;
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 if (NULL == ppShader) {
3319 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3320 return WINED3DERR_INVALIDCALL;
3323 *ppShader = This->stateBlock->pixelShader;
3324 if (NULL != *ppShader) {
3325 IWineD3DPixelShader_AddRef(*ppShader);
3327 TRACE("(%p) : returning %p\n", This, *ppShader);
3328 return WINED3D_OK;
3331 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3332 IWineD3DDevice *iface,
3333 UINT start,
3334 CONST BOOL *srcData,
3335 UINT count) {
3337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 int i, cnt = min(count, MAX_CONST_B - start);
3340 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3341 iface, srcData, start, count);
3343 if (srcData == NULL || cnt < 0)
3344 return WINED3DERR_INVALIDCALL;
3346 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3347 for (i = 0; i < cnt; i++)
3348 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3350 for (i = start; i < cnt + start; ++i) {
3351 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3352 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3357 return WINED3D_OK;
3360 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3361 IWineD3DDevice *iface,
3362 UINT start,
3363 BOOL *dstData,
3364 UINT count) {
3366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3367 int cnt = min(count, MAX_CONST_B - start);
3369 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3370 iface, dstData, start, count);
3372 if (dstData == NULL || cnt < 0)
3373 return WINED3DERR_INVALIDCALL;
3375 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3376 return WINED3D_OK;
3379 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3380 IWineD3DDevice *iface,
3381 UINT start,
3382 CONST int *srcData,
3383 UINT count) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 int i, cnt = min(count, MAX_CONST_I - start);
3388 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3389 iface, srcData, start, count);
3391 if (srcData == NULL || cnt < 0)
3392 return WINED3DERR_INVALIDCALL;
3394 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3395 for (i = 0; i < cnt; i++)
3396 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3397 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3399 for (i = start; i < cnt + start; ++i) {
3400 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3401 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3406 return WINED3D_OK;
3409 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3410 IWineD3DDevice *iface,
3411 UINT start,
3412 int *dstData,
3413 UINT count) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 int cnt = min(count, MAX_CONST_I - start);
3418 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3419 iface, dstData, start, count);
3421 if (dstData == NULL || cnt < 0)
3422 return WINED3DERR_INVALIDCALL;
3424 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3425 return WINED3D_OK;
3428 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3429 IWineD3DDevice *iface,
3430 UINT start,
3431 CONST float *srcData,
3432 UINT count) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 int i;
3437 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3438 iface, srcData, start, count);
3440 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3441 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3442 return WINED3DERR_INVALIDCALL;
3444 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3445 if(TRACE_ON(d3d)) {
3446 for (i = 0; i < count; i++)
3447 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3448 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3451 for (i = start; i < count + start; ++i) {
3452 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3453 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3454 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3455 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3456 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3458 ptr->idx[ptr->count++] = i;
3459 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3461 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3466 return WINED3D_OK;
3469 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3470 IWineD3DDevice *iface,
3471 UINT start,
3472 float *dstData,
3473 UINT count) {
3475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3476 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3478 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3479 iface, dstData, start, count);
3481 if (dstData == NULL || cnt < 0)
3482 return WINED3DERR_INVALIDCALL;
3484 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3485 return WINED3D_OK;
3488 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3489 static HRESULT
3490 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3491 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3492 unsigned int i;
3493 DWORD DestFVF = dest->fvf;
3494 WINED3DVIEWPORT vp;
3495 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3496 BOOL doClip;
3497 int numTextures;
3499 if (lpStrideData->u.s.normal.lpData) {
3500 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3503 if (lpStrideData->u.s.position.lpData == NULL) {
3504 ERR("Source has no position mask\n");
3505 return WINED3DERR_INVALIDCALL;
3508 /* We might access VBOs from this code, so hold the lock */
3509 ENTER_GL();
3511 if (dest->resource.allocatedMemory == NULL) {
3512 /* This may happen if we do direct locking into a vbo. Unlikely,
3513 * but theoretically possible(ddraw processvertices test)
3515 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3516 if(!dest->resource.allocatedMemory) {
3517 LEAVE_GL();
3518 ERR("Out of memory\n");
3519 return E_OUTOFMEMORY;
3521 if(dest->vbo) {
3522 void *src;
3523 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3524 checkGLcall("glBindBufferARB");
3525 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3526 if(src) {
3527 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3529 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3530 checkGLcall("glUnmapBufferARB");
3534 /* Get a pointer into the destination vbo(create one if none exists) and
3535 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3537 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3538 CreateVBO(dest);
3541 if(dest->vbo) {
3542 unsigned char extrabytes = 0;
3543 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3544 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3545 * this may write 4 extra bytes beyond the area that should be written
3547 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3548 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3549 if(!dest_conv_addr) {
3550 ERR("Out of memory\n");
3551 /* Continue without storing converted vertices */
3553 dest_conv = dest_conv_addr;
3556 /* Should I clip?
3557 * a) WINED3DRS_CLIPPING is enabled
3558 * b) WINED3DVOP_CLIP is passed
3560 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3561 static BOOL warned = FALSE;
3563 * The clipping code is not quite correct. Some things need
3564 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3565 * so disable clipping for now.
3566 * (The graphics in Half-Life are broken, and my processvertices
3567 * test crashes with IDirect3DDevice3)
3568 doClip = TRUE;
3570 doClip = FALSE;
3571 if(!warned) {
3572 warned = TRUE;
3573 FIXME("Clipping is broken and disabled for now\n");
3575 } else doClip = FALSE;
3576 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3578 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3579 WINED3DTS_VIEW,
3580 &view_mat);
3581 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3582 WINED3DTS_PROJECTION,
3583 &proj_mat);
3584 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3585 WINED3DTS_WORLDMATRIX(0),
3586 &world_mat);
3588 TRACE("View mat:\n");
3589 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);
3590 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);
3591 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);
3592 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);
3594 TRACE("Proj mat:\n");
3595 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);
3596 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);
3597 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);
3598 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);
3600 TRACE("World mat:\n");
3601 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);
3602 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);
3603 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);
3604 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);
3606 /* Get the viewport */
3607 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3608 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3609 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3611 multiply_matrix(&mat,&view_mat,&world_mat);
3612 multiply_matrix(&mat,&proj_mat,&mat);
3614 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3616 for (i = 0; i < dwCount; i+= 1) {
3617 unsigned int tex_index;
3619 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3620 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3621 /* The position first */
3622 float *p =
3623 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3624 float x, y, z, rhw;
3625 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3627 /* Multiplication with world, view and projection matrix */
3628 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);
3629 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);
3630 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);
3631 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);
3633 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3635 /* WARNING: The following things are taken from d3d7 and were not yet checked
3636 * against d3d8 or d3d9!
3639 /* Clipping conditions: From
3640 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3642 * A vertex is clipped if it does not match the following requirements
3643 * -rhw < x <= rhw
3644 * -rhw < y <= rhw
3645 * 0 < z <= rhw
3646 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3648 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3649 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3653 if( !doClip ||
3654 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3655 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3656 ( rhw > eps ) ) ) {
3658 /* "Normal" viewport transformation (not clipped)
3659 * 1) The values are divided by rhw
3660 * 2) The y axis is negative, so multiply it with -1
3661 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3662 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3663 * 4) Multiply x with Width/2 and add Width/2
3664 * 5) The same for the height
3665 * 6) Add the viewpoint X and Y to the 2D coordinates and
3666 * The minimum Z value to z
3667 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3669 * Well, basically it's simply a linear transformation into viewport
3670 * coordinates
3673 x /= rhw;
3674 y /= rhw;
3675 z /= rhw;
3677 y *= -1;
3679 x *= vp.Width / 2;
3680 y *= vp.Height / 2;
3681 z *= vp.MaxZ - vp.MinZ;
3683 x += vp.Width / 2 + vp.X;
3684 y += vp.Height / 2 + vp.Y;
3685 z += vp.MinZ;
3687 rhw = 1 / rhw;
3688 } else {
3689 /* That vertex got clipped
3690 * Contrary to OpenGL it is not dropped completely, it just
3691 * undergoes a different calculation.
3693 TRACE("Vertex got clipped\n");
3694 x += rhw;
3695 y += rhw;
3697 x /= 2;
3698 y /= 2;
3700 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3701 * outside of the main vertex buffer memory. That needs some more
3702 * investigation...
3706 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3709 ( (float *) dest_ptr)[0] = x;
3710 ( (float *) dest_ptr)[1] = y;
3711 ( (float *) dest_ptr)[2] = z;
3712 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3714 dest_ptr += 3 * sizeof(float);
3716 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3717 dest_ptr += sizeof(float);
3720 if(dest_conv) {
3721 float w = 1 / rhw;
3722 ( (float *) dest_conv)[0] = x * w;
3723 ( (float *) dest_conv)[1] = y * w;
3724 ( (float *) dest_conv)[2] = z * w;
3725 ( (float *) dest_conv)[3] = w;
3727 dest_conv += 3 * sizeof(float);
3729 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3730 dest_conv += sizeof(float);
3734 if (DestFVF & WINED3DFVF_PSIZE) {
3735 dest_ptr += sizeof(DWORD);
3736 if(dest_conv) dest_conv += sizeof(DWORD);
3738 if (DestFVF & WINED3DFVF_NORMAL) {
3739 float *normal =
3740 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3741 /* AFAIK this should go into the lighting information */
3742 FIXME("Didn't expect the destination to have a normal\n");
3743 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3744 if(dest_conv) {
3745 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3749 if (DestFVF & WINED3DFVF_DIFFUSE) {
3750 DWORD *color_d =
3751 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3752 if(!color_d) {
3753 static BOOL warned = FALSE;
3755 if(!warned) {
3756 ERR("No diffuse color in source, but destination has one\n");
3757 warned = TRUE;
3760 *( (DWORD *) dest_ptr) = 0xffffffff;
3761 dest_ptr += sizeof(DWORD);
3763 if(dest_conv) {
3764 *( (DWORD *) dest_conv) = 0xffffffff;
3765 dest_conv += sizeof(DWORD);
3768 else {
3769 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3770 if(dest_conv) {
3771 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3772 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3773 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3774 dest_conv += sizeof(DWORD);
3779 if (DestFVF & WINED3DFVF_SPECULAR) {
3780 /* What's the color value in the feedback buffer? */
3781 DWORD *color_s =
3782 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3783 if(!color_s) {
3784 static BOOL warned = FALSE;
3786 if(!warned) {
3787 ERR("No specular color in source, but destination has one\n");
3788 warned = TRUE;
3791 *( (DWORD *) dest_ptr) = 0xFF000000;
3792 dest_ptr += sizeof(DWORD);
3794 if(dest_conv) {
3795 *( (DWORD *) dest_conv) = 0xFF000000;
3796 dest_conv += sizeof(DWORD);
3799 else {
3800 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3801 if(dest_conv) {
3802 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3803 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3804 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3805 dest_conv += sizeof(DWORD);
3810 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3811 float *tex_coord =
3812 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3813 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3814 if(!tex_coord) {
3815 ERR("No source texture, but destination requests one\n");
3816 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3817 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3819 else {
3820 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3821 if(dest_conv) {
3822 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3828 if(dest_conv) {
3829 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3830 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3831 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3832 dwCount * get_flexible_vertex_size(DestFVF),
3833 dest_conv_addr));
3834 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3835 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3838 LEAVE_GL();
3840 return WINED3D_OK;
3842 #undef copy_and_next
3844 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3846 WineDirect3DVertexStridedData strided;
3847 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3848 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3850 if(pVertexDecl) {
3851 ERR("Output vertex declaration not implemented yet\n");
3854 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3855 * and this call is quite performance critical, so don't call needlessly
3857 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3858 ENTER_GL();
3859 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3860 LEAVE_GL();
3863 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3864 * control the streamIsUP flag, thus restore it afterwards.
3866 This->stateBlock->streamIsUP = FALSE;
3867 memset(&strided, 0, sizeof(strided));
3868 if(This->stateBlock->vertexDecl) {
3869 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3870 } else {
3871 primitiveConvertToStridedData(iface, &strided, &vbo);
3873 This->stateBlock->streamIsUP = streamWasUP;
3875 if(vbo || SrcStartIndex) {
3876 unsigned int i;
3877 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3878 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3880 * Also get the start index in, but only loop over all elements if there's something to add at all.
3882 #define FIXSRC(type) \
3883 if(strided.u.s.type.VBO) { \
3884 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3885 strided.u.s.type.VBO = 0; \
3886 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3887 ENTER_GL(); \
3888 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3889 vb->vbo = 0; \
3890 LEAVE_GL(); \
3892 if(strided.u.s.type.lpData) { \
3893 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3895 FIXSRC(position);
3896 FIXSRC(blendWeights);
3897 FIXSRC(blendMatrixIndices);
3898 FIXSRC(normal);
3899 FIXSRC(pSize);
3900 FIXSRC(diffuse);
3901 FIXSRC(specular);
3902 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3903 FIXSRC(texCoords[i]);
3905 FIXSRC(position2);
3906 FIXSRC(normal2);
3907 FIXSRC(tangent);
3908 FIXSRC(binormal);
3909 FIXSRC(tessFactor);
3910 FIXSRC(fog);
3911 FIXSRC(depth);
3912 FIXSRC(sample);
3913 #undef FIXSRC
3916 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3919 /*****
3920 * Get / Set Texture Stage States
3921 * TODO: Verify against dx9 definitions
3922 *****/
3923 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3925 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3927 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3929 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3931 if (Stage >= MAX_TEXTURES) {
3932 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3933 return WINED3D_OK;
3936 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3937 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3938 This->updateStateBlock->textureState[Stage][Type] = Value;
3940 if (This->isRecordingState) {
3941 TRACE("Recording... not performing anything\n");
3942 return WINED3D_OK;
3945 /* Checked after the assignments to allow proper stateblock recording */
3946 if(oldValue == Value) {
3947 TRACE("App is setting the old value over, nothing to do\n");
3948 return WINED3D_OK;
3951 if(Stage > This->stateBlock->lowest_disabled_stage &&
3952 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3953 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3954 * Changes in other states are important on disabled stages too
3956 return WINED3D_OK;
3959 if(Type == WINED3DTSS_COLOROP) {
3960 int i;
3962 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3963 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3964 * they have to be disabled
3966 * The current stage is dirtified below.
3968 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3969 TRACE("Additionally dirtifying stage %d\n", i);
3970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3972 This->stateBlock->lowest_disabled_stage = Stage;
3973 TRACE("New lowest disabled: %d\n", Stage);
3974 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3975 /* Previously disabled stage enabled. Stages above it may need enabling
3976 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3977 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3979 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3982 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3983 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3984 break;
3986 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3989 This->stateBlock->lowest_disabled_stage = i;
3990 TRACE("New lowest disabled: %d\n", i);
3992 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3993 /* TODO: Built a stage -> texture unit mapping for register combiners */
3997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3999 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4000 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4001 * will call FindTexUnitMap too.
4003 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4004 IWineD3DDeviceImpl_FindTexUnitMap(This);
4006 return WINED3D_OK;
4009 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4011 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4012 *pValue = This->updateStateBlock->textureState[Stage][Type];
4013 return WINED3D_OK;
4016 /*****
4017 * Get / Set Texture
4018 *****/
4019 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4022 IWineD3DBaseTexture *oldTexture;
4024 oldTexture = This->updateStateBlock->textures[Stage];
4025 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4027 #if 0 /* TODO: check so vertex textures */
4028 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4029 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4030 return WINED3D_OK;
4032 #endif
4034 if(pTexture != NULL) {
4035 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4037 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4038 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4039 return WINED3DERR_INVALIDCALL;
4041 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4044 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4045 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4047 This->updateStateBlock->set.textures[Stage] = TRUE;
4048 This->updateStateBlock->changed.textures[Stage] = TRUE;
4049 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4050 This->updateStateBlock->textures[Stage] = pTexture;
4052 /* Handle recording of state blocks */
4053 if (This->isRecordingState) {
4054 TRACE("Recording... not performing anything\n");
4055 return WINED3D_OK;
4058 if(oldTexture == pTexture) {
4059 TRACE("App is setting the same texture again, nothing to do\n");
4060 return WINED3D_OK;
4063 /** NOTE: MSDN says that setTexture increases the reference count,
4064 * and the the application must set the texture back to null (or have a leaky application),
4065 * This means we should pass the refcount up to the parent
4066 *******************************/
4067 if (NULL != This->updateStateBlock->textures[Stage]) {
4068 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4069 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4071 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4072 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4073 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4074 * so the COLOROP and ALPHAOP have to be dirtified.
4076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4079 if(bindCount == 1) {
4080 new->baseTexture.sampler = Stage;
4082 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4086 if (NULL != oldTexture) {
4087 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4088 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4090 IWineD3DBaseTexture_Release(oldTexture);
4091 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4096 if(bindCount && old->baseTexture.sampler == Stage) {
4097 int i;
4098 /* Have to do a search for the other sampler(s) where the texture is bound to
4099 * Shouldn't happen as long as apps bind a texture only to one stage
4101 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4102 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4103 if(This->updateStateBlock->textures[i] == oldTexture) {
4104 old->baseTexture.sampler = i;
4105 break;
4111 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4113 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4114 * pixel shader is used
4116 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4117 IWineD3DDeviceImpl_FindTexUnitMap(This);
4120 return WINED3D_OK;
4123 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4125 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4127 *ppTexture=This->stateBlock->textures[Stage];
4128 if (*ppTexture)
4129 IWineD3DBaseTexture_AddRef(*ppTexture);
4131 return WINED3D_OK;
4134 /*****
4135 * Get Back Buffer
4136 *****/
4137 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4138 IWineD3DSurface **ppBackBuffer) {
4139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4140 IWineD3DSwapChain *swapChain;
4141 HRESULT hr;
4143 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4145 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4146 if (hr == WINED3D_OK) {
4147 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4148 IWineD3DSwapChain_Release(swapChain);
4149 } else {
4150 *ppBackBuffer = NULL;
4152 return hr;
4155 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4157 WARN("(%p) : stub, calling idirect3d for now\n", This);
4158 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4161 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4163 IWineD3DSwapChain *swapChain;
4164 HRESULT hr;
4166 if(iSwapChain > 0) {
4167 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4168 if (hr == WINED3D_OK) {
4169 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4170 IWineD3DSwapChain_Release(swapChain);
4171 } else {
4172 FIXME("(%p) Error getting display mode\n", This);
4174 } else {
4175 /* Don't read the real display mode,
4176 but return the stored mode instead. X11 can't change the color
4177 depth, and some apps are pretty angry if they SetDisplayMode from
4178 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4180 Also don't relay to the swapchain because with ddraw it's possible
4181 that there isn't a swapchain at all */
4182 pMode->Width = This->ddraw_width;
4183 pMode->Height = This->ddraw_height;
4184 pMode->Format = This->ddraw_format;
4185 pMode->RefreshRate = 0;
4186 hr = WINED3D_OK;
4189 return hr;
4192 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4194 TRACE("(%p)->(%p)\n", This, hWnd);
4196 if(This->ddraw_fullscreen) {
4197 if(This->ddraw_window && This->ddraw_window != hWnd) {
4198 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4200 if(hWnd && This->ddraw_window != hWnd) {
4201 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4205 This->ddraw_window = hWnd;
4206 return WINED3D_OK;
4209 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4211 TRACE("(%p)->(%p)\n", This, hWnd);
4213 *hWnd = This->ddraw_window;
4214 return WINED3D_OK;
4217 /*****
4218 * Stateblock related functions
4219 *****/
4221 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4223 IWineD3DStateBlockImpl *object;
4224 HRESULT temp_result;
4225 int i;
4227 TRACE("(%p)\n", This);
4229 if (This->isRecordingState) {
4230 return WINED3DERR_INVALIDCALL;
4233 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4234 if (NULL == object ) {
4235 FIXME("(%p)Error allocating memory for stateblock\n", This);
4236 return E_OUTOFMEMORY;
4238 TRACE("(%p) created object %p\n", This, object);
4239 object->wineD3DDevice= This;
4240 /** FIXME: object->parent = parent; **/
4241 object->parent = NULL;
4242 object->blockType = WINED3DSBT_ALL;
4243 object->ref = 1;
4244 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4246 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4247 list_init(&object->lightMap[i]);
4250 temp_result = allocate_shader_constants(object);
4251 if (WINED3D_OK != temp_result)
4252 return temp_result;
4254 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4255 This->updateStateBlock = object;
4256 This->isRecordingState = TRUE;
4258 TRACE("(%p) recording stateblock %p\n",This , object);
4259 return WINED3D_OK;
4262 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4265 if (!This->isRecordingState) {
4266 FIXME("(%p) not recording! returning error\n", This);
4267 *ppStateBlock = NULL;
4268 return WINED3DERR_INVALIDCALL;
4271 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4272 This->isRecordingState = FALSE;
4273 This->updateStateBlock = This->stateBlock;
4274 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4275 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4276 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4277 return WINED3D_OK;
4280 /*****
4281 * Scene related functions
4282 *****/
4283 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4284 /* At the moment we have no need for any functionality at the beginning
4285 of a scene */
4286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4287 TRACE("(%p)\n", This);
4289 if(This->inScene) {
4290 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4291 return WINED3DERR_INVALIDCALL;
4293 This->inScene = TRUE;
4294 return WINED3D_OK;
4297 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4299 TRACE("(%p)\n", This);
4301 if(!This->inScene) {
4302 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4303 return WINED3DERR_INVALIDCALL;
4306 ENTER_GL();
4307 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4308 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4310 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4311 glFlush();
4312 checkGLcall("glFlush");
4313 LEAVE_GL();
4315 This->inScene = FALSE;
4316 return WINED3D_OK;
4319 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4320 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4321 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4323 IWineD3DSwapChain *swapChain = NULL;
4324 int i;
4325 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4327 TRACE("(%p) Presenting the frame\n", This);
4329 for(i = 0 ; i < swapchains ; i ++) {
4331 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4332 TRACE("presentinng chain %d, %p\n", i, swapChain);
4333 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4334 IWineD3DSwapChain_Release(swapChain);
4337 return WINED3D_OK;
4340 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4341 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4343 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4345 GLbitfield glMask = 0;
4346 unsigned int i;
4347 CONST WINED3DRECT* curRect;
4349 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4350 Count, pRects, Flags, Color, Z, Stencil);
4352 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4353 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4354 /* TODO: What about depth stencil buffers without stencil bits? */
4355 return WINED3DERR_INVALIDCALL;
4358 ENTER_GL();
4359 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4360 * and not the last active one.
4363 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4364 apply_fbo_state(iface);
4367 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4369 glEnable(GL_SCISSOR_TEST);
4370 checkGLcall("glEnable GL_SCISSOR_TEST");
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4374 if (Count > 0 && pRects) {
4375 curRect = pRects;
4376 } else {
4377 curRect = NULL;
4380 /* Only set the values up once, as they are not changing */
4381 if (Flags & WINED3DCLEAR_STENCIL) {
4382 glClearStencil(Stencil);
4383 checkGLcall("glClearStencil");
4384 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4385 glStencilMask(0xFFFFFFFF);
4388 if (Flags & WINED3DCLEAR_ZBUFFER) {
4389 glDepthMask(GL_TRUE);
4390 glClearDepth(Z);
4391 checkGLcall("glClearDepth");
4392 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4396 if (Flags & WINED3DCLEAR_TARGET) {
4397 TRACE("Clearing screen with glClear to color %x\n", Color);
4398 glClearColor(D3DCOLOR_R(Color),
4399 D3DCOLOR_G(Color),
4400 D3DCOLOR_B(Color),
4401 D3DCOLOR_A(Color));
4402 checkGLcall("glClearColor");
4404 /* Clear ALL colors! */
4405 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4406 glMask = glMask | GL_COLOR_BUFFER_BIT;
4409 if (!curRect) {
4410 /* In drawable flag is set below */
4412 glScissor(This->stateBlock->viewport.X,
4413 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4414 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4415 This->stateBlock->viewport.Width,
4416 This->stateBlock->viewport.Height);
4417 checkGLcall("glScissor");
4418 glClear(glMask);
4419 checkGLcall("glClear");
4420 } else {
4421 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4422 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4424 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4425 curRect[0].x2 < target->currentDesc.Width ||
4426 curRect[0].y2 < target->currentDesc.Height) {
4427 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4428 blt_to_drawable(This, target);
4432 /* Now process each rect in turn */
4433 for (i = 0; i < Count; i++) {
4434 /* Note gl uses lower left, width/height */
4435 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4436 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4437 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4438 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4440 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4441 * The rectangle is not cleared, no error is returned, but further rectanlges are
4442 * still cleared if they are valid
4444 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4445 TRACE("Rectangle with negative dimensions, ignoring\n");
4446 continue;
4449 if(This->render_offscreen) {
4450 glScissor(curRect[i].x1, curRect[i].y1,
4451 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4452 } else {
4453 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4454 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4456 checkGLcall("glScissor");
4458 glClear(glMask);
4459 checkGLcall("glClear");
4463 /* Restore the old values (why..?) */
4464 if (Flags & WINED3DCLEAR_STENCIL) {
4465 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4467 if (Flags & WINED3DCLEAR_TARGET) {
4468 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4469 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4470 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4471 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4472 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4475 LEAVE_GL();
4477 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4478 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4480 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4481 target->Flags |= SFLAG_INTEXTURE;
4482 target->Flags &= ~SFLAG_INSYSMEM;
4483 } else {
4484 target->Flags |= SFLAG_INDRAWABLE;
4485 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4487 return WINED3D_OK;
4490 /*****
4491 * Drawing functions
4492 *****/
4493 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4494 UINT PrimitiveCount) {
4496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4498 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4499 debug_d3dprimitivetype(PrimitiveType),
4500 StartVertex, PrimitiveCount);
4502 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4503 if(This->stateBlock->streamIsUP) {
4504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4505 This->stateBlock->streamIsUP = FALSE;
4508 if(This->stateBlock->loadBaseVertexIndex != 0) {
4509 This->stateBlock->loadBaseVertexIndex = 0;
4510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4512 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4513 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4514 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4515 return WINED3D_OK;
4518 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4519 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4520 WINED3DPRIMITIVETYPE PrimitiveType,
4521 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 UINT idxStride = 2;
4525 IWineD3DIndexBuffer *pIB;
4526 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4527 GLuint vbo;
4529 pIB = This->stateBlock->pIndexData;
4530 if (!pIB) {
4531 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4532 * without an index buffer set. (The first time at least...)
4533 * D3D8 simply dies, but I doubt it can do much harm to return
4534 * D3DERR_INVALIDCALL there as well. */
4535 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4536 return WINED3DERR_INVALIDCALL;
4539 if(This->stateBlock->streamIsUP) {
4540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4541 This->stateBlock->streamIsUP = FALSE;
4543 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4545 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4546 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4547 minIndex, NumVertices, startIndex, primCount);
4549 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4550 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4551 idxStride = 2;
4552 } else {
4553 idxStride = 4;
4556 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4557 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4561 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4562 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4564 return WINED3D_OK;
4567 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4568 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4569 UINT VertexStreamZeroStride) {
4570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4573 debug_d3dprimitivetype(PrimitiveType),
4574 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4576 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4577 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4578 This->stateBlock->streamOffset[0] = 0;
4579 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4580 This->stateBlock->streamIsUP = TRUE;
4581 This->stateBlock->loadBaseVertexIndex = 0;
4583 /* TODO: Only mark dirty if drawing from a different UP address */
4584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4586 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4587 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4589 /* MSDN specifies stream zero settings must be set to NULL */
4590 This->stateBlock->streamStride[0] = 0;
4591 This->stateBlock->streamSource[0] = NULL;
4593 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4594 * the new stream sources or use UP drawing again
4596 return WINED3D_OK;
4599 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4600 UINT MinVertexIndex, UINT NumVertices,
4601 UINT PrimitiveCount, CONST void* pIndexData,
4602 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4603 UINT VertexStreamZeroStride) {
4604 int idxStride;
4605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4607 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4608 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4609 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4610 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4612 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4613 idxStride = 2;
4614 } else {
4615 idxStride = 4;
4618 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4619 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4620 This->stateBlock->streamIsUP = TRUE;
4621 This->stateBlock->streamOffset[0] = 0;
4622 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4624 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4625 This->stateBlock->baseVertexIndex = 0;
4626 This->stateBlock->loadBaseVertexIndex = 0;
4627 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4631 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4633 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4634 This->stateBlock->streamSource[0] = NULL;
4635 This->stateBlock->streamStride[0] = 0;
4636 This->stateBlock->pIndexData = NULL;
4637 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4638 * SetStreamSource to specify a vertex buffer
4641 return WINED3D_OK;
4644 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4647 /* Mark the state dirty until we have nicer tracking
4648 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4649 * that value.
4651 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4653 This->stateBlock->baseVertexIndex = 0;
4654 This->up_strided = DrawPrimStrideData;
4655 This->stateBlock->streamIsUP = TRUE;
4656 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4657 This->up_strided = NULL;
4658 return WINED3D_OK;
4660 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4661 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 HRESULT hr = WINED3D_OK;
4664 WINED3DRESOURCETYPE sourceType;
4665 WINED3DRESOURCETYPE destinationType;
4666 int i ,levels;
4668 /* TODO: think about moving the code into IWineD3DBaseTexture */
4670 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4672 /* verify that the source and destination textures aren't NULL */
4673 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4674 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4675 This, pSourceTexture, pDestinationTexture);
4676 hr = WINED3DERR_INVALIDCALL;
4679 if (pSourceTexture == pDestinationTexture) {
4680 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4681 This, pSourceTexture, pDestinationTexture);
4682 hr = WINED3DERR_INVALIDCALL;
4684 /* Verify that the source and destination textures are the same type */
4685 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4686 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4688 if (sourceType != destinationType) {
4689 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4690 This);
4691 hr = WINED3DERR_INVALIDCALL;
4694 /* check that both textures have the identical numbers of levels */
4695 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4696 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4697 hr = WINED3DERR_INVALIDCALL;
4700 if (WINED3D_OK == hr) {
4702 /* Make sure that the destination texture is loaded */
4703 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4705 /* Update every surface level of the texture */
4706 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4708 switch (sourceType) {
4709 case WINED3DRTYPE_TEXTURE:
4711 IWineD3DSurface *srcSurface;
4712 IWineD3DSurface *destSurface;
4714 for (i = 0 ; i < levels ; ++i) {
4715 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4716 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4717 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4718 IWineD3DSurface_Release(srcSurface);
4719 IWineD3DSurface_Release(destSurface);
4720 if (WINED3D_OK != hr) {
4721 WARN("(%p) : Call to update surface failed\n", This);
4722 return hr;
4726 break;
4727 case WINED3DRTYPE_CUBETEXTURE:
4729 IWineD3DSurface *srcSurface;
4730 IWineD3DSurface *destSurface;
4731 WINED3DCUBEMAP_FACES faceType;
4733 for (i = 0 ; i < levels ; ++i) {
4734 /* Update each cube face */
4735 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4736 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4737 if (WINED3D_OK != hr) {
4738 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4739 } else {
4740 TRACE("Got srcSurface %p\n", srcSurface);
4742 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4743 if (WINED3D_OK != hr) {
4744 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4745 } else {
4746 TRACE("Got desrSurface %p\n", destSurface);
4748 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4749 IWineD3DSurface_Release(srcSurface);
4750 IWineD3DSurface_Release(destSurface);
4751 if (WINED3D_OK != hr) {
4752 WARN("(%p) : Call to update surface failed\n", This);
4753 return hr;
4758 break;
4759 #if 0 /* TODO: Add support for volume textures */
4760 case WINED3DRTYPE_VOLUMETEXTURE:
4762 IWineD3DVolume srcVolume = NULL;
4763 IWineD3DSurface destVolume = NULL;
4765 for (i = 0 ; i < levels ; ++i) {
4766 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4767 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4768 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4769 IWineD3DVolume_Release(srcSurface);
4770 IWineD3DVolume_Release(destSurface);
4771 if (WINED3D_OK != hr) {
4772 WARN("(%p) : Call to update volume failed\n", This);
4773 return hr;
4777 break;
4778 #endif
4779 default:
4780 FIXME("(%p) : Unsupported source and destination type\n", This);
4781 hr = WINED3DERR_INVALIDCALL;
4785 return hr;
4788 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4789 IWineD3DSwapChain *swapChain;
4790 HRESULT hr;
4791 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4792 if(hr == WINED3D_OK) {
4793 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4794 IWineD3DSwapChain_Release(swapChain);
4796 return hr;
4799 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4801 /* return a sensible default */
4802 *pNumPasses = 1;
4803 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4804 FIXME("(%p) : stub\n", This);
4805 return WINED3D_OK;
4808 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4810 int j;
4811 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4812 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4813 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4814 return WINED3DERR_INVALIDCALL;
4816 for (j = 0; j < 256; ++j) {
4817 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4818 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4819 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4820 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4822 TRACE("(%p) : returning\n", This);
4823 return WINED3D_OK;
4826 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4828 int j;
4829 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4830 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4831 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4832 return WINED3DERR_INVALIDCALL;
4834 for (j = 0; j < 256; ++j) {
4835 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4836 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4837 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4838 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4840 TRACE("(%p) : returning\n", This);
4841 return WINED3D_OK;
4844 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4846 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4847 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4848 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4849 return WINED3DERR_INVALIDCALL;
4851 /*TODO: stateblocks */
4852 This->currentPalette = PaletteNumber;
4853 TRACE("(%p) : returning\n", This);
4854 return WINED3D_OK;
4857 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4859 if (PaletteNumber == NULL) {
4860 WARN("(%p) : returning Invalid Call\n", This);
4861 return WINED3DERR_INVALIDCALL;
4863 /*TODO: stateblocks */
4864 *PaletteNumber = This->currentPalette;
4865 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4866 return WINED3D_OK;
4869 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4871 static BOOL showFixmes = TRUE;
4872 if (showFixmes) {
4873 FIXME("(%p) : stub\n", This);
4874 showFixmes = FALSE;
4877 This->softwareVertexProcessing = bSoftware;
4878 return WINED3D_OK;
4882 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4884 static BOOL showFixmes = TRUE;
4885 if (showFixmes) {
4886 FIXME("(%p) : stub\n", This);
4887 showFixmes = FALSE;
4889 return This->softwareVertexProcessing;
4893 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 IWineD3DSwapChain *swapChain;
4896 HRESULT hr;
4898 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4900 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4901 if(hr == WINED3D_OK){
4902 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4903 IWineD3DSwapChain_Release(swapChain);
4904 }else{
4905 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4907 return hr;
4911 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4913 static BOOL showfixmes = TRUE;
4914 if(nSegments != 0.0f) {
4915 if( showfixmes) {
4916 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4917 showfixmes = FALSE;
4920 return WINED3D_OK;
4923 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4925 static BOOL showfixmes = TRUE;
4926 if( showfixmes) {
4927 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4928 showfixmes = FALSE;
4930 return 0.0f;
4933 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4935 /** TODO: remove casts to IWineD3DSurfaceImpl
4936 * NOTE: move code to surface to accomplish this
4937 ****************************************/
4938 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4939 int srcWidth, srcHeight;
4940 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4941 WINED3DFORMAT destFormat, srcFormat;
4942 UINT destSize;
4943 int srcLeft, destLeft, destTop;
4944 WINED3DPOOL srcPool, destPool;
4945 int offset = 0;
4946 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4947 glDescriptor *glDescription = NULL;
4949 WINED3DSURFACE_DESC winedesc;
4951 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4952 memset(&winedesc, 0, sizeof(winedesc));
4953 winedesc.Width = &srcSurfaceWidth;
4954 winedesc.Height = &srcSurfaceHeight;
4955 winedesc.Pool = &srcPool;
4956 winedesc.Format = &srcFormat;
4958 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4960 winedesc.Width = &destSurfaceWidth;
4961 winedesc.Height = &destSurfaceHeight;
4962 winedesc.Pool = &destPool;
4963 winedesc.Format = &destFormat;
4964 winedesc.Size = &destSize;
4966 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4968 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4969 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4970 return WINED3DERR_INVALIDCALL;
4973 if (destFormat == WINED3DFMT_UNKNOWN) {
4974 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4975 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4977 /* Get the update surface description */
4978 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4981 ENTER_GL();
4983 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4985 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4986 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4987 checkGLcall("glActiveTextureARB");
4990 /* Make sure the surface is loaded and up to date */
4991 IWineD3DSurface_PreLoad(pDestinationSurface);
4993 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4995 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4996 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4997 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4998 srcLeft = pSourceRect ? pSourceRect->left : 0;
4999 destLeft = pDestPoint ? pDestPoint->x : 0;
5000 destTop = pDestPoint ? pDestPoint->y : 0;
5003 /* This function doesn't support compressed textures
5004 the pitch is just bytesPerPixel * width */
5005 if(srcWidth != srcSurfaceWidth || srcLeft ){
5006 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5007 offset += srcLeft * pSrcSurface->bytesPerPixel;
5008 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5010 /* TODO DXT formats */
5012 if(pSourceRect != NULL && pSourceRect->top != 0){
5013 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5015 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5016 ,This
5017 ,glDescription->level
5018 ,destLeft
5019 ,destTop
5020 ,srcWidth
5021 ,srcHeight
5022 ,glDescription->glFormat
5023 ,glDescription->glType
5024 ,IWineD3DSurface_GetData(pSourceSurface)
5027 /* Sanity check */
5028 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5030 /* need to lock the surface to get the data */
5031 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5034 /* TODO: Cube and volume support */
5035 if(rowoffset != 0){
5036 /* not a whole row so we have to do it a line at a time */
5037 int j;
5039 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5040 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5042 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5044 glTexSubImage2D(glDescription->target
5045 ,glDescription->level
5046 ,destLeft
5048 ,srcWidth
5050 ,glDescription->glFormat
5051 ,glDescription->glType
5052 ,data /* could be quicker using */
5054 data += rowoffset;
5057 } else { /* Full width, so just write out the whole texture */
5059 if (WINED3DFMT_DXT1 == destFormat ||
5060 WINED3DFMT_DXT2 == destFormat ||
5061 WINED3DFMT_DXT3 == destFormat ||
5062 WINED3DFMT_DXT4 == destFormat ||
5063 WINED3DFMT_DXT5 == destFormat) {
5064 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5065 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5066 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5067 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5068 } if (destFormat != srcFormat) {
5069 FIXME("Updating mixed format compressed texture is not curretly support\n");
5070 } else {
5071 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5072 glDescription->level,
5073 glDescription->glFormatInternal,
5074 srcWidth,
5075 srcHeight,
5077 destSize,
5078 IWineD3DSurface_GetData(pSourceSurface));
5080 } else {
5081 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5085 } else {
5086 glTexSubImage2D(glDescription->target
5087 ,glDescription->level
5088 ,destLeft
5089 ,destTop
5090 ,srcWidth
5091 ,srcHeight
5092 ,glDescription->glFormat
5093 ,glDescription->glType
5094 ,IWineD3DSurface_GetData(pSourceSurface)
5098 checkGLcall("glTexSubImage2D");
5100 LEAVE_GL();
5102 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5103 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5106 return WINED3D_OK;
5109 /* Implementation details at http://developer.nvidia.com/attach/6494
5111 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5112 hmm.. no longer supported use
5113 OpenGL evaluators or tessellate surfaces within your application.
5116 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5117 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5119 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5120 FIXME("(%p) : Stub\n", This);
5121 return WINED3D_OK;
5125 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5126 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5128 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5129 FIXME("(%p) : Stub\n", This);
5130 return WINED3D_OK;
5133 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 TRACE("(%p) Handle(%d)\n", This, Handle);
5136 FIXME("(%p) : Stub\n", This);
5137 return WINED3D_OK;
5140 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5141 HRESULT hr;
5142 IWineD3DSwapChain *swapchain;
5144 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5145 if (SUCCEEDED(hr)) {
5146 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5147 return swapchain;
5150 return NULL;
5153 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5156 if (!*fbo) {
5157 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5158 checkGLcall("glGenFramebuffersEXT()");
5160 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5161 checkGLcall("glBindFramebuffer()");
5164 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5165 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5166 GLenum texttarget, target;
5167 GLint old_binding;
5169 texttarget = surface_impl->glDescription.target;
5170 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5171 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5173 IWineD3DSurface_PreLoad(surface);
5175 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5176 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5177 glBindTexture(target, old_binding);
5179 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5181 checkGLcall("attach_surface_fbo");
5184 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5186 IWineD3DSwapChain *swapchain;
5188 swapchain = get_swapchain(surface);
5189 if (swapchain) {
5190 GLenum buffer;
5192 TRACE("Surface %p is onscreen\n", surface);
5194 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5195 buffer = surface_get_gl_buffer(surface, swapchain);
5196 glDrawBuffer(buffer);
5197 checkGLcall("glDrawBuffer()");
5198 } else {
5199 TRACE("Surface %p is offscreen\n", surface);
5200 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5201 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5204 if (rect) {
5205 glEnable(GL_SCISSOR_TEST);
5206 if(!swapchain) {
5207 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5208 } else {
5209 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5210 rect->x2 - rect->x1, rect->y2 - rect->y1);
5212 checkGLcall("glScissor");
5213 } else {
5214 glDisable(GL_SCISSOR_TEST);
5216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5218 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5221 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5222 glClear(GL_COLOR_BUFFER_BIT);
5223 checkGLcall("glClear");
5225 if (This->render_offscreen) {
5226 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5227 } else {
5228 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5229 checkGLcall("glBindFramebuffer()");
5232 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5233 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5234 glDrawBuffer(GL_BACK);
5235 checkGLcall("glDrawBuffer()");
5239 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5241 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5242 WINEDDBLTFX BltFx;
5243 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5245 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5246 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5247 return WINED3DERR_INVALIDCALL;
5250 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5251 color_fill_fbo(iface, pSurface, pRect, color);
5252 return WINED3D_OK;
5253 } else {
5254 /* Just forward this to the DirectDraw blitting engine */
5255 memset(&BltFx, 0, sizeof(BltFx));
5256 BltFx.dwSize = sizeof(BltFx);
5257 BltFx.u5.dwFillColor = color;
5258 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5262 /* rendertarget and deptth stencil functions */
5263 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5266 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5267 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5268 return WINED3DERR_INVALIDCALL;
5271 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5272 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5273 /* Note inc ref on returned surface */
5274 if(*ppRenderTarget != NULL)
5275 IWineD3DSurface_AddRef(*ppRenderTarget);
5276 return WINED3D_OK;
5279 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5281 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5282 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5283 IWineD3DSwapChainImpl *Swapchain;
5284 HRESULT hr;
5286 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5288 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5289 if(hr != WINED3D_OK) {
5290 ERR("Can't get the swapchain\n");
5291 return hr;
5294 /* Make sure to release the swapchain */
5295 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5297 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5298 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5299 return WINED3DERR_INVALIDCALL;
5301 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5302 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5303 return WINED3DERR_INVALIDCALL;
5306 if(Swapchain->frontBuffer != Front) {
5307 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5309 if(Swapchain->frontBuffer)
5310 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5311 Swapchain->frontBuffer = Front;
5313 if(Swapchain->frontBuffer) {
5314 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5318 if(Back && !Swapchain->backBuffer) {
5319 /* We need memory for the back buffer array - only one back buffer this way */
5320 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5321 if(!Swapchain->backBuffer) {
5322 ERR("Out of memory\n");
5323 return E_OUTOFMEMORY;
5327 if(Swapchain->backBuffer[0] != Back) {
5328 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5330 /* What to do about the context here in the case of multithreading? Not sure.
5331 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5333 ENTER_GL();
5334 if(!Swapchain->backBuffer[0]) {
5335 /* GL was told to draw to the front buffer at creation,
5336 * undo that
5338 glDrawBuffer(GL_BACK);
5339 checkGLcall("glDrawBuffer(GL_BACK)");
5340 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5341 Swapchain->presentParms.BackBufferCount = 1;
5342 } else if (!Back) {
5343 /* That makes problems - disable for now */
5344 /* glDrawBuffer(GL_FRONT); */
5345 checkGLcall("glDrawBuffer(GL_FRONT)");
5346 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5347 Swapchain->presentParms.BackBufferCount = 0;
5349 LEAVE_GL();
5351 if(Swapchain->backBuffer[0])
5352 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5353 Swapchain->backBuffer[0] = Back;
5355 if(Swapchain->backBuffer[0]) {
5356 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5357 } else {
5358 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5363 return WINED3D_OK;
5366 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5368 *ppZStencilSurface = This->depthStencilBuffer;
5369 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5371 if(*ppZStencilSurface != NULL) {
5372 /* Note inc ref on returned surface */
5373 IWineD3DSurface_AddRef(*ppZStencilSurface);
5375 return WINED3D_OK;
5378 /* TODO: Handle stencil attachments */
5379 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5381 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5383 TRACE("Set depth stencil to %p\n", depth_stencil);
5385 if (depth_stencil_impl) {
5386 if (depth_stencil_impl->current_renderbuffer) {
5387 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5388 checkGLcall("glFramebufferRenderbufferEXT()");
5389 } else {
5390 GLenum texttarget, target;
5391 GLint old_binding = 0;
5393 texttarget = depth_stencil_impl->glDescription.target;
5394 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5395 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5397 IWineD3DSurface_PreLoad(depth_stencil);
5399 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5400 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5401 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5402 glBindTexture(target, old_binding);
5404 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5405 checkGLcall("glFramebufferTexture2DEXT()");
5407 } else {
5408 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5409 checkGLcall("glFramebufferTexture2DEXT()");
5413 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5415 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5417 TRACE("Set render target %u to %p\n", idx, render_target);
5419 if (rtimpl) {
5420 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5421 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5422 } else {
5423 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5424 checkGLcall("glFramebufferTexture2DEXT()");
5426 This->draw_buffers[idx] = GL_NONE;
5430 static void check_fbo_status(IWineD3DDevice *iface) {
5431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5432 GLenum status;
5434 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5435 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5436 TRACE("FBO complete\n");
5437 } else {
5438 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5440 /* Dump the FBO attachments */
5441 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5442 IWineD3DSurfaceImpl *attachment;
5443 int i;
5445 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5446 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5447 if (attachment) {
5448 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5449 attachment->pow2Width, attachment->pow2Height);
5452 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5453 if (attachment) {
5454 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5455 attachment->pow2Width, attachment->pow2Height);
5461 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5463 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5464 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5466 if (!ds_impl) return FALSE;
5468 if (ds_impl->current_renderbuffer) {
5469 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5470 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5473 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5474 rt_impl->pow2Height != ds_impl->pow2Height);
5477 void apply_fbo_state(IWineD3DDevice *iface) {
5478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5479 unsigned int i;
5481 if (This->render_offscreen) {
5482 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5484 /* Apply render targets */
5485 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5486 IWineD3DSurface *render_target = This->render_targets[i];
5487 if (This->fbo_color_attachments[i] != render_target) {
5488 set_render_target_fbo(iface, i, render_target);
5489 This->fbo_color_attachments[i] = render_target;
5493 /* Apply depth targets */
5494 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5495 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5496 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5498 if (This->stencilBufferTarget) {
5499 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5501 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5502 This->fbo_depth_attachment = This->stencilBufferTarget;
5505 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5506 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5507 checkGLcall("glDrawBuffers()");
5508 } else {
5509 glDrawBuffer(This->draw_buffers[0]);
5510 checkGLcall("glDrawBuffer()");
5512 } else {
5513 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5516 check_fbo_status(iface);
5519 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5520 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5522 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5523 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5524 GLenum gl_filter;
5526 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5527 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5528 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5529 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5531 glDisable(GL_SCISSOR_TEST);
5532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5534 switch (filter) {
5535 case WINED3DTEXF_LINEAR:
5536 gl_filter = GL_LINEAR;
5537 break;
5539 default:
5540 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5541 case WINED3DTEXF_NONE:
5542 case WINED3DTEXF_POINT:
5543 gl_filter = GL_NEAREST;
5544 break;
5547 /* Attach src surface to src fbo */
5548 src_swapchain = get_swapchain(src_surface);
5549 if (src_swapchain) {
5550 GLenum buffer;
5552 TRACE("Source surface %p is onscreen\n", src_surface);
5554 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5555 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5556 glReadBuffer(buffer);
5557 checkGLcall("glReadBuffer()");
5559 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5560 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5561 } else {
5562 TRACE("Source surface %p is offscreen\n", src_surface);
5563 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5564 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5565 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5566 checkGLcall("glReadBuffer()");
5569 /* Attach dst surface to dst fbo */
5570 dst_swapchain = get_swapchain(dst_surface);
5571 if (dst_swapchain) {
5572 GLenum buffer;
5574 TRACE("Destination surface %p is onscreen\n", dst_surface);
5576 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5577 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5578 glDrawBuffer(buffer);
5579 checkGLcall("glDrawBuffer()");
5581 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5582 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5583 } else {
5584 TRACE("Destination surface %p is offscreen\n", dst_surface);
5585 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5586 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5587 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5588 checkGLcall("glDrawBuffer()");
5591 if (flip) {
5592 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5593 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5594 checkGLcall("glBlitFramebuffer()");
5595 } else {
5596 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5597 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5598 checkGLcall("glBlitFramebuffer()");
5601 if (This->render_offscreen) {
5602 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5603 } else {
5604 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5605 checkGLcall("glBindFramebuffer()");
5608 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5609 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5610 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5611 glDrawBuffer(GL_BACK);
5612 checkGLcall("glDrawBuffer()");
5616 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5618 WINED3DVIEWPORT viewport;
5620 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5622 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5623 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5624 return WINED3DERR_INVALIDCALL;
5627 /* MSDN says that null disables the render target
5628 but a device must always be associated with a render target
5629 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5631 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5632 for more details
5634 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5635 FIXME("Trying to set render target 0 to NULL\n");
5636 return WINED3DERR_INVALIDCALL;
5638 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5639 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);
5640 return WINED3DERR_INVALIDCALL;
5643 /* If we are trying to set what we already have, don't bother */
5644 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5645 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5646 return WINED3D_OK;
5648 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5649 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5650 This->render_targets[RenderTargetIndex] = pRenderTarget;
5652 /* Render target 0 is special */
5653 if(RenderTargetIndex == 0) {
5654 /* Finally, reset the viewport as the MSDN states. */
5655 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5656 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5657 viewport.X = 0;
5658 viewport.Y = 0;
5659 viewport.MaxZ = 1.0f;
5660 viewport.MinZ = 0.0f;
5661 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5662 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5663 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5667 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5668 * ctx properly.
5669 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5670 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5672 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5674 return WINED3D_OK;
5677 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5679 HRESULT hr = WINED3D_OK;
5680 IWineD3DSurface *tmp;
5682 TRACE("(%p) Swapping z-buffer\n",This);
5684 if (pNewZStencil == This->stencilBufferTarget) {
5685 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5686 } else {
5687 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5688 * depending on the renter target implementation being used.
5689 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5690 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5691 * stencil buffer and incure an extra memory overhead
5692 ******************************************************/
5694 tmp = This->stencilBufferTarget;
5695 This->stencilBufferTarget = pNewZStencil;
5696 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5697 /* should we be calling the parent or the wined3d surface? */
5698 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5699 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5700 hr = WINED3D_OK;
5702 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5703 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5710 return hr;
5713 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5714 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5716 /* TODO: the use of Impl is deprecated. */
5717 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5718 WINED3DLOCKED_RECT lockedRect;
5720 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5722 /* some basic validation checks */
5723 if(This->cursorTexture) {
5724 ENTER_GL();
5725 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5726 glDeleteTextures(1, &This->cursorTexture);
5727 LEAVE_GL();
5728 This->cursorTexture = 0;
5731 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5732 This->haveHardwareCursor = TRUE;
5733 else
5734 This->haveHardwareCursor = FALSE;
5736 if(pCursorBitmap) {
5737 WINED3DLOCKED_RECT rect;
5739 /* MSDN: Cursor must be A8R8G8B8 */
5740 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5741 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5742 return WINED3DERR_INVALIDCALL;
5745 /* MSDN: Cursor must be smaller than the display mode */
5746 if(pSur->currentDesc.Width > This->ddraw_width ||
5747 pSur->currentDesc.Height > This->ddraw_height) {
5748 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);
5749 return WINED3DERR_INVALIDCALL;
5752 if (!This->haveHardwareCursor) {
5753 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5755 /* Do not store the surface's pointer because the application may
5756 * release it after setting the cursor image. Windows doesn't
5757 * addref the set surface, so we can't do this either without
5758 * creating circular refcount dependencies. Copy out the gl texture
5759 * instead.
5761 This->cursorWidth = pSur->currentDesc.Width;
5762 This->cursorHeight = pSur->currentDesc.Height;
5763 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5765 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5766 char *mem, *bits = (char *)rect.pBits;
5767 GLint intfmt = tableEntry->glInternal;
5768 GLint format = tableEntry->glFormat;
5769 GLint type = tableEntry->glType;
5770 INT height = This->cursorHeight;
5771 INT width = This->cursorWidth;
5772 INT bpp = tableEntry->bpp;
5773 INT i;
5775 /* Reformat the texture memory (pitch and width can be
5776 * different) */
5777 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5778 for(i = 0; i < height; i++)
5779 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5780 IWineD3DSurface_UnlockRect(pCursorBitmap);
5781 ENTER_GL();
5783 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5784 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5785 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5788 /* Make sure that a proper texture unit is selected */
5789 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5790 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5791 checkGLcall("glActiveTextureARB");
5793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5794 /* Create a new cursor texture */
5795 glGenTextures(1, &This->cursorTexture);
5796 checkGLcall("glGenTextures");
5797 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5798 checkGLcall("glBindTexture");
5799 /* Copy the bitmap memory into the cursor texture */
5800 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5801 HeapFree(GetProcessHeap(), 0, mem);
5802 checkGLcall("glTexImage2D");
5804 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5805 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5806 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5809 LEAVE_GL();
5811 else
5813 FIXME("A cursor texture was not returned.\n");
5814 This->cursorTexture = 0;
5817 else
5819 /* Draw a hardware cursor */
5820 ICONINFO cursorInfo;
5821 HCURSOR cursor;
5822 /* Create and clear maskBits because it is not needed for
5823 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5824 * chunks. */
5825 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5826 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5827 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5828 WINED3DLOCK_NO_DIRTY_UPDATE |
5829 WINED3DLOCK_READONLY
5831 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5832 pSur->currentDesc.Height);
5834 cursorInfo.fIcon = FALSE;
5835 cursorInfo.xHotspot = XHotSpot;
5836 cursorInfo.yHotspot = YHotSpot;
5837 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5838 pSur->currentDesc.Height, 1,
5839 1, &maskBits);
5840 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5841 pSur->currentDesc.Height, 1,
5842 32, lockedRect.pBits);
5843 IWineD3DSurface_UnlockRect(pCursorBitmap);
5844 /* Create our cursor and clean up. */
5845 cursor = CreateIconIndirect(&cursorInfo);
5846 SetCursor(cursor);
5847 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5848 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5849 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5850 This->hardwareCursor = cursor;
5851 HeapFree(GetProcessHeap(), 0, maskBits);
5855 This->xHotSpot = XHotSpot;
5856 This->yHotSpot = YHotSpot;
5857 return WINED3D_OK;
5860 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5862 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5864 This->xScreenSpace = XScreenSpace;
5865 This->yScreenSpace = YScreenSpace;
5867 return;
5871 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5873 BOOL oldVisible = This->bCursorVisible;
5874 POINT pt;
5876 TRACE("(%p) : visible(%d)\n", This, bShow);
5879 * When ShowCursor is first called it should make the cursor appear at the OS's last
5880 * known cursor position. Because of this, some applications just repetitively call
5881 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5883 GetCursorPos(&pt);
5884 This->xScreenSpace = pt.x;
5885 This->yScreenSpace = pt.y;
5887 if (This->haveHardwareCursor) {
5888 This->bCursorVisible = bShow;
5889 if (bShow)
5890 SetCursor(This->hardwareCursor);
5891 else
5892 SetCursor(NULL);
5894 else
5896 if (This->cursorTexture)
5897 This->bCursorVisible = bShow;
5900 return oldVisible;
5903 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5905 TRACE("(%p) : state (%u)\n", This, This->state);
5906 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5907 switch (This->state) {
5908 case WINED3D_OK:
5909 return WINED3D_OK;
5910 case WINED3DERR_DEVICELOST:
5912 ResourceList *resourceList = This->resources;
5913 while (NULL != resourceList) {
5914 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5915 return WINED3DERR_DEVICENOTRESET;
5916 resourceList = resourceList->next;
5918 return WINED3DERR_DEVICELOST;
5920 case WINED3DERR_DRIVERINTERNALERROR:
5921 return WINED3DERR_DRIVERINTERNALERROR;
5924 /* Unknown state */
5925 return WINED3DERR_DRIVERINTERNALERROR;
5929 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5931 /** FIXME: Resource tracking needs to be done,
5932 * The closes we can do to this is set the priorities of all managed textures low
5933 * and then reset them.
5934 ***********************************************************/
5935 FIXME("(%p) : stub\n", This);
5936 return WINED3D_OK;
5939 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5940 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5942 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5943 if(surface->Flags & SFLAG_DIBSECTION) {
5944 /* Release the DC */
5945 SelectObject(surface->hDC, surface->dib.holdbitmap);
5946 DeleteDC(surface->hDC);
5947 /* Release the DIB section */
5948 DeleteObject(surface->dib.DIBsection);
5949 surface->dib.bitmap_data = NULL;
5950 surface->resource.allocatedMemory = NULL;
5951 surface->Flags &= ~SFLAG_DIBSECTION;
5953 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5954 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5955 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5956 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5957 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5958 } else {
5959 surface->pow2Width = surface->pow2Height = 1;
5960 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5961 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5963 if(surface->glDescription.textureName) {
5964 ENTER_GL();
5965 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5966 glDeleteTextures(1, &surface->glDescription.textureName);
5967 LEAVE_GL();
5968 surface->glDescription.textureName = 0;
5969 surface->Flags &= ~SFLAG_CLIENT;
5971 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5972 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5973 surface->Flags |= SFLAG_NONPOW2;
5974 } else {
5975 surface->Flags &= ~SFLAG_NONPOW2;
5977 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5978 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5981 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5983 IWineD3DSwapChainImpl *swapchain;
5984 HRESULT hr;
5985 BOOL DisplayModeChanged = FALSE;
5986 WINED3DDISPLAYMODE mode;
5987 TRACE("(%p)\n", This);
5989 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5990 if(FAILED(hr)) {
5991 ERR("Failed to get the first implicit swapchain\n");
5992 return hr;
5995 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5996 * on an existing gl context, so there's no real need for recreation.
5998 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6000 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6002 TRACE("New params:\n");
6003 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6004 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6005 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6006 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6007 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6008 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6009 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6010 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6011 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6012 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6013 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6014 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6015 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6017 /* No special treatment of these parameters. Just store them */
6018 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6019 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6020 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6021 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6023 /* What to do about these? */
6024 if(pPresentationParameters->BackBufferCount != 0 &&
6025 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6026 ERR("Cannot change the back buffer count yet\n");
6028 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6029 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6030 ERR("Cannot change the back buffer format yet\n");
6032 if(pPresentationParameters->hDeviceWindow != NULL &&
6033 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6034 ERR("Cannot change the device window yet\n");
6036 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6037 ERR("What do do about a changed auto depth stencil parameter?\n");
6040 if(pPresentationParameters->Windowed) {
6041 mode.Width = swapchain->orig_width;
6042 mode.Height = swapchain->orig_height;
6043 mode.RefreshRate = 0;
6044 mode.Format = swapchain->presentParms.BackBufferFormat;
6045 } else {
6046 mode.Width = pPresentationParameters->BackBufferWidth;
6047 mode.Height = pPresentationParameters->BackBufferHeight;
6048 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6049 mode.Format = swapchain->presentParms.BackBufferFormat;
6052 /* Should Width == 800 && Height == 0 set 800x600? */
6053 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6054 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6055 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6057 WINED3DVIEWPORT vp;
6058 int i;
6060 vp.X = 0;
6061 vp.Y = 0;
6062 vp.Width = pPresentationParameters->BackBufferWidth;
6063 vp.Height = pPresentationParameters->BackBufferHeight;
6064 vp.MinZ = 0;
6065 vp.MaxZ = 1;
6067 if(!pPresentationParameters->Windowed) {
6068 DisplayModeChanged = TRUE;
6070 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6071 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6073 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6074 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6075 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6078 /* Now set the new viewport */
6079 IWineD3DDevice_SetViewport(iface, &vp);
6082 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6083 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6084 DisplayModeChanged) {
6086 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6087 if(!pPresentationParameters->Windowed) {
6088 IWineD3DDevice_SetFullscreen(iface, TRUE);
6091 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6093 /* Switching out of fullscreen mode? First set the original res, then change the window */
6094 if(pPresentationParameters->Windowed) {
6095 IWineD3DDevice_SetFullscreen(iface, FALSE);
6097 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6100 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6101 return WINED3D_OK;
6104 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6106 /** FIXME: always true at the moment **/
6107 if(!bEnableDialogs) {
6108 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6110 return WINED3D_OK;
6114 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6116 TRACE("(%p) : pParameters %p\n", This, pParameters);
6118 *pParameters = This->createParms;
6119 return WINED3D_OK;
6122 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6123 IWineD3DSwapChain *swapchain;
6124 HRESULT hrc = WINED3D_OK;
6126 TRACE("Relaying to swapchain\n");
6128 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6129 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6130 IWineD3DSwapChain_Release(swapchain);
6132 return;
6135 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6136 IWineD3DSwapChain *swapchain;
6137 HRESULT hrc = WINED3D_OK;
6139 TRACE("Relaying to swapchain\n");
6141 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6142 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6143 IWineD3DSwapChain_Release(swapchain);
6145 return;
6149 /** ********************************************************
6150 * Notification functions
6151 ** ********************************************************/
6152 /** This function must be called in the release of a resource when ref == 0,
6153 * the contents of resource must still be correct,
6154 * any handels to other resource held by the caller must be closed
6155 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6156 *****************************************************/
6157 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6159 ResourceList* resourceList;
6161 TRACE("(%p) : resource %p\n", This, resource);
6162 /* add a new texture to the frot of the linked list */
6163 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6164 resourceList->resource = resource;
6166 /* Get the old head */
6167 resourceList->next = This->resources;
6169 This->resources = resourceList;
6170 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6172 return;
6175 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6177 ResourceList* resourceList = NULL;
6178 ResourceList* previousResourceList = NULL;
6180 TRACE("(%p) : resource %p\n", This, resource);
6182 resourceList = This->resources;
6184 while (resourceList != NULL) {
6185 if(resourceList->resource == resource) break;
6186 previousResourceList = resourceList;
6187 resourceList = resourceList->next;
6190 if (resourceList == NULL) {
6191 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6192 return;
6193 } else {
6194 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6196 /* make sure we don't leave a hole in the list */
6197 if (previousResourceList != NULL) {
6198 previousResourceList->next = resourceList->next;
6199 } else {
6200 This->resources = resourceList->next;
6203 return;
6207 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6209 int counter;
6211 TRACE("(%p) : resource %p\n", This, resource);
6212 switch(IWineD3DResource_GetType(resource)){
6213 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6214 case WINED3DRTYPE_SURFACE: {
6215 unsigned int i;
6217 /* Cleanup any FBO attachments */
6218 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6219 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6220 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6221 set_render_target_fbo(iface, i, NULL);
6222 This->fbo_color_attachments[i] = NULL;
6225 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6226 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6227 set_depth_stencil_fbo(iface, NULL);
6228 This->fbo_depth_attachment = NULL;
6231 break;
6234 case WINED3DRTYPE_TEXTURE:
6235 case WINED3DRTYPE_CUBETEXTURE:
6236 case WINED3DRTYPE_VOLUMETEXTURE:
6237 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6238 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6239 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6240 This->stateBlock->textures[counter] = NULL;
6242 if (This->updateStateBlock != This->stateBlock ){
6243 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6244 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6245 This->updateStateBlock->textures[counter] = NULL;
6249 break;
6250 case WINED3DRTYPE_VOLUME:
6251 /* TODO: nothing really? */
6252 break;
6253 case WINED3DRTYPE_VERTEXBUFFER:
6254 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6256 int streamNumber;
6257 TRACE("Cleaning up stream pointers\n");
6259 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6260 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6261 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6263 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6264 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6265 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6266 This->updateStateBlock->streamSource[streamNumber] = 0;
6267 /* Set changed flag? */
6270 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) */
6271 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6272 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6273 This->stateBlock->streamSource[streamNumber] = 0;
6276 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6277 else { /* This shouldn't happen */
6278 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6280 #endif
6284 break;
6285 case WINED3DRTYPE_INDEXBUFFER:
6286 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6287 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6288 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6289 This->updateStateBlock->pIndexData = NULL;
6292 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6293 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6294 This->stateBlock->pIndexData = NULL;
6298 break;
6299 default:
6300 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6301 break;
6305 /* Remove the resoruce from the resourceStore */
6306 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6308 TRACE("Resource released\n");
6312 /**********************************************************
6313 * IWineD3DDevice VTbl follows
6314 **********************************************************/
6316 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6318 /*** IUnknown methods ***/
6319 IWineD3DDeviceImpl_QueryInterface,
6320 IWineD3DDeviceImpl_AddRef,
6321 IWineD3DDeviceImpl_Release,
6322 /*** IWineD3DDevice methods ***/
6323 IWineD3DDeviceImpl_GetParent,
6324 /*** Creation methods**/
6325 IWineD3DDeviceImpl_CreateVertexBuffer,
6326 IWineD3DDeviceImpl_CreateIndexBuffer,
6327 IWineD3DDeviceImpl_CreateStateBlock,
6328 IWineD3DDeviceImpl_CreateSurface,
6329 IWineD3DDeviceImpl_CreateTexture,
6330 IWineD3DDeviceImpl_CreateVolumeTexture,
6331 IWineD3DDeviceImpl_CreateVolume,
6332 IWineD3DDeviceImpl_CreateCubeTexture,
6333 IWineD3DDeviceImpl_CreateQuery,
6334 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6335 IWineD3DDeviceImpl_CreateVertexDeclaration,
6336 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6337 IWineD3DDeviceImpl_CreateVertexShader,
6338 IWineD3DDeviceImpl_CreatePixelShader,
6339 IWineD3DDeviceImpl_CreatePalette,
6340 /*** Odd functions **/
6341 IWineD3DDeviceImpl_Init3D,
6342 IWineD3DDeviceImpl_Uninit3D,
6343 IWineD3DDeviceImpl_SetFullscreen,
6344 IWineD3DDeviceImpl_SetMultithreaded,
6345 IWineD3DDeviceImpl_EvictManagedResources,
6346 IWineD3DDeviceImpl_GetAvailableTextureMem,
6347 IWineD3DDeviceImpl_GetBackBuffer,
6348 IWineD3DDeviceImpl_GetCreationParameters,
6349 IWineD3DDeviceImpl_GetDeviceCaps,
6350 IWineD3DDeviceImpl_GetDirect3D,
6351 IWineD3DDeviceImpl_GetDisplayMode,
6352 IWineD3DDeviceImpl_SetDisplayMode,
6353 IWineD3DDeviceImpl_GetHWND,
6354 IWineD3DDeviceImpl_SetHWND,
6355 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6356 IWineD3DDeviceImpl_GetRasterStatus,
6357 IWineD3DDeviceImpl_GetSwapChain,
6358 IWineD3DDeviceImpl_Reset,
6359 IWineD3DDeviceImpl_SetDialogBoxMode,
6360 IWineD3DDeviceImpl_SetCursorProperties,
6361 IWineD3DDeviceImpl_SetCursorPosition,
6362 IWineD3DDeviceImpl_ShowCursor,
6363 IWineD3DDeviceImpl_TestCooperativeLevel,
6364 /*** Getters and setters **/
6365 IWineD3DDeviceImpl_SetClipPlane,
6366 IWineD3DDeviceImpl_GetClipPlane,
6367 IWineD3DDeviceImpl_SetClipStatus,
6368 IWineD3DDeviceImpl_GetClipStatus,
6369 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6370 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6371 IWineD3DDeviceImpl_SetDepthStencilSurface,
6372 IWineD3DDeviceImpl_GetDepthStencilSurface,
6373 IWineD3DDeviceImpl_SetFVF,
6374 IWineD3DDeviceImpl_GetFVF,
6375 IWineD3DDeviceImpl_SetGammaRamp,
6376 IWineD3DDeviceImpl_GetGammaRamp,
6377 IWineD3DDeviceImpl_SetIndices,
6378 IWineD3DDeviceImpl_GetIndices,
6379 IWineD3DDeviceImpl_SetBaseVertexIndex,
6380 IWineD3DDeviceImpl_SetLight,
6381 IWineD3DDeviceImpl_GetLight,
6382 IWineD3DDeviceImpl_SetLightEnable,
6383 IWineD3DDeviceImpl_GetLightEnable,
6384 IWineD3DDeviceImpl_SetMaterial,
6385 IWineD3DDeviceImpl_GetMaterial,
6386 IWineD3DDeviceImpl_SetNPatchMode,
6387 IWineD3DDeviceImpl_GetNPatchMode,
6388 IWineD3DDeviceImpl_SetPaletteEntries,
6389 IWineD3DDeviceImpl_GetPaletteEntries,
6390 IWineD3DDeviceImpl_SetPixelShader,
6391 IWineD3DDeviceImpl_GetPixelShader,
6392 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6393 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6394 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6395 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6396 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6397 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6398 IWineD3DDeviceImpl_SetRenderState,
6399 IWineD3DDeviceImpl_GetRenderState,
6400 IWineD3DDeviceImpl_SetRenderTarget,
6401 IWineD3DDeviceImpl_GetRenderTarget,
6402 IWineD3DDeviceImpl_SetFrontBackBuffers,
6403 IWineD3DDeviceImpl_SetSamplerState,
6404 IWineD3DDeviceImpl_GetSamplerState,
6405 IWineD3DDeviceImpl_SetScissorRect,
6406 IWineD3DDeviceImpl_GetScissorRect,
6407 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6408 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6409 IWineD3DDeviceImpl_SetStreamSource,
6410 IWineD3DDeviceImpl_GetStreamSource,
6411 IWineD3DDeviceImpl_SetStreamSourceFreq,
6412 IWineD3DDeviceImpl_GetStreamSourceFreq,
6413 IWineD3DDeviceImpl_SetTexture,
6414 IWineD3DDeviceImpl_GetTexture,
6415 IWineD3DDeviceImpl_SetTextureStageState,
6416 IWineD3DDeviceImpl_GetTextureStageState,
6417 IWineD3DDeviceImpl_SetTransform,
6418 IWineD3DDeviceImpl_GetTransform,
6419 IWineD3DDeviceImpl_SetVertexDeclaration,
6420 IWineD3DDeviceImpl_GetVertexDeclaration,
6421 IWineD3DDeviceImpl_SetVertexShader,
6422 IWineD3DDeviceImpl_GetVertexShader,
6423 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6424 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6425 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6426 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6427 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6428 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6429 IWineD3DDeviceImpl_SetViewport,
6430 IWineD3DDeviceImpl_GetViewport,
6431 IWineD3DDeviceImpl_MultiplyTransform,
6432 IWineD3DDeviceImpl_ValidateDevice,
6433 IWineD3DDeviceImpl_ProcessVertices,
6434 /*** State block ***/
6435 IWineD3DDeviceImpl_BeginStateBlock,
6436 IWineD3DDeviceImpl_EndStateBlock,
6437 /*** Scene management ***/
6438 IWineD3DDeviceImpl_BeginScene,
6439 IWineD3DDeviceImpl_EndScene,
6440 IWineD3DDeviceImpl_Present,
6441 IWineD3DDeviceImpl_Clear,
6442 /*** Drawing ***/
6443 IWineD3DDeviceImpl_DrawPrimitive,
6444 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6445 IWineD3DDeviceImpl_DrawPrimitiveUP,
6446 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6447 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6448 IWineD3DDeviceImpl_DrawRectPatch,
6449 IWineD3DDeviceImpl_DrawTriPatch,
6450 IWineD3DDeviceImpl_DeletePatch,
6451 IWineD3DDeviceImpl_ColorFill,
6452 IWineD3DDeviceImpl_UpdateTexture,
6453 IWineD3DDeviceImpl_UpdateSurface,
6454 IWineD3DDeviceImpl_GetFrontBufferData,
6455 /*** object tracking ***/
6456 IWineD3DDeviceImpl_ResourceReleased
6460 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6461 WINED3DRS_ALPHABLENDENABLE ,
6462 WINED3DRS_ALPHAFUNC ,
6463 WINED3DRS_ALPHAREF ,
6464 WINED3DRS_ALPHATESTENABLE ,
6465 WINED3DRS_BLENDOP ,
6466 WINED3DRS_COLORWRITEENABLE ,
6467 WINED3DRS_DESTBLEND ,
6468 WINED3DRS_DITHERENABLE ,
6469 WINED3DRS_FILLMODE ,
6470 WINED3DRS_FOGDENSITY ,
6471 WINED3DRS_FOGEND ,
6472 WINED3DRS_FOGSTART ,
6473 WINED3DRS_LASTPIXEL ,
6474 WINED3DRS_SHADEMODE ,
6475 WINED3DRS_SRCBLEND ,
6476 WINED3DRS_STENCILENABLE ,
6477 WINED3DRS_STENCILFAIL ,
6478 WINED3DRS_STENCILFUNC ,
6479 WINED3DRS_STENCILMASK ,
6480 WINED3DRS_STENCILPASS ,
6481 WINED3DRS_STENCILREF ,
6482 WINED3DRS_STENCILWRITEMASK ,
6483 WINED3DRS_STENCILZFAIL ,
6484 WINED3DRS_TEXTUREFACTOR ,
6485 WINED3DRS_WRAP0 ,
6486 WINED3DRS_WRAP1 ,
6487 WINED3DRS_WRAP2 ,
6488 WINED3DRS_WRAP3 ,
6489 WINED3DRS_WRAP4 ,
6490 WINED3DRS_WRAP5 ,
6491 WINED3DRS_WRAP6 ,
6492 WINED3DRS_WRAP7 ,
6493 WINED3DRS_ZENABLE ,
6494 WINED3DRS_ZFUNC ,
6495 WINED3DRS_ZWRITEENABLE
6498 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6499 WINED3DTSS_ADDRESSW ,
6500 WINED3DTSS_ALPHAARG0 ,
6501 WINED3DTSS_ALPHAARG1 ,
6502 WINED3DTSS_ALPHAARG2 ,
6503 WINED3DTSS_ALPHAOP ,
6504 WINED3DTSS_BUMPENVLOFFSET ,
6505 WINED3DTSS_BUMPENVLSCALE ,
6506 WINED3DTSS_BUMPENVMAT00 ,
6507 WINED3DTSS_BUMPENVMAT01 ,
6508 WINED3DTSS_BUMPENVMAT10 ,
6509 WINED3DTSS_BUMPENVMAT11 ,
6510 WINED3DTSS_COLORARG0 ,
6511 WINED3DTSS_COLORARG1 ,
6512 WINED3DTSS_COLORARG2 ,
6513 WINED3DTSS_COLOROP ,
6514 WINED3DTSS_RESULTARG ,
6515 WINED3DTSS_TEXCOORDINDEX ,
6516 WINED3DTSS_TEXTURETRANSFORMFLAGS
6519 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6520 WINED3DSAMP_ADDRESSU ,
6521 WINED3DSAMP_ADDRESSV ,
6522 WINED3DSAMP_ADDRESSW ,
6523 WINED3DSAMP_BORDERCOLOR ,
6524 WINED3DSAMP_MAGFILTER ,
6525 WINED3DSAMP_MINFILTER ,
6526 WINED3DSAMP_MIPFILTER ,
6527 WINED3DSAMP_MIPMAPLODBIAS ,
6528 WINED3DSAMP_MAXMIPLEVEL ,
6529 WINED3DSAMP_MAXANISOTROPY ,
6530 WINED3DSAMP_SRGBTEXTURE ,
6531 WINED3DSAMP_ELEMENTINDEX
6534 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6535 WINED3DRS_AMBIENT ,
6536 WINED3DRS_AMBIENTMATERIALSOURCE ,
6537 WINED3DRS_CLIPPING ,
6538 WINED3DRS_CLIPPLANEENABLE ,
6539 WINED3DRS_COLORVERTEX ,
6540 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6541 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6542 WINED3DRS_FOGDENSITY ,
6543 WINED3DRS_FOGEND ,
6544 WINED3DRS_FOGSTART ,
6545 WINED3DRS_FOGTABLEMODE ,
6546 WINED3DRS_FOGVERTEXMODE ,
6547 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6548 WINED3DRS_LIGHTING ,
6549 WINED3DRS_LOCALVIEWER ,
6550 WINED3DRS_MULTISAMPLEANTIALIAS ,
6551 WINED3DRS_MULTISAMPLEMASK ,
6552 WINED3DRS_NORMALIZENORMALS ,
6553 WINED3DRS_PATCHEDGESTYLE ,
6554 WINED3DRS_POINTSCALE_A ,
6555 WINED3DRS_POINTSCALE_B ,
6556 WINED3DRS_POINTSCALE_C ,
6557 WINED3DRS_POINTSCALEENABLE ,
6558 WINED3DRS_POINTSIZE ,
6559 WINED3DRS_POINTSIZE_MAX ,
6560 WINED3DRS_POINTSIZE_MIN ,
6561 WINED3DRS_POINTSPRITEENABLE ,
6562 WINED3DRS_RANGEFOGENABLE ,
6563 WINED3DRS_SPECULARMATERIALSOURCE ,
6564 WINED3DRS_TWEENFACTOR ,
6565 WINED3DRS_VERTEXBLEND
6568 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6569 WINED3DTSS_TEXCOORDINDEX ,
6570 WINED3DTSS_TEXTURETRANSFORMFLAGS
6573 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6574 WINED3DSAMP_DMAPOFFSET
6577 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6578 DWORD rep = StateTable[state].representative;
6579 DWORD idx;
6580 BYTE shift;
6581 UINT i;
6582 WineD3DContext *context;
6584 if(!rep) return;
6585 for(i = 0; i < This->numContexts; i++) {
6586 context = This->contexts[i];
6587 if(isStateDirty(context, rep)) continue;
6589 context->dirtyArray[context->numDirtyEntries++] = rep;
6590 idx = rep >> 5;
6591 shift = rep & 0x1f;
6592 context->isStateDirty[idx] |= (1 << shift);