wined3d: Manage private data in a wine linked list.
[wine/hacks.git] / dlls / wined3d / device.c
blob16df8a5ee64b9ec24c1574611ee62537de69ad8e
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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 WINED3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 static inline Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* static function declarations */
74 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
76 /* helper macros */
77 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
79 #define D3DCREATEOBJECTINSTANCE(object, type) { \
80 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
81 D3DMEMCHECK(object, pp##type); \
82 object->lpVtbl = &IWineD3D##type##_Vtbl; \
83 object->wineD3DDevice = This; \
84 object->parent = parent; \
85 object->ref = 1; \
86 *pp##type = (IWineD3D##type *) object; \
89 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
90 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
91 D3DMEMCHECK(object, pp##type); \
92 object->lpVtbl = &IWineD3D##type##_Vtbl; \
93 object->parent = parent; \
94 object->ref = 1; \
95 object->baseShader.device = (IWineD3DDevice*) This; \
96 list_init(&object->baseShader.linked_programs); \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 list_init(&object->resource.privateData); \
113 /* Check that we have enough video ram left */ \
114 if (Pool == WINED3DPOOL_DEFAULT) { \
115 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
116 WARN("Out of 'bogus' video memory\n"); \
117 HeapFree(GetProcessHeap(), 0, object); \
118 *pp##type = NULL; \
119 return WINED3DERR_OUTOFVIDEOMEMORY; \
121 globalChangeGlRam(_size); \
123 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
124 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
125 FIXME("Out of memory!\n"); \
126 HeapFree(GetProcessHeap(), 0, object); \
127 *pp##type = NULL; \
128 return WINED3DERR_OUTOFVIDEOMEMORY; \
130 *pp##type = (IWineD3D##type *) object; \
131 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
132 TRACE("(%p) : Created resource %p\n", This, object); \
135 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
136 _basetexture.levels = Levels; \
137 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
138 _basetexture.LOD = 0; \
139 _basetexture.dirty = TRUE; \
142 /**********************************************************
143 * Global variable / Constants follow
144 **********************************************************/
145 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
147 /**********************************************************
148 * IUnknown parts follows
149 **********************************************************/
151 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
155 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
156 if (IsEqualGUID(riid, &IID_IUnknown)
157 || IsEqualGUID(riid, &IID_IWineD3DBase)
158 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
159 IUnknown_AddRef(iface);
160 *ppobj = This;
161 return S_OK;
163 *ppobj = NULL;
164 return E_NOINTERFACE;
167 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
169 ULONG refCount = InterlockedIncrement(&This->ref);
171 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
172 return refCount;
175 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
177 ULONG refCount = InterlockedDecrement(&This->ref);
179 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
181 if (!refCount) {
182 if (This->fbo) {
183 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
185 if (This->src_fbo) {
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
188 if (This->dst_fbo) {
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
192 HeapFree(GetProcessHeap(), 0, This->render_targets);
193 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
194 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
196 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
198 /* TODO: Clean up all the surfaces and textures! */
199 /* NOTE: You must release the parent if the object was created via a callback
200 ** ***************************/
202 /* Release the update stateblock */
203 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
204 if(This->updateStateBlock != This->stateBlock)
205 FIXME("(%p) Something's still holding the Update stateblock\n",This);
207 This->updateStateBlock = NULL;
208 { /* because were not doing proper internal refcounts releasing the primary state block
209 causes recursion with the extra checks in ResourceReleased, to avoid this we have
210 to set this->stateBlock = NULL; first */
211 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
212 This->stateBlock = NULL;
214 /* Release the stateblock */
215 if(IWineD3DStateBlock_Release(stateBlock) > 0){
216 FIXME("(%p) Something's still holding the Update stateblock\n",This);
220 if (This->resources != NULL ) {
221 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
222 dumpResources(This->resources);
225 if(This->contexts) ERR("Context array not freed!\n");
227 IWineD3D_Release(This->wineD3D);
228 This->wineD3D = NULL;
229 HeapFree(GetProcessHeap(), 0, This);
230 TRACE("Freed device %p\n", This);
231 This = NULL;
233 return refCount;
236 /**********************************************************
237 * IWineD3DDevice implementation follows
238 **********************************************************/
239 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
241 *pParent = This->parent;
242 IUnknown_AddRef(This->parent);
243 return WINED3D_OK;
246 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
247 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
248 GLenum error, glUsage;
249 DWORD vboUsage = object->resource.usage;
250 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
251 WARN("Creating a vbo failed once, not trying again\n");
252 return;
255 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
257 ENTER_GL();
258 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
259 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
261 /* Make sure that the gl error is cleared. Do not use checkGLcall
262 * here because checkGLcall just prints a fixme and continues. However,
263 * if an error during VBO creation occurs we can fall back to non-vbo operation
264 * with full functionality(but performance loss)
266 while(glGetError() != GL_NO_ERROR);
268 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
269 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
270 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
271 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
272 * to check if the rhw and color values are in the correct format.
275 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
276 error = glGetError();
277 if(object->vbo == 0 || error != GL_NO_ERROR) {
278 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
279 goto error;
282 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR) {
285 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
286 goto error;
289 /* Don't use static, because dx apps tend to update the buffer
290 * quite often even if they specify 0 usage. Because we always keep the local copy
291 * we never read from the vbo and can create a write only opengl buffer.
293 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
294 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
295 case WINED3DUSAGE_DYNAMIC:
296 TRACE("Gl usage = GL_STREAM_DRAW\n");
297 glUsage = GL_STREAM_DRAW_ARB;
298 break;
299 case WINED3DUSAGE_WRITEONLY:
300 default:
301 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
302 glUsage = GL_DYNAMIC_DRAW_ARB;
303 break;
306 /* Reserve memory for the buffer. The amount of data won't change
307 * so we are safe with calling glBufferData once with a NULL ptr and
308 * calling glBufferSubData on updates
310 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
311 error = glGetError();
312 if(error != GL_NO_ERROR) {
313 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
314 goto error;
317 LEAVE_GL();
319 return;
320 error:
321 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
322 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
323 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
324 object->vbo = 0;
325 object->Flags |= VBFLAG_VBOCREATEFAIL;
326 LEAVE_GL();
327 return;
330 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
331 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
332 IUnknown *parent) {
333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
334 IWineD3DVertexBufferImpl *object;
335 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
336 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
337 BOOL conv;
339 if(Size == 0) {
340 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
341 *ppVertexBuffer = NULL;
342 return WINED3DERR_INVALIDCALL;
345 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
347 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
348 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
350 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
351 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
353 object->fvf = FVF;
355 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
356 * drawStridedFast (half-life 2).
358 * Basically converting the vertices in the buffer is quite expensive, and observations
359 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
360 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
362 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
363 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
364 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
365 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
366 * dx7 apps.
367 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
368 * more. In this call we can convert dx7 buffers too.
370 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
371 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
372 (dxVersion > 7 || !conv) ) {
373 CreateVBO(object);
375 return WINED3D_OK;
378 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
379 GLenum error, glUsage;
380 TRACE("Creating VBO for Index Buffer %p\n", object);
382 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
383 * restored on the next draw
385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
387 ENTER_GL();
388 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
389 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
391 while(glGetError());
393 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
394 error = glGetError();
395 if(error != GL_NO_ERROR || object->vbo == 0) {
396 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
397 goto out;
400 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
401 error = glGetError();
402 if(error != GL_NO_ERROR) {
403 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
404 goto out;
407 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
408 * copy no readback will be needed
410 glUsage = GL_STATIC_DRAW_ARB;
411 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
412 error = glGetError();
413 if(error != GL_NO_ERROR) {
414 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
415 goto out;
417 LEAVE_GL();
418 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
419 return;
421 out:
422 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
423 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
424 LEAVE_GL();
425 object->vbo = 0;
428 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
429 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
430 HANDLE *sharedHandle, IUnknown *parent) {
431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
432 IWineD3DIndexBufferImpl *object;
433 TRACE("(%p) Creating index buffer\n", This);
435 /* Allocate the storage for the device */
436 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
438 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
439 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
442 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
443 CreateIndexBufferVBO(This, object);
446 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
447 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
448 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
450 return WINED3D_OK;
453 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
456 IWineD3DStateBlockImpl *object;
457 int i, j;
458 HRESULT temp_result;
460 D3DCREATEOBJECTINSTANCE(object, StateBlock)
461 object->blockType = Type;
463 for(i = 0; i < LIGHTMAP_SIZE; i++) {
464 list_init(&object->lightMap[i]);
467 /* Special case - Used during initialization to produce a placeholder stateblock
468 so other functions called can update a state block */
469 if (Type == WINED3DSBT_INIT) {
470 /* Don't bother increasing the reference count otherwise a device will never
471 be freed due to circular dependencies */
472 return WINED3D_OK;
475 temp_result = allocate_shader_constants(object);
476 if (WINED3D_OK != temp_result)
477 return temp_result;
479 /* Otherwise, might as well set the whole state block to the appropriate values */
480 if (This->stateBlock != NULL)
481 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
482 else
483 memset(object->streamFreq, 1, sizeof(object->streamFreq));
485 /* Reset the ref and type after kludging it */
486 object->wineD3DDevice = This;
487 object->ref = 1;
488 object->blockType = Type;
490 TRACE("Updating changed flags appropriate for type %d\n", Type);
492 if (Type == WINED3DSBT_ALL) {
494 TRACE("ALL => Pretend everything has changed\n");
495 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
497 /* Lights are not part of the changed / set structure */
498 for(j = 0; j < LIGHTMAP_SIZE; j++) {
499 struct list *e;
500 LIST_FOR_EACH(e, &object->lightMap[j]) {
501 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
502 light->changed = TRUE;
503 light->enabledChanged = TRUE;
506 } else if (Type == WINED3DSBT_PIXELSTATE) {
508 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
509 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
511 object->changed.pixelShader = TRUE;
513 /* Pixel Shader Constants */
514 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
515 object->changed.pixelShaderConstantsF[i] = TRUE;
516 for (i = 0; i < MAX_CONST_B; ++i)
517 object->changed.pixelShaderConstantsB[i] = TRUE;
518 for (i = 0; i < MAX_CONST_I; ++i)
519 object->changed.pixelShaderConstantsI[i] = TRUE;
521 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
522 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
524 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
525 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
526 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
529 for (j = 0 ; j < 16; j++) {
530 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
532 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
536 } else if (Type == WINED3DSBT_VERTEXSTATE) {
538 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
539 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
541 object->changed.vertexShader = TRUE;
543 /* Vertex Shader Constants */
544 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
545 object->changed.vertexShaderConstantsF[i] = TRUE;
546 for (i = 0; i < MAX_CONST_B; ++i)
547 object->changed.vertexShaderConstantsB[i] = TRUE;
548 for (i = 0; i < MAX_CONST_I; ++i)
549 object->changed.vertexShaderConstantsI[i] = TRUE;
551 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
552 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
554 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
555 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
556 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
559 for (j = 0 ; j < 16; j++){
560 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
561 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
565 for(j = 0; j < LIGHTMAP_SIZE; j++) {
566 struct list *e;
567 LIST_FOR_EACH(e, &object->lightMap[j]) {
568 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
569 light->changed = TRUE;
570 light->enabledChanged = TRUE;
573 } else {
574 FIXME("Unrecognized state block type %d\n", Type);
577 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
578 return WINED3D_OK;
582 /* ************************************
583 MSDN:
584 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
586 Discard
587 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
589 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.
591 ******************************** */
593 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) {
594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
595 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
596 unsigned int pow2Width, pow2Height;
597 unsigned int Size = 1;
598 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
599 TRACE("(%p) Create surface\n",This);
601 /** FIXME: Check ranges on the inputs are valid
602 * MSDN
603 * MultisampleQuality
604 * [in] Quality level. The valid range is between zero and one less than the level
605 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
606 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
607 * values of paired render targets, depth stencil surfaces, and the MultiSample type
608 * must all match.
609 *******************************/
613 * TODO: Discard MSDN
614 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
616 * If this flag is set, the contents of the depth stencil buffer will be
617 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
618 * with a different depth surface.
620 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
621 ***************************/
623 if(MultisampleQuality < 0) {
624 FIXME("Invalid multisample level %d\n", MultisampleQuality);
625 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
628 if(MultisampleQuality > 0) {
629 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
630 MultisampleQuality=0;
633 /** FIXME: Check that the format is supported
634 * by the device.
635 *******************************/
637 /* Non-power2 support */
638 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
639 pow2Width = Width;
640 pow2Height = Height;
641 } else {
642 /* Find the nearest pow2 match */
643 pow2Width = pow2Height = 1;
644 while (pow2Width < Width) pow2Width <<= 1;
645 while (pow2Height < Height) pow2Height <<= 1;
648 if (pow2Width > Width || pow2Height > Height) {
649 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
650 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
651 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
652 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
653 This, Width, Height);
654 return WINED3DERR_NOTAVAILABLE;
658 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
659 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
660 * space!
661 *********************************/
662 if (WINED3DFMT_UNKNOWN == Format) {
663 Size = 0;
664 } else if (Format == WINED3DFMT_DXT1) {
665 /* DXT1 is half byte per pixel */
666 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
668 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
669 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
670 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
671 } else {
672 /* The pitch is a multiple of 4 bytes */
673 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
674 Size *= Height;
677 /** Create and initialise the surface resource **/
678 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
679 /* "Standalone" surface */
680 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
682 object->currentDesc.Width = Width;
683 object->currentDesc.Height = Height;
684 object->currentDesc.MultiSampleType = MultiSample;
685 object->currentDesc.MultiSampleQuality = MultisampleQuality;
687 /* Setup some glformat defaults */
688 object->glDescription.glFormat = tableEntry->glFormat;
689 object->glDescription.glFormatInternal = tableEntry->glInternal;
690 object->glDescription.glType = tableEntry->glType;
692 object->glDescription.textureName = 0;
693 object->glDescription.level = Level;
694 object->glDescription.target = GL_TEXTURE_2D;
696 /* Internal data */
697 object->pow2Width = pow2Width;
698 object->pow2Height = pow2Height;
700 /* Flags */
701 object->Flags = SFLAG_DYNLOCK;
702 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
703 object->Flags |= Discard ? SFLAG_DISCARD : 0;
704 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
705 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
708 if (WINED3DFMT_UNKNOWN != Format) {
709 object->bytesPerPixel = tableEntry->bpp;
710 } else {
711 object->bytesPerPixel = 0;
714 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
716 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
718 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
719 * this function is too deep to need to care about things like this.
720 * Levels need to be checked too, and possibly Type since they all affect what can be done.
721 * ****************************************/
722 switch(Pool) {
723 case WINED3DPOOL_SCRATCH:
724 if(!Lockable)
725 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
726 "which are mutually exclusive, setting lockable to TRUE\n");
727 Lockable = TRUE;
728 break;
729 case WINED3DPOOL_SYSTEMMEM:
730 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
731 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
732 case WINED3DPOOL_MANAGED:
733 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
734 "Usage of DYNAMIC which are mutually exclusive, not doing "
735 "anything just telling you.\n");
736 break;
737 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
738 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
739 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
740 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
741 break;
742 default:
743 FIXME("(%p) Unknown pool %d\n", This, Pool);
744 break;
747 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
748 FIXME("Trying to create a render target that isn't in the default pool\n");
751 /* mark the texture as dirty so that it gets loaded first time around*/
752 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
753 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
754 This, Width, Height, Format, debug_d3dformat(Format),
755 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
757 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
758 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
759 This->ddraw_primary = (IWineD3DSurface *) object;
761 /* Look at the implementation and set the correct Vtable */
762 switch(Impl) {
763 case SURFACE_OPENGL:
764 /* Nothing to do, it's set already */
765 break;
767 case SURFACE_GDI:
768 object->lpVtbl = &IWineGDISurface_Vtbl;
769 break;
771 default:
772 /* To be sure to catch this */
773 ERR("Unknown requested surface implementation %d!\n", Impl);
774 IWineD3DSurface_Release((IWineD3DSurface *) object);
775 return WINED3DERR_INVALIDCALL;
778 list_init(&object->renderbuffers);
780 /* Call the private setup routine */
781 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
785 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
786 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
787 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
788 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
791 IWineD3DTextureImpl *object;
792 unsigned int i;
793 UINT tmpW;
794 UINT tmpH;
795 HRESULT hr;
796 unsigned int pow2Width;
797 unsigned int pow2Height;
800 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
801 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
802 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
804 /* TODO: It should only be possible to create textures for formats
805 that are reported as supported */
806 if (WINED3DFMT_UNKNOWN >= Format) {
807 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
808 return WINED3DERR_INVALIDCALL;
811 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
812 D3DINITIALIZEBASETEXTURE(object->baseTexture);
813 object->width = Width;
814 object->height = Height;
816 /** Non-power2 support **/
817 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
818 pow2Width = Width;
819 pow2Height = Height;
820 } else {
821 /* Find the nearest pow2 match */
822 pow2Width = pow2Height = 1;
823 while (pow2Width < Width) pow2Width <<= 1;
824 while (pow2Height < Height) pow2Height <<= 1;
827 /** FIXME: add support for real non-power-two if it's provided by the video card **/
828 /* Precalculated scaling for 'faked' non power of two texture coords */
829 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
830 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
831 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
833 /* Calculate levels for mip mapping */
834 if (Levels == 0) {
835 TRACE("calculating levels %d\n", object->baseTexture.levels);
836 object->baseTexture.levels++;
837 tmpW = Width;
838 tmpH = Height;
839 while (tmpW > 1 || tmpH > 1) {
840 tmpW = max(1, tmpW >> 1);
841 tmpH = max(1, tmpH >> 1);
842 object->baseTexture.levels++;
844 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
847 /* Generate all the surfaces */
848 tmpW = Width;
849 tmpH = Height;
850 for (i = 0; i < object->baseTexture.levels; i++)
852 /* use the callback to create the texture surface */
853 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
854 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
855 FIXME("Failed to create surface %p\n", object);
856 /* clean up */
857 object->surfaces[i] = NULL;
858 IWineD3DTexture_Release((IWineD3DTexture *)object);
860 *ppTexture = NULL;
861 return hr;
864 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
865 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
866 /* calculate the next mipmap level */
867 tmpW = max(1, tmpW >> 1);
868 tmpH = max(1, tmpH >> 1);
871 TRACE("(%p) : Created texture %p\n", This, object);
872 return WINED3D_OK;
875 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
876 UINT Width, UINT Height, UINT Depth,
877 UINT Levels, DWORD Usage,
878 WINED3DFORMAT Format, WINED3DPOOL Pool,
879 IWineD3DVolumeTexture **ppVolumeTexture,
880 HANDLE *pSharedHandle, IUnknown *parent,
881 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
884 IWineD3DVolumeTextureImpl *object;
885 unsigned int i;
886 UINT tmpW;
887 UINT tmpH;
888 UINT tmpD;
890 /* TODO: It should only be possible to create textures for formats
891 that are reported as supported */
892 if (WINED3DFMT_UNKNOWN >= Format) {
893 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
894 return WINED3DERR_INVALIDCALL;
897 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
898 D3DINITIALIZEBASETEXTURE(object->baseTexture);
900 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
901 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
903 object->width = Width;
904 object->height = Height;
905 object->depth = Depth;
907 /* Calculate levels for mip mapping */
908 if (Levels == 0) {
909 object->baseTexture.levels++;
910 tmpW = Width;
911 tmpH = Height;
912 tmpD = Depth;
913 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
914 tmpW = max(1, tmpW >> 1);
915 tmpH = max(1, tmpH >> 1);
916 tmpD = max(1, tmpD >> 1);
917 object->baseTexture.levels++;
919 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
922 /* Generate all the surfaces */
923 tmpW = Width;
924 tmpH = Height;
925 tmpD = Depth;
927 for (i = 0; i < object->baseTexture.levels; i++)
929 HRESULT hr;
930 /* Create the volume */
931 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
932 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
934 if(FAILED(hr)) {
935 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
936 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
937 *ppVolumeTexture = NULL;
938 return hr;
941 /* Set its container to this object */
942 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
944 /* calcualte the next mipmap level */
945 tmpW = max(1, tmpW >> 1);
946 tmpH = max(1, tmpH >> 1);
947 tmpD = max(1, tmpD >> 1);
950 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
951 TRACE("(%p) : Created volume texture %p\n", This, object);
952 return WINED3D_OK;
955 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
956 UINT Width, UINT Height, UINT Depth,
957 DWORD Usage,
958 WINED3DFORMAT Format, WINED3DPOOL Pool,
959 IWineD3DVolume** ppVolume,
960 HANDLE* pSharedHandle, IUnknown *parent) {
962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
963 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
964 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
966 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
968 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
969 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
971 object->currentDesc.Width = Width;
972 object->currentDesc.Height = Height;
973 object->currentDesc.Depth = Depth;
974 object->bytesPerPixel = formatDesc->bpp;
976 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
977 object->lockable = TRUE;
978 object->locked = FALSE;
979 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
980 object->dirty = TRUE;
982 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
985 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
986 UINT Levels, DWORD Usage,
987 WINED3DFORMAT Format, WINED3DPOOL Pool,
988 IWineD3DCubeTexture **ppCubeTexture,
989 HANDLE *pSharedHandle, IUnknown *parent,
990 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
993 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
994 unsigned int i, j;
995 UINT tmpW;
996 HRESULT hr;
997 unsigned int pow2EdgeLength = EdgeLength;
999 /* TODO: It should only be possible to create textures for formats
1000 that are reported as supported */
1001 if (WINED3DFMT_UNKNOWN >= Format) {
1002 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1003 return WINED3DERR_INVALIDCALL;
1006 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1007 WARN("(%p) : Tried to create not supported cube texture\n", This);
1008 return WINED3DERR_INVALIDCALL;
1011 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1012 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1014 TRACE("(%p) Create Cube Texture\n", This);
1016 /** Non-power2 support **/
1018 /* Find the nearest pow2 match */
1019 pow2EdgeLength = 1;
1020 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1022 object->edgeLength = EdgeLength;
1023 /* TODO: support for native non-power 2 */
1024 /* Precalculated scaling for 'faked' non power of two texture coords */
1025 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1027 /* Calculate levels for mip mapping */
1028 if (Levels == 0) {
1029 object->baseTexture.levels++;
1030 tmpW = EdgeLength;
1031 while (tmpW > 1) {
1032 tmpW = max(1, tmpW >> 1);
1033 object->baseTexture.levels++;
1035 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1038 /* Generate all the surfaces */
1039 tmpW = EdgeLength;
1040 for (i = 0; i < object->baseTexture.levels; i++) {
1042 /* Create the 6 faces */
1043 for (j = 0; j < 6; j++) {
1045 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1046 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1048 if(hr!= WINED3D_OK) {
1049 /* clean up */
1050 int k;
1051 int l;
1052 for (l = 0; l < j; l++) {
1053 IWineD3DSurface_Release(object->surfaces[j][i]);
1055 for (k = 0; k < i; k++) {
1056 for (l = 0; l < 6; l++) {
1057 IWineD3DSurface_Release(object->surfaces[l][j]);
1061 FIXME("(%p) Failed to create surface\n",object);
1062 HeapFree(GetProcessHeap(),0,object);
1063 *ppCubeTexture = NULL;
1064 return hr;
1066 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1067 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1069 tmpW = max(1, tmpW >> 1);
1072 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1073 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1074 return WINED3D_OK;
1077 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1079 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1080 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1082 /* Just a check to see if we support this type of query */
1083 switch(Type) {
1084 case WINED3DQUERYTYPE_OCCLUSION:
1085 TRACE("(%p) occlusion query\n", This);
1086 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1087 hr = WINED3D_OK;
1088 else
1089 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1090 break;
1092 case WINED3DQUERYTYPE_EVENT:
1093 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1094 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1095 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1097 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1099 hr = WINED3D_OK;
1100 break;
1102 case WINED3DQUERYTYPE_VCACHE:
1103 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1104 case WINED3DQUERYTYPE_VERTEXSTATS:
1105 case WINED3DQUERYTYPE_TIMESTAMP:
1106 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1107 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1108 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1109 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1110 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1111 case WINED3DQUERYTYPE_PIXELTIMINGS:
1112 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1113 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1114 default:
1115 FIXME("(%p) Unhandled query type %d\n", This, Type);
1117 if(NULL == ppQuery || hr != WINED3D_OK) {
1118 return hr;
1121 D3DCREATEOBJECTINSTANCE(object, Query)
1122 object->type = Type;
1123 /* allocated the 'extended' data based on the type of query requested */
1124 switch(Type){
1125 case WINED3DQUERYTYPE_OCCLUSION:
1126 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1127 TRACE("(%p) Allocating data for an occlusion query\n", This);
1128 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1129 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1130 break;
1132 case WINED3DQUERYTYPE_EVENT:
1133 /* TODO: GL_APPLE_fence */
1134 if(GL_SUPPORT(APPLE_FENCE)) {
1135 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1136 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1137 checkGLcall("glGenFencesAPPLE");
1138 } else if(GL_SUPPORT(NV_FENCE)) {
1139 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1140 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1141 checkGLcall("glGenFencesNV");
1143 break;
1145 case WINED3DQUERYTYPE_VCACHE:
1146 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1147 case WINED3DQUERYTYPE_VERTEXSTATS:
1148 case WINED3DQUERYTYPE_TIMESTAMP:
1149 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1150 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1151 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1152 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1153 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1154 case WINED3DQUERYTYPE_PIXELTIMINGS:
1155 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1156 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1157 default:
1158 object->extendedData = 0;
1159 FIXME("(%p) Unhandled query type %d\n",This , Type);
1161 TRACE("(%p) : Created Query %p\n", This, object);
1162 return WINED3D_OK;
1165 /*****************************************************************************
1166 * IWineD3DDeviceImpl_SetupFullscreenWindow
1168 * Helper function that modifies a HWND's Style and ExStyle for proper
1169 * fullscreen use.
1171 * Params:
1172 * iface: Pointer to the IWineD3DDevice interface
1173 * window: Window to setup
1175 *****************************************************************************/
1176 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1179 LONG style, exStyle;
1180 /* Don't do anything if an original style is stored.
1181 * That shouldn't happen
1183 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1184 if (This->style || This->exStyle) {
1185 ERR("(%p): Want to change the window parameters of HWND %p, but "
1186 "another style is stored for restoration afterwards\n", This, window);
1189 /* Get the parameters and save them */
1190 style = GetWindowLongW(window, GWL_STYLE);
1191 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1192 This->style = style;
1193 This->exStyle = exStyle;
1195 /* Filter out window decorations */
1196 style &= ~WS_CAPTION;
1197 style &= ~WS_THICKFRAME;
1198 exStyle &= ~WS_EX_WINDOWEDGE;
1199 exStyle &= ~WS_EX_CLIENTEDGE;
1201 /* Make sure the window is managed, otherwise we won't get keyboard input */
1202 style |= WS_POPUP | WS_SYSMENU;
1204 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1205 This->style, This->exStyle, style, exStyle);
1207 SetWindowLongW(window, GWL_STYLE, style);
1208 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1210 /* Inform the window about the update. */
1211 SetWindowPos(window, HWND_TOP, 0, 0,
1212 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1213 ShowWindow(window, SW_NORMAL);
1216 /*****************************************************************************
1217 * IWineD3DDeviceImpl_RestoreWindow
1219 * Helper function that restores a windows' properties when taking it out
1220 * of fullscreen mode
1222 * Params:
1223 * iface: Pointer to the IWineD3DDevice interface
1224 * window: Window to setup
1226 *****************************************************************************/
1227 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1230 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1231 * switch, do nothing
1233 if (!This->style && !This->exStyle) return;
1235 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1236 This, window, This->style, This->exStyle);
1238 SetWindowLongW(window, GWL_STYLE, This->style);
1239 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1241 /* Delete the old values */
1242 This->style = 0;
1243 This->exStyle = 0;
1245 /* Inform the window about the update */
1246 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1247 0, 0, 0, 0, /* Pos, Size, ignored */
1248 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1251 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1252 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1253 IUnknown* parent,
1254 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1255 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1258 HDC hDc;
1259 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1260 HRESULT hr = WINED3D_OK;
1261 IUnknown *bufferParent;
1262 Display *display;
1264 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1266 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1267 * does a device hold a reference to a swap chain giving them a lifetime of the device
1268 * or does the swap chain notify the device of its destruction.
1269 *******************************/
1271 /* Check the params */
1272 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1273 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1274 return WINED3DERR_INVALIDCALL;
1275 } else if (pPresentationParameters->BackBufferCount > 1) {
1276 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");
1279 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1281 /*********************
1282 * Lookup the window Handle and the relating X window handle
1283 ********************/
1285 /* Setup hwnd we are using, plus which display this equates to */
1286 object->win_handle = pPresentationParameters->hDeviceWindow;
1287 if (!object->win_handle) {
1288 object->win_handle = This->createParms.hFocusWindow;
1291 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1292 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1293 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1294 return WINED3DERR_NOTAVAILABLE;
1296 hDc = GetDC(object->win_handle);
1297 display = get_display(hDc);
1298 ReleaseDC(object->win_handle, hDc);
1299 TRACE("Using a display of %p %p\n", display, hDc);
1301 if (NULL == display || NULL == hDc) {
1302 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1303 return WINED3DERR_NOTAVAILABLE;
1306 if (object->win == 0) {
1307 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1308 return WINED3DERR_NOTAVAILABLE;
1311 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1312 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1313 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1315 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1316 * then the corresponding dimension of the client area of the hDeviceWindow
1317 * (or the focus window, if hDeviceWindow is NULL) is taken.
1318 **********************/
1320 if (pPresentationParameters->Windowed &&
1321 ((pPresentationParameters->BackBufferWidth == 0) ||
1322 (pPresentationParameters->BackBufferHeight == 0))) {
1324 RECT Rect;
1325 GetClientRect(object->win_handle, &Rect);
1327 if (pPresentationParameters->BackBufferWidth == 0) {
1328 pPresentationParameters->BackBufferWidth = Rect.right;
1329 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1331 if (pPresentationParameters->BackBufferHeight == 0) {
1332 pPresentationParameters->BackBufferHeight = Rect.bottom;
1333 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1337 /* Put the correct figures in the presentation parameters */
1338 TRACE("Copying across presentation parameters\n");
1339 object->presentParms = *pPresentationParameters;
1341 TRACE("calling rendertarget CB\n");
1342 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1343 parent,
1344 object->presentParms.BackBufferWidth,
1345 object->presentParms.BackBufferHeight,
1346 object->presentParms.BackBufferFormat,
1347 object->presentParms.MultiSampleType,
1348 object->presentParms.MultiSampleQuality,
1349 TRUE /* Lockable */,
1350 &object->frontBuffer,
1351 NULL /* pShared (always null)*/);
1352 if (object->frontBuffer != NULL) {
1353 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1354 } else {
1355 ERR("Failed to create the front buffer\n");
1356 goto error;
1360 * Create an opengl context for the display visual
1361 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1362 * use different properties after that point in time. FIXME: How to handle when requested format
1363 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1364 * it chooses is identical to the one already being used!
1365 **********************************/
1366 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1368 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1369 if(!object->context) {
1371 object->num_contexts = 1;
1373 ENTER_GL();
1374 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1375 LEAVE_GL();
1377 if (!object->context) {
1378 ERR("Failed to create a new context\n");
1379 hr = WINED3DERR_NOTAVAILABLE;
1380 goto error;
1381 } else {
1382 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1383 object->win_handle, object->context[0]->glCtx, object->win);
1386 /*********************
1387 * Windowed / Fullscreen
1388 *******************/
1391 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1392 * so we should really check to see if there is a fullscreen swapchain already
1393 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1394 **************************************/
1396 if (!pPresentationParameters->Windowed) {
1398 DEVMODEW devmode;
1399 HDC hdc;
1400 int bpp = 0;
1401 RECT clip_rc;
1403 /* Get info on the current display setup */
1404 hdc = GetDC(0);
1405 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1406 ReleaseDC(0, hdc);
1408 /* Change the display settings */
1409 memset(&devmode, 0, sizeof(DEVMODEW));
1410 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1411 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1412 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1413 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1414 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1415 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1417 /* For GetDisplayMode */
1418 This->ddraw_width = devmode.dmPelsWidth;
1419 This->ddraw_height = devmode.dmPelsHeight;
1420 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1422 IWineD3DDevice_SetFullscreen(iface, TRUE);
1424 /* And finally clip mouse to our screen */
1425 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1426 ClipCursor(&clip_rc);
1429 /*********************
1430 * Create the back, front and stencil buffers
1431 *******************/
1432 if(object->presentParms.BackBufferCount > 0) {
1433 int i;
1435 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1436 if(!object->backBuffer) {
1437 ERR("Out of memory\n");
1438 hr = E_OUTOFMEMORY;
1439 goto error;
1442 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1443 TRACE("calling rendertarget CB\n");
1444 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1445 parent,
1446 object->presentParms.BackBufferWidth,
1447 object->presentParms.BackBufferHeight,
1448 object->presentParms.BackBufferFormat,
1449 object->presentParms.MultiSampleType,
1450 object->presentParms.MultiSampleQuality,
1451 TRUE /* Lockable */,
1452 &object->backBuffer[i],
1453 NULL /* pShared (always null)*/);
1454 if(hr == WINED3D_OK && object->backBuffer[i]) {
1455 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1456 } else {
1457 ERR("Cannot create new back buffer\n");
1458 goto error;
1460 ENTER_GL();
1461 glDrawBuffer(GL_BACK);
1462 checkGLcall("glDrawBuffer(GL_BACK)");
1463 LEAVE_GL();
1465 } else {
1466 object->backBuffer = NULL;
1468 /* Single buffering - draw to front buffer */
1469 ENTER_GL();
1470 glDrawBuffer(GL_FRONT);
1471 checkGLcall("glDrawBuffer(GL_FRONT)");
1472 LEAVE_GL();
1475 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1476 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1477 TRACE("Creating depth stencil buffer\n");
1478 if (This->depthStencilBuffer == NULL ) {
1479 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1480 parent,
1481 object->presentParms.BackBufferWidth,
1482 object->presentParms.BackBufferHeight,
1483 object->presentParms.AutoDepthStencilFormat,
1484 object->presentParms.MultiSampleType,
1485 object->presentParms.MultiSampleQuality,
1486 FALSE /* FIXME: Discard */,
1487 &This->depthStencilBuffer,
1488 NULL /* pShared (always null)*/ );
1489 if (This->depthStencilBuffer != NULL)
1490 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1493 /** TODO: A check on width, height and multisample types
1494 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1495 ****************************/
1496 object->wantsDepthStencilBuffer = TRUE;
1497 } else {
1498 object->wantsDepthStencilBuffer = FALSE;
1501 TRACE("Created swapchain %p\n", object);
1502 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1503 return WINED3D_OK;
1505 error:
1506 if (object->backBuffer) {
1507 int i;
1508 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1509 if(object->backBuffer[i]) {
1510 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1511 IUnknown_Release(bufferParent); /* once for the get parent */
1512 if (IUnknown_Release(bufferParent) > 0) {
1513 FIXME("(%p) Something's still holding the back buffer\n",This);
1517 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1518 object->backBuffer = NULL;
1520 if(object->context) {
1521 DestroyContext(This, object->context[0]);
1523 if(object->frontBuffer) {
1524 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1525 IUnknown_Release(bufferParent); /* once for the get parent */
1526 if (IUnknown_Release(bufferParent) > 0) {
1527 FIXME("(%p) Something's still holding the front buffer\n",This);
1530 HeapFree(GetProcessHeap(), 0, object);
1531 return hr;
1534 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1535 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1537 TRACE("(%p)\n", This);
1539 return This->NumberOfSwapChains;
1542 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1546 if(iSwapChain < This->NumberOfSwapChains) {
1547 *pSwapChain = This->swapchains[iSwapChain];
1548 IWineD3DSwapChain_AddRef(*pSwapChain);
1549 TRACE("(%p) returning %p\n", This, *pSwapChain);
1550 return WINED3D_OK;
1551 } else {
1552 TRACE("Swapchain out of range\n");
1553 *pSwapChain = NULL;
1554 return WINED3DERR_INVALIDCALL;
1558 /*****
1559 * Vertex Declaration
1560 *****/
1561 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1562 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1564 IWineD3DVertexDeclarationImpl *object = NULL;
1565 HRESULT hr = WINED3D_OK;
1567 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1568 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1570 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1572 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1574 return hr;
1577 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1579 unsigned int idx, idx2;
1580 unsigned int offset;
1581 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1582 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1583 BOOL has_blend_idx = has_blend &&
1584 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1585 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1586 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1587 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1588 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1589 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1590 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1592 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1593 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1595 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1596 WINED3DVERTEXELEMENT *elements = NULL;
1598 unsigned int size;
1599 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1600 if (has_blend_idx) num_blends--;
1602 /* Compute declaration size */
1603 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1604 has_psize + has_diffuse + has_specular + num_textures + 1;
1606 /* convert the declaration */
1607 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1608 if (!elements)
1609 return 0;
1611 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1612 idx = 0;
1613 if (has_pos) {
1614 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1615 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1616 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1618 else {
1619 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1620 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1622 elements[idx].UsageIndex = 0;
1623 idx++;
1625 if (has_blend && (num_blends > 0)) {
1626 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1627 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1628 else
1629 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1630 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1631 elements[idx].UsageIndex = 0;
1632 idx++;
1634 if (has_blend_idx) {
1635 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1636 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1637 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1638 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1639 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1640 else
1641 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1642 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1643 elements[idx].UsageIndex = 0;
1644 idx++;
1646 if (has_normal) {
1647 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1648 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1649 elements[idx].UsageIndex = 0;
1650 idx++;
1652 if (has_psize) {
1653 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1654 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1655 elements[idx].UsageIndex = 0;
1656 idx++;
1658 if (has_diffuse) {
1659 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1660 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1661 elements[idx].UsageIndex = 0;
1662 idx++;
1664 if (has_specular) {
1665 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1666 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1667 elements[idx].UsageIndex = 1;
1668 idx++;
1670 for (idx2 = 0; idx2 < num_textures; idx2++) {
1671 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1672 switch (numcoords) {
1673 case WINED3DFVF_TEXTUREFORMAT1:
1674 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1675 break;
1676 case WINED3DFVF_TEXTUREFORMAT2:
1677 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1678 break;
1679 case WINED3DFVF_TEXTUREFORMAT3:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1681 break;
1682 case WINED3DFVF_TEXTUREFORMAT4:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1684 break;
1686 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1687 elements[idx].UsageIndex = idx2;
1688 idx++;
1691 /* Now compute offsets, and initialize the rest of the fields */
1692 for (idx = 0, offset = 0; idx < size-1; idx++) {
1693 elements[idx].Stream = 0;
1694 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1695 elements[idx].Offset = offset;
1696 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1699 *ppVertexElements = elements;
1700 return size;
1703 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1704 WINED3DVERTEXELEMENT* elements = NULL;
1705 size_t size;
1706 DWORD hr;
1708 size = ConvertFvfToDeclaration(Fvf, &elements);
1709 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1711 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1712 HeapFree(GetProcessHeap(), 0, elements);
1713 if (hr != S_OK) return hr;
1715 return WINED3D_OK;
1718 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1719 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1721 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1722 HRESULT hr = WINED3D_OK;
1723 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1724 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1726 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1728 if (vertex_declaration) {
1729 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1732 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1734 if (WINED3D_OK != hr) {
1735 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1736 IWineD3DVertexShader_Release(*ppVertexShader);
1737 return WINED3DERR_INVALIDCALL;
1740 return WINED3D_OK;
1743 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1745 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1746 HRESULT hr = WINED3D_OK;
1748 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1749 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1750 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1751 if (WINED3D_OK == hr) {
1752 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1753 } else {
1754 WARN("(%p) : Failed to create pixel shader\n", This);
1757 return hr;
1760 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1762 IWineD3DPaletteImpl *object;
1763 HRESULT hr;
1764 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1766 /* Create the new object */
1767 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1768 if(!object) {
1769 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1770 return E_OUTOFMEMORY;
1773 object->lpVtbl = &IWineD3DPalette_Vtbl;
1774 object->ref = 1;
1775 object->Flags = Flags;
1776 object->parent = Parent;
1777 object->wineD3DDevice = This;
1778 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1780 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1782 if(!object->hpal) {
1783 HeapFree( GetProcessHeap(), 0, object);
1784 return E_OUTOFMEMORY;
1787 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1788 if(FAILED(hr)) {
1789 IWineD3DPalette_Release((IWineD3DPalette *) object);
1790 return hr;
1793 *Palette = (IWineD3DPalette *) object;
1795 return WINED3D_OK;
1798 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1800 IWineD3DSwapChainImpl *swapchain;
1801 DWORD state;
1803 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1804 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1806 /* TODO: Test if OpenGL is compiled in and loaded */
1808 /* Initialize the texture unit mapping to a 1:1 mapping */
1809 for(state = 0; state < MAX_SAMPLERS; state++) {
1810 This->texUnitMap[state] = state;
1812 This->oneToOneTexUnitMap = TRUE;
1814 /* Setup the implicit swapchain */
1815 TRACE("Creating implicit swapchain\n");
1816 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1817 WARN("Failed to create implicit swapchain\n");
1818 return WINED3DERR_INVALIDCALL;
1821 This->NumberOfSwapChains = 1;
1822 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1823 if(!This->swapchains) {
1824 ERR("Out of memory!\n");
1825 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1826 return E_OUTOFMEMORY;
1828 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1830 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1832 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1833 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1834 This->render_targets[0] = swapchain->backBuffer[0];
1835 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1837 else {
1838 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1839 This->render_targets[0] = swapchain->frontBuffer;
1840 This->lastActiveRenderTarget = swapchain->frontBuffer;
1842 IWineD3DSurface_AddRef(This->render_targets[0]);
1843 This->activeContext = swapchain->context[0];
1845 /* Depth Stencil support */
1846 This->stencilBufferTarget = This->depthStencilBuffer;
1847 if (NULL != This->stencilBufferTarget) {
1848 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1851 /* Set up some starting GL setup */
1852 ENTER_GL();
1854 * Initialize openGL extension related variables
1855 * with Default values
1858 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1859 /* Setup all the devices defaults */
1860 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1861 #if 0
1862 IWineD3DImpl_CheckGraphicsMemory();
1863 #endif
1865 { /* Set a default viewport */
1866 WINED3DVIEWPORT vp;
1867 vp.X = 0;
1868 vp.Y = 0;
1869 vp.Width = pPresentationParameters->BackBufferWidth;
1870 vp.Height = pPresentationParameters->BackBufferHeight;
1871 vp.MinZ = 0.0f;
1872 vp.MaxZ = 1.0f;
1873 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1876 /* Initialize the current view state */
1877 This->view_ident = 1;
1878 This->contexts[0]->last_was_rhw = 0;
1879 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1880 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1882 switch(wined3d_settings.offscreen_rendering_mode) {
1883 case ORM_FBO:
1884 case ORM_PBUFFER:
1885 This->offscreenBuffer = GL_BACK;
1886 break;
1888 case ORM_BACKBUFFER:
1890 if(GL_LIMITS(aux_buffers) > 0) {
1891 TRACE("Using auxilliary buffer for offscreen rendering\n");
1892 This->offscreenBuffer = GL_AUX0;
1893 } else {
1894 TRACE("Using back buffer for offscreen rendering\n");
1895 This->offscreenBuffer = GL_BACK;
1900 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1901 LEAVE_GL();
1903 /* Clear the screen */
1904 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1905 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1906 0x00, 1.0, 0);
1908 This->d3d_initialized = TRUE;
1909 return WINED3D_OK;
1912 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1914 int sampler;
1915 uint i;
1916 TRACE("(%p)\n", This);
1918 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1920 ENTER_GL();
1921 /* I don't think that the interface guarants that the device is destroyed from the same thread
1922 * it was created. Thus make sure a context is active for the glDelete* calls
1924 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1925 LEAVE_GL();
1927 /* Delete the pbuffer context if there is any */
1928 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1930 /* Delete the mouse cursor texture */
1931 if(This->cursorTexture) {
1932 ENTER_GL();
1933 glDeleteTextures(1, &This->cursorTexture);
1934 LEAVE_GL();
1935 This->cursorTexture = 0;
1938 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1939 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1942 /* Release the buffers (with sanity checks)*/
1943 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1944 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1945 if(This->depthStencilBuffer != This->stencilBufferTarget)
1946 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1948 This->stencilBufferTarget = NULL;
1950 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1951 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1952 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1954 TRACE("Setting rendertarget to NULL\n");
1955 This->render_targets[0] = NULL;
1957 if (This->depthStencilBuffer) {
1958 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1959 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1961 This->depthStencilBuffer = NULL;
1964 for(i=0; i < This->NumberOfSwapChains; i++) {
1965 TRACE("Releasing the implicit swapchain %d\n", i);
1966 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1967 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1971 HeapFree(GetProcessHeap(), 0, This->swapchains);
1972 This->swapchains = NULL;
1973 This->NumberOfSwapChains = 0;
1975 This->d3d_initialized = FALSE;
1976 return WINED3D_OK;
1979 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1981 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1983 /* Setup the window for fullscreen mode */
1984 if(fullscreen && !This->ddraw_fullscreen) {
1985 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1986 } else if(!fullscreen && This->ddraw_fullscreen) {
1987 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1990 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1991 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1992 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1993 * separately.
1995 This->ddraw_fullscreen = fullscreen;
1998 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1999 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2000 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2002 * There is no way to deactivate thread safety once it is enabled
2004 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 FIXME("No thread safety in wined3d yet\n");
2008 /*For now just store the flag(needed in case of ddraw) */
2009 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2011 return;
2014 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2015 DEVMODEW devmode;
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2017 LONG ret;
2018 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2019 RECT clip_rc;
2021 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2023 /* Resize the screen even without a window:
2024 * The app could have unset it with SetCooperativeLevel, but not called
2025 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2026 * but we don't have any hwnd
2029 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2030 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2031 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2032 devmode.dmPelsWidth = pMode->Width;
2033 devmode.dmPelsHeight = pMode->Height;
2035 devmode.dmDisplayFrequency = pMode->RefreshRate;
2036 if (pMode->RefreshRate != 0) {
2037 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2040 /* Only change the mode if necessary */
2041 if( (This->ddraw_width == pMode->Width) &&
2042 (This->ddraw_height == pMode->Height) &&
2043 (This->ddraw_format == pMode->Format) &&
2044 (pMode->RefreshRate == 0) ) {
2045 return WINED3D_OK;
2048 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2049 if (ret != DISP_CHANGE_SUCCESSFUL) {
2050 if(devmode.dmDisplayFrequency != 0) {
2051 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2052 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2053 devmode.dmDisplayFrequency = 0;
2054 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2056 if(ret != DISP_CHANGE_SUCCESSFUL) {
2057 return WINED3DERR_NOTAVAILABLE;
2061 /* Store the new values */
2062 This->ddraw_width = pMode->Width;
2063 This->ddraw_height = pMode->Height;
2064 This->ddraw_format = pMode->Format;
2066 /* Only do this with a window of course */
2067 if(This->ddraw_window)
2068 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2070 /* And finally clip mouse to our screen */
2071 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2072 ClipCursor(&clip_rc);
2074 return WINED3D_OK;
2077 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2079 *ppD3D= This->wineD3D;
2080 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2081 IWineD3D_AddRef(*ppD3D);
2082 return WINED3D_OK;
2085 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2086 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2087 * into the video ram as possible and seeing how many fit
2088 * you can also get the correct initial value from nvidia and ATI's driver via X
2089 * texture memory is video memory + AGP memory
2090 *******************/
2091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2092 static BOOL showfixmes = TRUE;
2093 if (showfixmes) {
2094 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2095 (wined3d_settings.emulated_textureram/(1024*1024)),
2096 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2097 showfixmes = FALSE;
2099 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2100 (wined3d_settings.emulated_textureram/(1024*1024)),
2101 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2102 /* return simulated texture memory left */
2103 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2108 /*****
2109 * Get / Set FVF
2110 *****/
2111 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2114 /* Update the current state block */
2115 This->updateStateBlock->changed.fvf = TRUE;
2116 This->updateStateBlock->set.fvf = TRUE;
2118 if(This->updateStateBlock->fvf == fvf) {
2119 TRACE("Application is setting the old fvf over, nothing to do\n");
2120 return WINED3D_OK;
2123 This->updateStateBlock->fvf = fvf;
2124 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2126 return WINED3D_OK;
2130 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2132 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2133 *pfvf = This->stateBlock->fvf;
2134 return WINED3D_OK;
2137 /*****
2138 * Get / Set Stream Source
2139 *****/
2140 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2142 IWineD3DVertexBuffer *oldSrc;
2144 if (StreamNumber >= MAX_STREAMS) {
2145 WARN("Stream out of range %d\n", StreamNumber);
2146 return WINED3DERR_INVALIDCALL;
2149 oldSrc = This->stateBlock->streamSource[StreamNumber];
2150 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2152 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2153 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2155 if(oldSrc == pStreamData &&
2156 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2157 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2158 TRACE("Application is setting the old values over, nothing to do\n");
2159 return WINED3D_OK;
2162 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2163 if (pStreamData) {
2164 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2165 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2168 /* Handle recording of state blocks */
2169 if (This->isRecordingState) {
2170 TRACE("Recording... not performing anything\n");
2171 return WINED3D_OK;
2174 /* Need to do a getParent and pass the reffs up */
2175 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2176 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2177 so for now, just count internally */
2178 if (pStreamData != NULL) {
2179 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2180 InterlockedIncrement(&vbImpl->bindCount);
2182 if (oldSrc != NULL) {
2183 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2188 return WINED3D_OK;
2191 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2194 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2195 This->stateBlock->streamSource[StreamNumber],
2196 This->stateBlock->streamOffset[StreamNumber],
2197 This->stateBlock->streamStride[StreamNumber]);
2199 if (StreamNumber >= MAX_STREAMS) {
2200 WARN("Stream out of range %d\n", StreamNumber);
2201 return WINED3DERR_INVALIDCALL;
2203 *pStream = This->stateBlock->streamSource[StreamNumber];
2204 *pStride = This->stateBlock->streamStride[StreamNumber];
2205 if (pOffset) {
2206 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2209 if (*pStream != NULL) {
2210 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2212 return WINED3D_OK;
2215 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2217 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2218 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2220 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2221 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2223 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2224 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2225 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2227 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2228 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2232 return WINED3D_OK;
2235 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2238 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2239 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2241 TRACE("(%p) : returning %d\n", This, *Divider);
2243 return WINED3D_OK;
2246 /*****
2247 * Get / Set & Multiply Transform
2248 *****/
2249 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2252 /* Most of this routine, comments included copied from ddraw tree initially: */
2253 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2255 /* Handle recording of state blocks */
2256 if (This->isRecordingState) {
2257 TRACE("Recording... not performing anything\n");
2258 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2259 This->updateStateBlock->set.transform[d3dts] = TRUE;
2260 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2261 return WINED3D_OK;
2265 * If the new matrix is the same as the current one,
2266 * we cut off any further processing. this seems to be a reasonable
2267 * optimization because as was noticed, some apps (warcraft3 for example)
2268 * tend towards setting the same matrix repeatedly for some reason.
2270 * From here on we assume that the new matrix is different, wherever it matters.
2272 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2273 TRACE("The app is setting the same matrix over again\n");
2274 return WINED3D_OK;
2275 } else {
2276 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2280 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2281 where ViewMat = Camera space, WorldMat = world space.
2283 In OpenGL, camera and world space is combined into GL_MODELVIEW
2284 matrix. The Projection matrix stay projection matrix.
2287 /* Capture the times we can just ignore the change for now */
2288 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2289 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2290 /* Handled by the state manager */
2293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2294 return WINED3D_OK;
2297 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2299 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2300 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2301 return WINED3D_OK;
2304 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2305 WINED3DMATRIX *mat = NULL;
2306 WINED3DMATRIX temp;
2308 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2309 * below means it will be recorded in a state block change, but it
2310 * works regardless where it is recorded.
2311 * If this is found to be wrong, change to StateBlock.
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2314 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2316 if (State < HIGHEST_TRANSFORMSTATE)
2318 mat = &This->updateStateBlock->transforms[State];
2319 } else {
2320 FIXME("Unhandled transform state!!\n");
2323 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2325 /* Apply change via set transform - will reapply to eg. lights this way */
2326 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2329 /*****
2330 * Get / Set Light
2331 *****/
2332 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2333 you can reference any indexes you want as long as that number max are enabled at any
2334 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2335 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2336 but when recording, just build a chain pretty much of commands to be replayed. */
2338 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2339 float rho;
2340 PLIGHTINFOEL *object = NULL;
2341 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2342 struct list *e;
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2347 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2348 * the gl driver.
2350 if(!pLight) {
2351 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2352 return WINED3DERR_INVALIDCALL;
2355 switch(pLight->Type) {
2356 case WINED3DLIGHT_POINT:
2357 case WINED3DLIGHT_SPOT:
2358 case WINED3DLIGHT_PARALLELPOINT:
2359 case WINED3DLIGHT_GLSPOT:
2360 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2361 * most wanted
2363 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2364 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2365 return WINED3DERR_INVALIDCALL;
2367 break;
2369 case WINED3DLIGHT_DIRECTIONAL:
2370 /* Ignores attenuation */
2371 break;
2373 default:
2374 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2375 return WINED3DERR_INVALIDCALL;
2378 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2379 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2380 if(object->OriginalIndex == Index) break;
2381 object = NULL;
2384 if(!object) {
2385 TRACE("Adding new light\n");
2386 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2387 if(!object) {
2388 ERR("Out of memory error when allocating a light\n");
2389 return E_OUTOFMEMORY;
2391 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2392 object->glIndex = -1;
2393 object->OriginalIndex = Index;
2394 object->changed = TRUE;
2397 /* Initialize the object */
2398 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,
2399 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2400 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2401 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2402 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2403 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2404 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2406 /* Save away the information */
2407 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2409 switch (pLight->Type) {
2410 case WINED3DLIGHT_POINT:
2411 /* Position */
2412 object->lightPosn[0] = pLight->Position.x;
2413 object->lightPosn[1] = pLight->Position.y;
2414 object->lightPosn[2] = pLight->Position.z;
2415 object->lightPosn[3] = 1.0f;
2416 object->cutoff = 180.0f;
2417 /* FIXME: Range */
2418 break;
2420 case WINED3DLIGHT_DIRECTIONAL:
2421 /* Direction */
2422 object->lightPosn[0] = -pLight->Direction.x;
2423 object->lightPosn[1] = -pLight->Direction.y;
2424 object->lightPosn[2] = -pLight->Direction.z;
2425 object->lightPosn[3] = 0.0;
2426 object->exponent = 0.0f;
2427 object->cutoff = 180.0f;
2428 break;
2430 case WINED3DLIGHT_SPOT:
2431 /* Position */
2432 object->lightPosn[0] = pLight->Position.x;
2433 object->lightPosn[1] = pLight->Position.y;
2434 object->lightPosn[2] = pLight->Position.z;
2435 object->lightPosn[3] = 1.0;
2437 /* Direction */
2438 object->lightDirn[0] = pLight->Direction.x;
2439 object->lightDirn[1] = pLight->Direction.y;
2440 object->lightDirn[2] = pLight->Direction.z;
2441 object->lightDirn[3] = 1.0;
2444 * opengl-ish and d3d-ish spot lights use too different models for the
2445 * light "intensity" as a function of the angle towards the main light direction,
2446 * so we only can approximate very roughly.
2447 * however spot lights are rather rarely used in games (if ever used at all).
2448 * furthermore if still used, probably nobody pays attention to such details.
2450 if (pLight->Falloff == 0) {
2451 rho = 6.28f;
2452 } else {
2453 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2455 if (rho < 0.0001) rho = 0.0001f;
2456 object->exponent = -0.3/log(cos(rho/2));
2457 if (object->exponent > 128.0) {
2458 object->exponent = 128.0;
2460 object->cutoff = pLight->Phi*90/M_PI;
2462 /* FIXME: Range */
2463 break;
2465 default:
2466 FIXME("Unrecognized light type %d\n", pLight->Type);
2469 /* Update the live definitions if the light is currently assigned a glIndex */
2470 if (object->glIndex != -1 && !This->isRecordingState) {
2471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2473 return WINED3D_OK;
2476 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2477 PLIGHTINFOEL *lightInfo = NULL;
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2480 struct list *e;
2481 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2483 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2484 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2485 if(lightInfo->OriginalIndex == Index) break;
2486 lightInfo = NULL;
2489 if (lightInfo == NULL) {
2490 TRACE("Light information requested but light not defined\n");
2491 return WINED3DERR_INVALIDCALL;
2494 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2495 return WINED3D_OK;
2498 /*****
2499 * Get / Set Light Enable
2500 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2501 *****/
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2503 PLIGHTINFOEL *lightInfo = NULL;
2504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2505 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2506 struct list *e;
2507 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2509 /* Tests show true = 128...not clear why */
2510 Enable = Enable? 128: 0;
2512 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2513 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2514 if(lightInfo->OriginalIndex == Index) break;
2515 lightInfo = NULL;
2517 TRACE("Found light: %p\n", lightInfo);
2519 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2520 if (lightInfo == NULL) {
2522 TRACE("Light enabled requested but light not defined, so defining one!\n");
2523 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2525 /* Search for it again! Should be fairly quick as near head of list */
2526 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2527 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2528 if(lightInfo->OriginalIndex == Index) break;
2529 lightInfo = NULL;
2531 if (lightInfo == NULL) {
2532 FIXME("Adding default lights has failed dismally\n");
2533 return WINED3DERR_INVALIDCALL;
2537 lightInfo->enabledChanged = TRUE;
2538 if(!Enable) {
2539 if(lightInfo->glIndex != -1) {
2540 if(!This->isRecordingState) {
2541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2544 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2545 lightInfo->glIndex = -1;
2546 } else {
2547 TRACE("Light already disabled, nothing to do\n");
2549 } else {
2550 if (lightInfo->glIndex != -1) {
2551 /* nop */
2552 TRACE("Nothing to do as light was enabled\n");
2553 } else {
2554 int i;
2555 /* Find a free gl light */
2556 for(i = 0; i < This->maxConcurrentLights; i++) {
2557 if(This->stateBlock->activeLights[i] == NULL) {
2558 This->stateBlock->activeLights[i] = lightInfo;
2559 lightInfo->glIndex = i;
2560 break;
2563 if(lightInfo->glIndex == -1) {
2564 ERR("Too many concurrently active lights\n");
2565 return WINED3DERR_INVALIDCALL;
2568 /* i == lightInfo->glIndex */
2569 if(!This->isRecordingState) {
2570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2575 return WINED3D_OK;
2578 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2580 PLIGHTINFOEL *lightInfo = NULL;
2581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2582 struct list *e;
2583 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2584 TRACE("(%p) : for idx(%d)\n", This, Index);
2586 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2587 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2588 if(lightInfo->OriginalIndex == Index) break;
2589 lightInfo = NULL;
2592 if (lightInfo == NULL) {
2593 TRACE("Light enabled state requested but light not defined\n");
2594 return WINED3DERR_INVALIDCALL;
2596 /* true is 128 according to SetLightEnable */
2597 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2598 return WINED3D_OK;
2601 /*****
2602 * Get / Set Clip Planes
2603 *****/
2604 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2606 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2608 /* Validate Index */
2609 if (Index >= GL_LIMITS(clipplanes)) {
2610 TRACE("Application has requested clipplane this device doesn't support\n");
2611 return WINED3DERR_INVALIDCALL;
2614 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2615 This->updateStateBlock->set.clipplane[Index] = TRUE;
2617 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2618 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2619 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2620 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2621 TRACE("Application is setting old values over, nothing to do\n");
2622 return WINED3D_OK;
2625 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2626 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2627 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2628 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2630 /* Handle recording of state blocks */
2631 if (This->isRecordingState) {
2632 TRACE("Recording... not performing anything\n");
2633 return WINED3D_OK;
2636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2638 return WINED3D_OK;
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 TRACE("(%p) : for idx %d\n", This, Index);
2645 /* Validate Index */
2646 if (Index >= GL_LIMITS(clipplanes)) {
2647 TRACE("Application has requested clipplane this device doesn't support\n");
2648 return WINED3DERR_INVALIDCALL;
2651 pPlane[0] = This->stateBlock->clipplane[Index][0];
2652 pPlane[1] = This->stateBlock->clipplane[Index][1];
2653 pPlane[2] = This->stateBlock->clipplane[Index][2];
2654 pPlane[3] = This->stateBlock->clipplane[Index][3];
2655 return WINED3D_OK;
2658 /*****
2659 * Get / Set Clip Plane Status
2660 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2661 *****/
2662 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 FIXME("(%p) : stub\n", This);
2665 if (NULL == pClipStatus) {
2666 return WINED3DERR_INVALIDCALL;
2668 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2669 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2670 return WINED3D_OK;
2673 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 FIXME("(%p) : stub\n", This);
2676 if (NULL == pClipStatus) {
2677 return WINED3DERR_INVALIDCALL;
2679 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2680 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2681 return WINED3D_OK;
2684 /*****
2685 * Get / Set Material
2686 *****/
2687 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2690 This->updateStateBlock->changed.material = TRUE;
2691 This->updateStateBlock->set.material = TRUE;
2692 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2694 /* Handle recording of state blocks */
2695 if (This->isRecordingState) {
2696 TRACE("Recording... not performing anything\n");
2697 return WINED3D_OK;
2700 ENTER_GL();
2701 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2702 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2703 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2704 pMaterial->Ambient.b, pMaterial->Ambient.a);
2705 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2706 pMaterial->Specular.b, pMaterial->Specular.a);
2707 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2708 pMaterial->Emissive.b, pMaterial->Emissive.a);
2709 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2711 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2712 checkGLcall("glMaterialfv(GL_AMBIENT)");
2713 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2714 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2716 /* Only change material color if specular is enabled, otherwise it is set to black */
2717 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2718 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2719 checkGLcall("glMaterialfv(GL_SPECULAR");
2720 } else {
2721 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2722 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2723 checkGLcall("glMaterialfv(GL_SPECULAR");
2725 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2726 checkGLcall("glMaterialfv(GL_EMISSION)");
2727 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2728 checkGLcall("glMaterialf(GL_SHININESS");
2730 LEAVE_GL();
2731 return WINED3D_OK;
2734 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2737 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2738 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2739 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2740 pMaterial->Ambient.b, pMaterial->Ambient.a);
2741 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2742 pMaterial->Specular.b, pMaterial->Specular.a);
2743 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2744 pMaterial->Emissive.b, pMaterial->Emissive.a);
2745 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2747 return WINED3D_OK;
2750 /*****
2751 * Get / Set Indices
2752 *****/
2753 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2754 UINT BaseVertexIndex) {
2755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2756 IWineD3DIndexBuffer *oldIdxs;
2757 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2759 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2760 oldIdxs = This->updateStateBlock->pIndexData;
2762 This->updateStateBlock->changed.indices = TRUE;
2763 This->updateStateBlock->set.indices = TRUE;
2764 This->updateStateBlock->pIndexData = pIndexData;
2765 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2767 /* Handle recording of state blocks */
2768 if (This->isRecordingState) {
2769 TRACE("Recording... not performing anything\n");
2770 return WINED3D_OK;
2773 /* The base vertex index affects the stream sources, while
2774 * The index buffer is a seperate index buffer state
2776 if(BaseVertexIndex != oldBaseIndex) {
2777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2779 if(oldIdxs != pIndexData) {
2780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2782 return WINED3D_OK;
2785 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2788 *ppIndexData = This->stateBlock->pIndexData;
2790 /* up ref count on ppindexdata */
2791 if (*ppIndexData) {
2792 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2793 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2794 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2795 }else{
2796 TRACE("(%p) No index data set\n", This);
2798 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2800 return WINED3D_OK;
2803 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2804 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 TRACE("(%p)->(%d)\n", This, BaseIndex);
2808 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2809 TRACE("Application is setting the old value over, nothing to do\n");
2810 return WINED3D_OK;
2813 This->updateStateBlock->baseVertexIndex = BaseIndex;
2815 if (This->isRecordingState) {
2816 TRACE("Recording... not performing anything\n");
2817 return WINED3D_OK;
2819 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2820 return WINED3D_OK;
2823 /*****
2824 * Get / Set Viewports
2825 *****/
2826 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2829 TRACE("(%p)\n", This);
2830 This->updateStateBlock->changed.viewport = TRUE;
2831 This->updateStateBlock->set.viewport = TRUE;
2832 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2834 /* Handle recording of state blocks */
2835 if (This->isRecordingState) {
2836 TRACE("Recording... not performing anything\n");
2837 return WINED3D_OK;
2840 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2841 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2844 return WINED3D_OK;
2848 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850 TRACE("(%p)\n", This);
2851 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2852 return WINED3D_OK;
2855 /*****
2856 * Get / Set Render States
2857 * TODO: Verify against dx9 definitions
2858 *****/
2859 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2862 DWORD oldValue = This->stateBlock->renderState[State];
2864 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2866 This->updateStateBlock->changed.renderState[State] = TRUE;
2867 This->updateStateBlock->set.renderState[State] = TRUE;
2868 This->updateStateBlock->renderState[State] = Value;
2870 /* Handle recording of state blocks */
2871 if (This->isRecordingState) {
2872 TRACE("Recording... not performing anything\n");
2873 return WINED3D_OK;
2876 /* Compared here and not before the assignment to allow proper stateblock recording */
2877 if(Value == oldValue) {
2878 TRACE("Application is setting the old value over, nothing to do\n");
2879 } else {
2880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2883 return WINED3D_OK;
2886 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2889 *pValue = This->stateBlock->renderState[State];
2890 return WINED3D_OK;
2893 /*****
2894 * Get / Set Sampler States
2895 * TODO: Verify against dx9 definitions
2896 *****/
2898 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2903 * SetSampler is designed to allow for more than the standard up to 8 textures
2904 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2905 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2907 * http://developer.nvidia.com/object/General_FAQ.html#t6
2909 * There are two new settings for GForce
2910 * the sampler one:
2911 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2912 * and the texture one:
2913 * GL_MAX_TEXTURE_COORDS_ARB.
2914 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2915 ******************/
2917 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2918 debug_d3dsamplerstate(Type), Type, Value);
2919 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2920 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2921 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2923 /* Handle recording of state blocks */
2924 if (This->isRecordingState) {
2925 TRACE("Recording... not performing anything\n");
2926 return WINED3D_OK;
2929 if(oldValue == Value) {
2930 TRACE("Application is setting the old value over, nothing to do\n");
2931 return WINED3D_OK;
2934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2936 return WINED3D_OK;
2939 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2941 *Value = This->stateBlock->samplerState[Sampler][Type];
2942 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2944 return WINED3D_OK;
2947 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 This->updateStateBlock->set.scissorRect = TRUE;
2951 This->updateStateBlock->changed.scissorRect = TRUE;
2952 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2953 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2954 return WINED3D_OK;
2956 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2958 if(This->isRecordingState) {
2959 TRACE("Recording... not performing anything\n");
2960 return WINED3D_OK;
2963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2965 return WINED3D_OK;
2968 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2971 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2972 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2973 return WINED3D_OK;
2976 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2978 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2980 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2982 This->updateStateBlock->vertexDecl = pDecl;
2983 This->updateStateBlock->changed.vertexDecl = TRUE;
2984 This->updateStateBlock->set.vertexDecl = TRUE;
2986 if (This->isRecordingState) {
2987 TRACE("Recording... not performing anything\n");
2988 return WINED3D_OK;
2989 } else if(pDecl == oldDecl) {
2990 /* Checked after the assignment to allow proper stateblock recording */
2991 TRACE("Application is setting the old declaration over, nothing to do\n");
2992 return WINED3D_OK;
2995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2996 return WINED3D_OK;
2999 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3002 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3004 *ppDecl = This->stateBlock->vertexDecl;
3005 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3006 return WINED3D_OK;
3009 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3013 This->updateStateBlock->vertexShader = pShader;
3014 This->updateStateBlock->changed.vertexShader = TRUE;
3015 This->updateStateBlock->set.vertexShader = TRUE;
3017 if (This->isRecordingState) {
3018 TRACE("Recording... not performing anything\n");
3019 return WINED3D_OK;
3020 } else if(oldShader == pShader) {
3021 /* Checked here to allow proper stateblock recording */
3022 TRACE("App is setting the old shader over, nothing to do\n");
3023 return WINED3D_OK;
3026 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3030 return WINED3D_OK;
3033 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 if (NULL == ppShader) {
3037 return WINED3DERR_INVALIDCALL;
3039 *ppShader = This->stateBlock->vertexShader;
3040 if( NULL != *ppShader)
3041 IWineD3DVertexShader_AddRef(*ppShader);
3043 TRACE("(%p) : returning %p\n", This, *ppShader);
3044 return WINED3D_OK;
3047 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3048 IWineD3DDevice *iface,
3049 UINT start,
3050 CONST BOOL *srcData,
3051 UINT count) {
3053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3054 int i, cnt = min(count, MAX_CONST_B - start);
3056 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3057 iface, srcData, start, count);
3059 if (srcData == NULL || cnt < 0)
3060 return WINED3DERR_INVALIDCALL;
3062 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3063 for (i = 0; i < cnt; i++)
3064 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3066 for (i = start; i < cnt + start; ++i) {
3067 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3068 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3077 IWineD3DDevice *iface,
3078 UINT start,
3079 BOOL *dstData,
3080 UINT count) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 int cnt = min(count, MAX_CONST_B - start);
3085 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3086 iface, dstData, start, count);
3088 if (dstData == NULL || cnt < 0)
3089 return WINED3DERR_INVALIDCALL;
3091 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3092 return WINED3D_OK;
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3096 IWineD3DDevice *iface,
3097 UINT start,
3098 CONST int *srcData,
3099 UINT count) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3102 int i, cnt = min(count, MAX_CONST_I - start);
3104 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3105 iface, srcData, start, count);
3107 if (srcData == NULL || cnt < 0)
3108 return WINED3DERR_INVALIDCALL;
3110 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3111 for (i = 0; i < cnt; i++)
3112 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3113 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3115 for (i = start; i < cnt + start; ++i) {
3116 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3117 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3122 return WINED3D_OK;
3125 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3126 IWineD3DDevice *iface,
3127 UINT start,
3128 int *dstData,
3129 UINT count) {
3131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 int cnt = min(count, MAX_CONST_I - start);
3134 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3135 iface, dstData, start, count);
3137 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3138 return WINED3DERR_INVALIDCALL;
3140 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3141 return WINED3D_OK;
3144 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3145 IWineD3DDevice *iface,
3146 UINT start,
3147 CONST float *srcData,
3148 UINT count) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 int i;
3153 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3154 iface, srcData, start, count);
3156 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3157 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3158 return WINED3DERR_INVALIDCALL;
3160 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3161 if(TRACE_ON(d3d)) {
3162 for (i = 0; i < count; i++)
3163 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3164 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3167 for (i = start; i < count + start; ++i) {
3168 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3169 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3170 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3171 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3172 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3174 ptr->idx[ptr->count++] = i;
3175 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3177 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3180 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3182 return WINED3D_OK;
3185 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3186 IWineD3DDevice *iface,
3187 UINT start,
3188 float *dstData,
3189 UINT count) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3194 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3195 iface, dstData, start, count);
3197 if (dstData == NULL || cnt < 0)
3198 return WINED3DERR_INVALIDCALL;
3200 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3201 return WINED3D_OK;
3204 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3205 DWORD i;
3206 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3211 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3212 DWORD i, tex;
3213 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3214 * it is never called.
3216 * Rules are:
3217 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3218 * that would be really messy and require shader recompilation
3219 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3220 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3221 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3222 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3224 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3225 if(This->oneToOneTexUnitMap) {
3226 TRACE("Not touching 1:1 map\n");
3227 return;
3229 TRACE("Restoring 1:1 texture unit mapping\n");
3230 /* Restore a 1:1 mapping */
3231 for(i = 0; i < MAX_SAMPLERS; i++) {
3232 if(This->texUnitMap[i] != i) {
3233 This->texUnitMap[i] = i;
3234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3235 markTextureStagesDirty(This, i);
3238 This->oneToOneTexUnitMap = TRUE;
3239 return;
3240 } else {
3241 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3242 * First, see if we can succeed at all
3244 tex = 0;
3245 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3246 if(This->stateBlock->textures[i] == NULL) tex++;
3249 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3250 FIXME("Too many bound textures to support the combiner settings\n");
3251 return;
3254 /* Now work out the mapping */
3255 tex = 0;
3256 This->oneToOneTexUnitMap = FALSE;
3257 WARN("Non 1:1 mapping UNTESTED!\n");
3258 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3259 /* Skip NULL textures */
3260 if (!This->stateBlock->textures[i]) {
3261 /* Map to -1, so the check below doesn't fail if a non-NULL
3262 * texture is set on this stage */
3263 TRACE("Mapping texture stage %d to -1\n", i);
3264 This->texUnitMap[i] = -1;
3266 continue;
3269 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3270 if(This->texUnitMap[i] != tex) {
3271 This->texUnitMap[i] = tex;
3272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3273 markTextureStagesDirty(This, i);
3276 ++tex;
3281 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3284 This->updateStateBlock->pixelShader = pShader;
3285 This->updateStateBlock->changed.pixelShader = TRUE;
3286 This->updateStateBlock->set.pixelShader = TRUE;
3288 /* Handle recording of state blocks */
3289 if (This->isRecordingState) {
3290 TRACE("Recording... not performing anything\n");
3293 if (This->isRecordingState) {
3294 TRACE("Recording... not performing anything\n");
3295 return WINED3D_OK;
3298 if(pShader == oldShader) {
3299 TRACE("App is setting the old pixel shader over, nothing to do\n");
3300 return WINED3D_OK;
3303 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3304 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3306 /* Rebuild the texture unit mapping if nvrc's are supported */
3307 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3308 IWineD3DDeviceImpl_FindTexUnitMap(This);
3311 return WINED3D_OK;
3314 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3317 if (NULL == ppShader) {
3318 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3319 return WINED3DERR_INVALIDCALL;
3322 *ppShader = This->stateBlock->pixelShader;
3323 if (NULL != *ppShader) {
3324 IWineD3DPixelShader_AddRef(*ppShader);
3326 TRACE("(%p) : returning %p\n", This, *ppShader);
3327 return WINED3D_OK;
3330 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3331 IWineD3DDevice *iface,
3332 UINT start,
3333 CONST BOOL *srcData,
3334 UINT count) {
3336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3337 int i, cnt = min(count, MAX_CONST_B - start);
3339 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3340 iface, srcData, start, count);
3342 if (srcData == NULL || cnt < 0)
3343 return WINED3DERR_INVALIDCALL;
3345 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3346 for (i = 0; i < cnt; i++)
3347 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3349 for (i = start; i < cnt + start; ++i) {
3350 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3351 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3356 return WINED3D_OK;
3359 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3360 IWineD3DDevice *iface,
3361 UINT start,
3362 BOOL *dstData,
3363 UINT count) {
3365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3366 int cnt = min(count, MAX_CONST_B - start);
3368 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3369 iface, dstData, start, count);
3371 if (dstData == NULL || cnt < 0)
3372 return WINED3DERR_INVALIDCALL;
3374 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3375 return WINED3D_OK;
3378 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3379 IWineD3DDevice *iface,
3380 UINT start,
3381 CONST int *srcData,
3382 UINT count) {
3384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 int i, cnt = min(count, MAX_CONST_I - start);
3387 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3388 iface, srcData, start, count);
3390 if (srcData == NULL || cnt < 0)
3391 return WINED3DERR_INVALIDCALL;
3393 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3394 for (i = 0; i < cnt; i++)
3395 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3396 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3398 for (i = start; i < cnt + start; ++i) {
3399 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3400 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3403 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3405 return WINED3D_OK;
3408 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3409 IWineD3DDevice *iface,
3410 UINT start,
3411 int *dstData,
3412 UINT count) {
3414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3415 int cnt = min(count, MAX_CONST_I - start);
3417 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3418 iface, dstData, start, count);
3420 if (dstData == NULL || cnt < 0)
3421 return WINED3DERR_INVALIDCALL;
3423 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3424 return WINED3D_OK;
3427 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3428 IWineD3DDevice *iface,
3429 UINT start,
3430 CONST float *srcData,
3431 UINT count) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3434 int i;
3436 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3437 iface, srcData, start, count);
3439 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3440 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3441 return WINED3DERR_INVALIDCALL;
3443 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3444 if(TRACE_ON(d3d)) {
3445 for (i = 0; i < count; i++)
3446 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3447 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3450 for (i = start; i < count + start; ++i) {
3451 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3452 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3453 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3454 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3455 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3457 ptr->idx[ptr->count++] = i;
3458 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3460 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3465 return WINED3D_OK;
3468 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3469 IWineD3DDevice *iface,
3470 UINT start,
3471 float *dstData,
3472 UINT count) {
3474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3475 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3477 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3478 iface, dstData, start, count);
3480 if (dstData == NULL || cnt < 0)
3481 return WINED3DERR_INVALIDCALL;
3483 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3484 return WINED3D_OK;
3487 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3488 static HRESULT
3489 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3490 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3491 unsigned int i;
3492 DWORD DestFVF = dest->fvf;
3493 WINED3DVIEWPORT vp;
3494 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3495 BOOL doClip;
3496 int numTextures;
3498 if (lpStrideData->u.s.normal.lpData) {
3499 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3502 if (lpStrideData->u.s.position.lpData == NULL) {
3503 ERR("Source has no position mask\n");
3504 return WINED3DERR_INVALIDCALL;
3507 /* We might access VBOs from this code, so hold the lock */
3508 ENTER_GL();
3510 if (dest->resource.allocatedMemory == NULL) {
3511 /* This may happen if we do direct locking into a vbo. Unlikely,
3512 * but theoretically possible(ddraw processvertices test)
3514 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3515 if(!dest->resource.allocatedMemory) {
3516 LEAVE_GL();
3517 ERR("Out of memory\n");
3518 return E_OUTOFMEMORY;
3520 if(dest->vbo) {
3521 void *src;
3522 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3523 checkGLcall("glBindBufferARB");
3524 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3525 if(src) {
3526 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3528 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3529 checkGLcall("glUnmapBufferARB");
3533 /* Get a pointer into the destination vbo(create one if none exists) and
3534 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3536 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3537 CreateVBO(dest);
3540 if(dest->vbo) {
3541 unsigned char extrabytes = 0;
3542 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3543 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3544 * this may write 4 extra bytes beyond the area that should be written
3546 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3547 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3548 if(!dest_conv_addr) {
3549 ERR("Out of memory\n");
3550 /* Continue without storing converted vertices */
3552 dest_conv = dest_conv_addr;
3555 /* Should I clip?
3556 * a) WINED3DRS_CLIPPING is enabled
3557 * b) WINED3DVOP_CLIP is passed
3559 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3560 static BOOL warned = FALSE;
3562 * The clipping code is not quite correct. Some things need
3563 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3564 * so disable clipping for now.
3565 * (The graphics in Half-Life are broken, and my processvertices
3566 * test crashes with IDirect3DDevice3)
3567 doClip = TRUE;
3569 doClip = FALSE;
3570 if(!warned) {
3571 warned = TRUE;
3572 FIXME("Clipping is broken and disabled for now\n");
3574 } else doClip = FALSE;
3575 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3577 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3578 WINED3DTS_VIEW,
3579 &view_mat);
3580 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3581 WINED3DTS_PROJECTION,
3582 &proj_mat);
3583 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3584 WINED3DTS_WORLDMATRIX(0),
3585 &world_mat);
3587 TRACE("View mat:\n");
3588 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);
3589 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);
3590 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);
3591 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);
3593 TRACE("Proj mat:\n");
3594 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);
3595 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);
3596 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);
3597 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);
3599 TRACE("World mat:\n");
3600 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);
3601 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);
3602 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);
3603 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);
3605 /* Get the viewport */
3606 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3607 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3608 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3610 multiply_matrix(&mat,&view_mat,&world_mat);
3611 multiply_matrix(&mat,&proj_mat,&mat);
3613 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3615 for (i = 0; i < dwCount; i+= 1) {
3616 unsigned int tex_index;
3618 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3619 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3620 /* The position first */
3621 float *p =
3622 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3623 float x, y, z, rhw;
3624 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3626 /* Multiplication with world, view and projection matrix */
3627 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);
3628 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);
3629 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);
3630 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);
3632 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3634 /* WARNING: The following things are taken from d3d7 and were not yet checked
3635 * against d3d8 or d3d9!
3638 /* Clipping conditions: From
3639 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3641 * A vertex is clipped if it does not match the following requirements
3642 * -rhw < x <= rhw
3643 * -rhw < y <= rhw
3644 * 0 < z <= rhw
3645 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3647 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3648 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3652 if( !doClip ||
3653 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3654 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3655 ( rhw > eps ) ) ) {
3657 /* "Normal" viewport transformation (not clipped)
3658 * 1) The values are divided by rhw
3659 * 2) The y axis is negative, so multiply it with -1
3660 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3661 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3662 * 4) Multiply x with Width/2 and add Width/2
3663 * 5) The same for the height
3664 * 6) Add the viewpoint X and Y to the 2D coordinates and
3665 * The minimum Z value to z
3666 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3668 * Well, basically it's simply a linear transformation into viewport
3669 * coordinates
3672 x /= rhw;
3673 y /= rhw;
3674 z /= rhw;
3676 y *= -1;
3678 x *= vp.Width / 2;
3679 y *= vp.Height / 2;
3680 z *= vp.MaxZ - vp.MinZ;
3682 x += vp.Width / 2 + vp.X;
3683 y += vp.Height / 2 + vp.Y;
3684 z += vp.MinZ;
3686 rhw = 1 / rhw;
3687 } else {
3688 /* That vertex got clipped
3689 * Contrary to OpenGL it is not dropped completely, it just
3690 * undergoes a different calculation.
3692 TRACE("Vertex got clipped\n");
3693 x += rhw;
3694 y += rhw;
3696 x /= 2;
3697 y /= 2;
3699 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3700 * outside of the main vertex buffer memory. That needs some more
3701 * investigation...
3705 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3708 ( (float *) dest_ptr)[0] = x;
3709 ( (float *) dest_ptr)[1] = y;
3710 ( (float *) dest_ptr)[2] = z;
3711 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3713 dest_ptr += 3 * sizeof(float);
3715 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3716 dest_ptr += sizeof(float);
3719 if(dest_conv) {
3720 float w = 1 / rhw;
3721 ( (float *) dest_conv)[0] = x * w;
3722 ( (float *) dest_conv)[1] = y * w;
3723 ( (float *) dest_conv)[2] = z * w;
3724 ( (float *) dest_conv)[3] = w;
3726 dest_conv += 3 * sizeof(float);
3728 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3729 dest_conv += sizeof(float);
3733 if (DestFVF & WINED3DFVF_PSIZE) {
3734 dest_ptr += sizeof(DWORD);
3735 if(dest_conv) dest_conv += sizeof(DWORD);
3737 if (DestFVF & WINED3DFVF_NORMAL) {
3738 float *normal =
3739 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3740 /* AFAIK this should go into the lighting information */
3741 FIXME("Didn't expect the destination to have a normal\n");
3742 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3743 if(dest_conv) {
3744 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3748 if (DestFVF & WINED3DFVF_DIFFUSE) {
3749 DWORD *color_d =
3750 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3751 if(!color_d) {
3752 static BOOL warned = FALSE;
3754 if(!warned) {
3755 ERR("No diffuse color in source, but destination has one\n");
3756 warned = TRUE;
3759 *( (DWORD *) dest_ptr) = 0xffffffff;
3760 dest_ptr += sizeof(DWORD);
3762 if(dest_conv) {
3763 *( (DWORD *) dest_conv) = 0xffffffff;
3764 dest_conv += sizeof(DWORD);
3767 else {
3768 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3769 if(dest_conv) {
3770 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3771 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3772 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3773 dest_conv += sizeof(DWORD);
3778 if (DestFVF & WINED3DFVF_SPECULAR) {
3779 /* What's the color value in the feedback buffer? */
3780 DWORD *color_s =
3781 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3782 if(!color_s) {
3783 static BOOL warned = FALSE;
3785 if(!warned) {
3786 ERR("No specular color in source, but destination has one\n");
3787 warned = TRUE;
3790 *( (DWORD *) dest_ptr) = 0xFF000000;
3791 dest_ptr += sizeof(DWORD);
3793 if(dest_conv) {
3794 *( (DWORD *) dest_conv) = 0xFF000000;
3795 dest_conv += sizeof(DWORD);
3798 else {
3799 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3800 if(dest_conv) {
3801 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3802 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3803 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3804 dest_conv += sizeof(DWORD);
3809 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3810 float *tex_coord =
3811 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3812 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3813 if(!tex_coord) {
3814 ERR("No source texture, but destination requests one\n");
3815 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3816 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3818 else {
3819 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3820 if(dest_conv) {
3821 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3827 if(dest_conv) {
3828 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3829 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3830 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3831 dwCount * get_flexible_vertex_size(DestFVF),
3832 dest_conv_addr));
3833 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3834 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3837 LEAVE_GL();
3839 return WINED3D_OK;
3841 #undef copy_and_next
3843 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3845 WineDirect3DVertexStridedData strided;
3846 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3847 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3849 if(pVertexDecl) {
3850 ERR("Output vertex declaration not implemented yet\n");
3853 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3854 * and this call is quite performance critical, so don't call needlessly
3856 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3857 ENTER_GL();
3858 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3859 LEAVE_GL();
3862 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3863 * control the streamIsUP flag, thus restore it afterwards.
3865 This->stateBlock->streamIsUP = FALSE;
3866 memset(&strided, 0, sizeof(strided));
3867 if(This->stateBlock->vertexDecl) {
3868 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3869 } else {
3870 primitiveConvertToStridedData(iface, &strided, &vbo);
3872 This->stateBlock->streamIsUP = streamWasUP;
3874 if(vbo || SrcStartIndex) {
3875 unsigned int i;
3876 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3877 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3879 * Also get the start index in, but only loop over all elements if there's something to add at all.
3881 #define FIXSRC(type) \
3882 if(strided.u.s.type.VBO) { \
3883 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3884 strided.u.s.type.VBO = 0; \
3885 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3886 ENTER_GL(); \
3887 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3888 vb->vbo = 0; \
3889 LEAVE_GL(); \
3891 if(strided.u.s.type.lpData) { \
3892 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3894 FIXSRC(position);
3895 FIXSRC(blendWeights);
3896 FIXSRC(blendMatrixIndices);
3897 FIXSRC(normal);
3898 FIXSRC(pSize);
3899 FIXSRC(diffuse);
3900 FIXSRC(specular);
3901 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3902 FIXSRC(texCoords[i]);
3904 FIXSRC(position2);
3905 FIXSRC(normal2);
3906 FIXSRC(tangent);
3907 FIXSRC(binormal);
3908 FIXSRC(tessFactor);
3909 FIXSRC(fog);
3910 FIXSRC(depth);
3911 FIXSRC(sample);
3912 #undef FIXSRC
3915 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3918 /*****
3919 * Get / Set Texture Stage States
3920 * TODO: Verify against dx9 definitions
3921 *****/
3922 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3926 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3928 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3930 if (Stage >= MAX_TEXTURES) {
3931 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3932 return WINED3D_OK;
3935 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3936 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3937 This->updateStateBlock->textureState[Stage][Type] = Value;
3939 if (This->isRecordingState) {
3940 TRACE("Recording... not performing anything\n");
3941 return WINED3D_OK;
3944 /* Checked after the assignments to allow proper stateblock recording */
3945 if(oldValue == Value) {
3946 TRACE("App is setting the old value over, nothing to do\n");
3947 return WINED3D_OK;
3950 if(Stage > This->stateBlock->lowest_disabled_stage &&
3951 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3952 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3953 * Changes in other states are important on disabled stages too
3955 return WINED3D_OK;
3958 if(Type == WINED3DTSS_COLOROP) {
3959 int i;
3961 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3962 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3963 * they have to be disabled
3965 * The current stage is dirtified below.
3967 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3968 TRACE("Additionally dirtifying stage %d\n", i);
3969 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3971 This->stateBlock->lowest_disabled_stage = Stage;
3972 TRACE("New lowest disabled: %d\n", Stage);
3973 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3974 /* Previously disabled stage enabled. Stages above it may need enabling
3975 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3976 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3978 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3981 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3982 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3983 break;
3985 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3988 This->stateBlock->lowest_disabled_stage = i;
3989 TRACE("New lowest disabled: %d\n", i);
3991 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3992 /* TODO: Built a stage -> texture unit mapping for register combiners */
3996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3998 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3999 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4000 * will call FindTexUnitMap too.
4002 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4003 IWineD3DDeviceImpl_FindTexUnitMap(This);
4005 return WINED3D_OK;
4008 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4011 *pValue = This->updateStateBlock->textureState[Stage][Type];
4012 return WINED3D_OK;
4015 /*****
4016 * Get / Set Texture
4017 *****/
4018 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4021 IWineD3DBaseTexture *oldTexture;
4023 oldTexture = This->updateStateBlock->textures[Stage];
4024 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4026 #if 0 /* TODO: check so vertex textures */
4027 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4028 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4029 return WINED3D_OK;
4031 #endif
4033 if(pTexture != NULL) {
4034 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4036 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4037 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4038 return WINED3DERR_INVALIDCALL;
4040 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4043 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4044 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4046 This->updateStateBlock->set.textures[Stage] = TRUE;
4047 This->updateStateBlock->changed.textures[Stage] = TRUE;
4048 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4049 This->updateStateBlock->textures[Stage] = pTexture;
4051 /* Handle recording of state blocks */
4052 if (This->isRecordingState) {
4053 TRACE("Recording... not performing anything\n");
4054 return WINED3D_OK;
4057 if(oldTexture == pTexture) {
4058 TRACE("App is setting the same texture again, nothing to do\n");
4059 return WINED3D_OK;
4062 /** NOTE: MSDN says that setTexture increases the reference count,
4063 * and the the application nust set the texture back to null (or have a leaky application),
4064 * This means we should pass the refcount up to the parent
4065 *******************************/
4066 if (NULL != This->updateStateBlock->textures[Stage]) {
4067 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4068 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4070 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4071 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4072 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4073 * so the COLOROP and ALPHAOP have to be dirtified.
4075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4078 if(bindCount == 1) {
4079 new->baseTexture.sampler = Stage;
4081 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4085 if (NULL != oldTexture) {
4086 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4087 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4089 IWineD3DBaseTexture_Release(oldTexture);
4090 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4095 if(bindCount && old->baseTexture.sampler == Stage) {
4096 int i;
4097 /* Have to do a search for the other sampler(s) where the texture is bound to
4098 * Shouldn't happen as long as apps bind a texture only to one stage
4100 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4101 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4102 if(This->updateStateBlock->textures[i] == oldTexture) {
4103 old->baseTexture.sampler = i;
4104 break;
4110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4112 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4113 * pixel shader is used
4115 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4116 IWineD3DDeviceImpl_FindTexUnitMap(This);
4119 return WINED3D_OK;
4122 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4124 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4126 *ppTexture=This->stateBlock->textures[Stage];
4127 if (*ppTexture)
4128 IWineD3DBaseTexture_AddRef(*ppTexture);
4130 return WINED3D_OK;
4133 /*****
4134 * Get Back Buffer
4135 *****/
4136 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4137 IWineD3DSurface **ppBackBuffer) {
4138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4139 IWineD3DSwapChain *swapChain;
4140 HRESULT hr;
4142 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4144 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4145 if (hr == WINED3D_OK) {
4146 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4147 IWineD3DSwapChain_Release(swapChain);
4148 } else {
4149 *ppBackBuffer = NULL;
4151 return hr;
4154 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4156 WARN("(%p) : stub, calling idirect3d for now\n", This);
4157 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4160 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4162 IWineD3DSwapChain *swapChain;
4163 HRESULT hr;
4165 if(iSwapChain > 0) {
4166 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4167 if (hr == WINED3D_OK) {
4168 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4169 IWineD3DSwapChain_Release(swapChain);
4170 } else {
4171 FIXME("(%p) Error getting display mode\n", This);
4173 } else {
4174 /* Don't read the real display mode,
4175 but return the stored mode instead. X11 can't change the color
4176 depth, and some apps are pretty angry if they SetDisplayMode from
4177 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4179 Also don't relay to the swapchain because with ddraw it's possible
4180 that there isn't a swapchain at all */
4181 pMode->Width = This->ddraw_width;
4182 pMode->Height = This->ddraw_height;
4183 pMode->Format = This->ddraw_format;
4184 pMode->RefreshRate = 0;
4185 hr = WINED3D_OK;
4188 return hr;
4191 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4193 TRACE("(%p)->(%p)\n", This, hWnd);
4195 if(This->ddraw_fullscreen) {
4196 if(This->ddraw_window && This->ddraw_window != hWnd) {
4197 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4199 if(hWnd && This->ddraw_window != hWnd) {
4200 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4204 This->ddraw_window = hWnd;
4205 return WINED3D_OK;
4208 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4210 TRACE("(%p)->(%p)\n", This, hWnd);
4212 *hWnd = This->ddraw_window;
4213 return WINED3D_OK;
4216 /*****
4217 * Stateblock related functions
4218 *****/
4220 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4222 IWineD3DStateBlockImpl *object;
4223 HRESULT temp_result;
4224 int i;
4226 TRACE("(%p)\n", This);
4228 if (This->isRecordingState) {
4229 return WINED3DERR_INVALIDCALL;
4232 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4233 if (NULL == object ) {
4234 FIXME("(%p)Error allocating memory for stateblock\n", This);
4235 return E_OUTOFMEMORY;
4237 TRACE("(%p) created object %p\n", This, object);
4238 object->wineD3DDevice= This;
4239 /** FIXME: object->parent = parent; **/
4240 object->parent = NULL;
4241 object->blockType = WINED3DSBT_ALL;
4242 object->ref = 1;
4243 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4245 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4246 list_init(&object->lightMap[i]);
4249 temp_result = allocate_shader_constants(object);
4250 if (WINED3D_OK != temp_result)
4251 return temp_result;
4253 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4254 This->updateStateBlock = object;
4255 This->isRecordingState = TRUE;
4257 TRACE("(%p) recording stateblock %p\n",This , object);
4258 return WINED3D_OK;
4261 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4264 if (!This->isRecordingState) {
4265 FIXME("(%p) not recording! returning error\n", This);
4266 *ppStateBlock = NULL;
4267 return WINED3DERR_INVALIDCALL;
4270 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4271 This->isRecordingState = FALSE;
4272 This->updateStateBlock = This->stateBlock;
4273 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4274 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4275 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4276 return WINED3D_OK;
4279 /*****
4280 * Scene related functions
4281 *****/
4282 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4283 /* At the moment we have no need for any functionality at the beginning
4284 of a scene */
4285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4286 TRACE("(%p)\n", This);
4288 if(This->inScene) {
4289 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4290 return WINED3DERR_INVALIDCALL;
4292 This->inScene = TRUE;
4293 return WINED3D_OK;
4296 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4298 TRACE("(%p)\n", This);
4300 if(!This->inScene) {
4301 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4302 return WINED3DERR_INVALIDCALL;
4305 ENTER_GL();
4306 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4307 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4309 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4310 glFlush();
4311 checkGLcall("glFlush");
4312 LEAVE_GL();
4314 This->inScene = FALSE;
4315 return WINED3D_OK;
4318 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4319 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4320 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4322 IWineD3DSwapChain *swapChain = NULL;
4323 int i;
4324 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4326 TRACE("(%p) Presenting the frame\n", This);
4328 for(i = 0 ; i < swapchains ; i ++) {
4330 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4331 TRACE("presentinng chain %d, %p\n", i, swapChain);
4332 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4333 IWineD3DSwapChain_Release(swapChain);
4336 return WINED3D_OK;
4339 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4340 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4342 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4344 GLbitfield glMask = 0;
4345 unsigned int i;
4346 CONST WINED3DRECT* curRect;
4348 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4349 Count, pRects, Flags, Z, Stencil);
4351 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4352 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4353 /* TODO: What about depth stencil buffers without stencil bits? */
4354 return WINED3DERR_INVALIDCALL;
4357 ENTER_GL();
4358 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4359 * and not the last active one.
4362 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4363 apply_fbo_state(iface);
4366 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4368 glEnable(GL_SCISSOR_TEST);
4369 checkGLcall("glEnable GL_SCISSOR_TEST");
4370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4373 if (Count > 0 && pRects) {
4374 curRect = pRects;
4375 } else {
4376 curRect = NULL;
4379 /* Only set the values up once, as they are not changing */
4380 if (Flags & WINED3DCLEAR_STENCIL) {
4381 glClearStencil(Stencil);
4382 checkGLcall("glClearStencil");
4383 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4384 glStencilMask(0xFFFFFFFF);
4387 if (Flags & WINED3DCLEAR_ZBUFFER) {
4388 glDepthMask(GL_TRUE);
4389 glClearDepth(Z);
4390 checkGLcall("glClearDepth");
4391 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4395 if (Flags & WINED3DCLEAR_TARGET) {
4396 TRACE("Clearing screen with glClear to color %x\n", Color);
4397 glClearColor(D3DCOLOR_R(Color),
4398 D3DCOLOR_G(Color),
4399 D3DCOLOR_B(Color),
4400 D3DCOLOR_A(Color));
4401 checkGLcall("glClearColor");
4403 /* Clear ALL colors! */
4404 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4405 glMask = glMask | GL_COLOR_BUFFER_BIT;
4408 if (!curRect) {
4409 /* In drawable flag is set below */
4411 glScissor(This->stateBlock->viewport.X,
4412 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4413 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4414 This->stateBlock->viewport.Width,
4415 This->stateBlock->viewport.Height);
4416 checkGLcall("glScissor");
4417 glClear(glMask);
4418 checkGLcall("glClear");
4419 } else {
4420 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4421 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4423 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4424 curRect[0].x2 < target->currentDesc.Width ||
4425 curRect[0].y2 < target->currentDesc.Height) {
4426 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4427 blt_to_drawable(This, target);
4431 /* Now process each rect in turn */
4432 for (i = 0; i < Count; i++) {
4433 /* Note gl uses lower left, width/height */
4434 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4435 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4436 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4437 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4439 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4440 * The rectangle is not cleared, no error is returned, but further rectanlges are
4441 * still cleared if they are valid
4443 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4444 TRACE("Rectangle with negative dimensions, ignoring\n");
4445 continue;
4448 if(This->render_offscreen) {
4449 glScissor(curRect[i].x1, curRect[i].y1,
4450 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4451 } else {
4452 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4453 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4455 checkGLcall("glScissor");
4457 glClear(glMask);
4458 checkGLcall("glClear");
4462 /* Restore the old values (why..?) */
4463 if (Flags & WINED3DCLEAR_STENCIL) {
4464 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4466 if (Flags & WINED3DCLEAR_TARGET) {
4467 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4468 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4469 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4470 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4471 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4474 LEAVE_GL();
4476 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4477 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4479 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4480 target->Flags |= SFLAG_INTEXTURE;
4481 target->Flags &= ~SFLAG_INSYSMEM;
4482 } else {
4483 target->Flags |= SFLAG_INDRAWABLE;
4484 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4486 return WINED3D_OK;
4489 /*****
4490 * Drawing functions
4491 *****/
4492 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4493 UINT PrimitiveCount) {
4495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4497 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4498 debug_d3dprimitivetype(PrimitiveType),
4499 StartVertex, PrimitiveCount);
4501 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4502 if(This->stateBlock->streamIsUP) {
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4504 This->stateBlock->streamIsUP = FALSE;
4507 if(This->stateBlock->loadBaseVertexIndex != 0) {
4508 This->stateBlock->loadBaseVertexIndex = 0;
4509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4511 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4512 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4513 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4514 return WINED3D_OK;
4517 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4518 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4519 WINED3DPRIMITIVETYPE PrimitiveType,
4520 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4523 UINT idxStride = 2;
4524 IWineD3DIndexBuffer *pIB;
4525 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4526 GLuint vbo;
4528 if(This->stateBlock->streamIsUP) {
4529 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4530 This->stateBlock->streamIsUP = FALSE;
4532 pIB = This->stateBlock->pIndexData;
4533 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4535 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4536 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4537 minIndex, NumVertices, startIndex, primCount);
4539 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4540 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4541 idxStride = 2;
4542 } else {
4543 idxStride = 4;
4546 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4547 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4551 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4552 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4554 return WINED3D_OK;
4557 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4558 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4559 UINT VertexStreamZeroStride) {
4560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4562 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4563 debug_d3dprimitivetype(PrimitiveType),
4564 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4566 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4567 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4568 This->stateBlock->streamOffset[0] = 0;
4569 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4570 This->stateBlock->streamIsUP = TRUE;
4571 This->stateBlock->loadBaseVertexIndex = 0;
4573 /* TODO: Only mark dirty if drawing from a different UP address */
4574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4576 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4577 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4579 /* MSDN specifies stream zero settings must be set to NULL */
4580 This->stateBlock->streamStride[0] = 0;
4581 This->stateBlock->streamSource[0] = NULL;
4583 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4584 * the new stream sources or use UP drawing again
4586 return WINED3D_OK;
4589 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4590 UINT MinVertexIndex, UINT NumVertices,
4591 UINT PrimitiveCount, CONST void* pIndexData,
4592 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4593 UINT VertexStreamZeroStride) {
4594 int idxStride;
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4597 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4598 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4599 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4600 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4602 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4603 idxStride = 2;
4604 } else {
4605 idxStride = 4;
4608 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4609 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4610 This->stateBlock->streamIsUP = TRUE;
4611 This->stateBlock->streamOffset[0] = 0;
4612 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4614 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4615 This->stateBlock->baseVertexIndex = 0;
4616 This->stateBlock->loadBaseVertexIndex = 0;
4617 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4621 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4623 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4624 This->stateBlock->streamSource[0] = NULL;
4625 This->stateBlock->streamStride[0] = 0;
4626 This->stateBlock->pIndexData = NULL;
4627 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4628 * SetStreamSource to specify a vertex buffer
4631 return WINED3D_OK;
4634 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4637 /* Mark the state dirty until we have nicer tracking
4638 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4639 * that value.
4641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4643 This->stateBlock->baseVertexIndex = 0;
4644 This->up_strided = DrawPrimStrideData;
4645 This->stateBlock->streamIsUP = TRUE;
4646 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4647 This->up_strided = NULL;
4648 return WINED3D_OK;
4650 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4651 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4653 HRESULT hr = WINED3D_OK;
4654 WINED3DRESOURCETYPE sourceType;
4655 WINED3DRESOURCETYPE destinationType;
4656 int i ,levels;
4658 /* TODO: think about moving the code into IWineD3DBaseTexture */
4660 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4662 /* verify that the source and destination textures aren't NULL */
4663 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4664 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4665 This, pSourceTexture, pDestinationTexture);
4666 hr = WINED3DERR_INVALIDCALL;
4669 if (pSourceTexture == pDestinationTexture) {
4670 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4671 This, pSourceTexture, pDestinationTexture);
4672 hr = WINED3DERR_INVALIDCALL;
4674 /* Verify that the source and destination textures are the same type */
4675 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4676 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4678 if (sourceType != destinationType) {
4679 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4680 This);
4681 hr = WINED3DERR_INVALIDCALL;
4684 /* check that both textures have the identical numbers of levels */
4685 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4686 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4687 hr = WINED3DERR_INVALIDCALL;
4690 if (WINED3D_OK == hr) {
4692 /* Make sure that the destination texture is loaded */
4693 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4695 /* Update every surface level of the texture */
4696 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4698 switch (sourceType) {
4699 case WINED3DRTYPE_TEXTURE:
4701 IWineD3DSurface *srcSurface;
4702 IWineD3DSurface *destSurface;
4704 for (i = 0 ; i < levels ; ++i) {
4705 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4706 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4707 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4708 IWineD3DSurface_Release(srcSurface);
4709 IWineD3DSurface_Release(destSurface);
4710 if (WINED3D_OK != hr) {
4711 WARN("(%p) : Call to update surface failed\n", This);
4712 return hr;
4716 break;
4717 case WINED3DRTYPE_CUBETEXTURE:
4719 IWineD3DSurface *srcSurface;
4720 IWineD3DSurface *destSurface;
4721 WINED3DCUBEMAP_FACES faceType;
4723 for (i = 0 ; i < levels ; ++i) {
4724 /* Update each cube face */
4725 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4726 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4727 if (WINED3D_OK != hr) {
4728 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4729 } else {
4730 TRACE("Got srcSurface %p\n", srcSurface);
4732 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4733 if (WINED3D_OK != hr) {
4734 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4735 } else {
4736 TRACE("Got desrSurface %p\n", destSurface);
4738 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4739 IWineD3DSurface_Release(srcSurface);
4740 IWineD3DSurface_Release(destSurface);
4741 if (WINED3D_OK != hr) {
4742 WARN("(%p) : Call to update surface failed\n", This);
4743 return hr;
4748 break;
4749 #if 0 /* TODO: Add support for volume textures */
4750 case WINED3DRTYPE_VOLUMETEXTURE:
4752 IWineD3DVolume srcVolume = NULL;
4753 IWineD3DSurface destVolume = NULL;
4755 for (i = 0 ; i < levels ; ++i) {
4756 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4757 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4758 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4759 IWineD3DVolume_Release(srcSurface);
4760 IWineD3DVolume_Release(destSurface);
4761 if (WINED3D_OK != hr) {
4762 WARN("(%p) : Call to update volume failed\n", This);
4763 return hr;
4767 break;
4768 #endif
4769 default:
4770 FIXME("(%p) : Unsupported source and destination type\n", This);
4771 hr = WINED3DERR_INVALIDCALL;
4775 return hr;
4778 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4779 IWineD3DSwapChain *swapChain;
4780 HRESULT hr;
4781 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4782 if(hr == WINED3D_OK) {
4783 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4784 IWineD3DSwapChain_Release(swapChain);
4786 return hr;
4789 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4791 /* return a sensible default */
4792 *pNumPasses = 1;
4793 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4794 FIXME("(%p) : stub\n", This);
4795 return WINED3D_OK;
4798 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 int j;
4801 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4802 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4803 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4804 return WINED3DERR_INVALIDCALL;
4806 for (j = 0; j < 256; ++j) {
4807 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4808 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4809 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4810 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4812 TRACE("(%p) : returning\n", This);
4813 return WINED3D_OK;
4816 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4818 int j;
4819 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4820 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4821 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4822 return WINED3DERR_INVALIDCALL;
4824 for (j = 0; j < 256; ++j) {
4825 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4826 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4827 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4828 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4830 TRACE("(%p) : returning\n", This);
4831 return WINED3D_OK;
4834 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4836 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4837 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4838 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4839 return WINED3DERR_INVALIDCALL;
4841 /*TODO: stateblocks */
4842 This->currentPalette = PaletteNumber;
4843 TRACE("(%p) : returning\n", This);
4844 return WINED3D_OK;
4847 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4849 if (PaletteNumber == NULL) {
4850 WARN("(%p) : returning Invalid Call\n", This);
4851 return WINED3DERR_INVALIDCALL;
4853 /*TODO: stateblocks */
4854 *PaletteNumber = This->currentPalette;
4855 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4856 return WINED3D_OK;
4859 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4861 static BOOL showFixmes = TRUE;
4862 if (showFixmes) {
4863 FIXME("(%p) : stub\n", This);
4864 showFixmes = FALSE;
4867 This->softwareVertexProcessing = bSoftware;
4868 return WINED3D_OK;
4872 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4874 static BOOL showFixmes = TRUE;
4875 if (showFixmes) {
4876 FIXME("(%p) : stub\n", This);
4877 showFixmes = FALSE;
4879 return This->softwareVertexProcessing;
4883 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4885 IWineD3DSwapChain *swapChain;
4886 HRESULT hr;
4888 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4890 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4891 if(hr == WINED3D_OK){
4892 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4893 IWineD3DSwapChain_Release(swapChain);
4894 }else{
4895 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4897 return hr;
4901 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4903 static BOOL showfixmes = TRUE;
4904 if(nSegments != 0.0f) {
4905 if( showfixmes) {
4906 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4907 showfixmes = FALSE;
4910 return WINED3D_OK;
4913 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4915 static BOOL showfixmes = TRUE;
4916 if( showfixmes) {
4917 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4918 showfixmes = FALSE;
4920 return 0.0f;
4923 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4925 /** TODO: remove casts to IWineD3DSurfaceImpl
4926 * NOTE: move code to surface to accomplish this
4927 ****************************************/
4928 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4929 int srcWidth, srcHeight;
4930 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4931 WINED3DFORMAT destFormat, srcFormat;
4932 UINT destSize;
4933 int srcLeft, destLeft, destTop;
4934 WINED3DPOOL srcPool, destPool;
4935 int offset = 0;
4936 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4937 glDescriptor *glDescription = NULL;
4939 WINED3DSURFACE_DESC winedesc;
4941 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4942 memset(&winedesc, 0, sizeof(winedesc));
4943 winedesc.Width = &srcSurfaceWidth;
4944 winedesc.Height = &srcSurfaceHeight;
4945 winedesc.Pool = &srcPool;
4946 winedesc.Format = &srcFormat;
4948 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4950 winedesc.Width = &destSurfaceWidth;
4951 winedesc.Height = &destSurfaceHeight;
4952 winedesc.Pool = &destPool;
4953 winedesc.Format = &destFormat;
4954 winedesc.Size = &destSize;
4956 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4958 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4959 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4960 return WINED3DERR_INVALIDCALL;
4963 if (destFormat == WINED3DFMT_UNKNOWN) {
4964 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4965 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4967 /* Get the update surface description */
4968 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4971 ENTER_GL();
4973 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4975 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4976 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4977 checkGLcall("glActiveTextureARB");
4980 /* Make sure the surface is loaded and up to date */
4981 IWineD3DSurface_PreLoad(pDestinationSurface);
4983 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4985 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4986 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4987 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4988 srcLeft = pSourceRect ? pSourceRect->left : 0;
4989 destLeft = pDestPoint ? pDestPoint->x : 0;
4990 destTop = pDestPoint ? pDestPoint->y : 0;
4993 /* This function doesn't support compressed textures
4994 the pitch is just bytesPerPixel * width */
4995 if(srcWidth != srcSurfaceWidth || srcLeft ){
4996 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4997 offset += srcLeft * pSrcSurface->bytesPerPixel;
4998 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5000 /* TODO DXT formats */
5002 if(pSourceRect != NULL && pSourceRect->top != 0){
5003 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5005 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5006 ,This
5007 ,glDescription->level
5008 ,destLeft
5009 ,destTop
5010 ,srcWidth
5011 ,srcHeight
5012 ,glDescription->glFormat
5013 ,glDescription->glType
5014 ,IWineD3DSurface_GetData(pSourceSurface)
5017 /* Sanity check */
5018 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5020 /* need to lock the surface to get the data */
5021 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5024 /* TODO: Cube and volume support */
5025 if(rowoffset != 0){
5026 /* not a whole row so we have to do it a line at a time */
5027 int j;
5029 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5030 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5032 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5034 glTexSubImage2D(glDescription->target
5035 ,glDescription->level
5036 ,destLeft
5038 ,srcWidth
5040 ,glDescription->glFormat
5041 ,glDescription->glType
5042 ,data /* could be quicker using */
5044 data += rowoffset;
5047 } else { /* Full width, so just write out the whole texture */
5049 if (WINED3DFMT_DXT1 == destFormat ||
5050 WINED3DFMT_DXT2 == destFormat ||
5051 WINED3DFMT_DXT3 == destFormat ||
5052 WINED3DFMT_DXT4 == destFormat ||
5053 WINED3DFMT_DXT5 == destFormat) {
5054 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5055 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5056 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5057 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5058 } if (destFormat != srcFormat) {
5059 FIXME("Updating mixed format compressed texture is not curretly support\n");
5060 } else {
5061 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5062 glDescription->level,
5063 glDescription->glFormatInternal,
5064 srcWidth,
5065 srcHeight,
5067 destSize,
5068 IWineD3DSurface_GetData(pSourceSurface));
5070 } else {
5071 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5075 } else {
5076 glTexSubImage2D(glDescription->target
5077 ,glDescription->level
5078 ,destLeft
5079 ,destTop
5080 ,srcWidth
5081 ,srcHeight
5082 ,glDescription->glFormat
5083 ,glDescription->glType
5084 ,IWineD3DSurface_GetData(pSourceSurface)
5088 checkGLcall("glTexSubImage2D");
5090 LEAVE_GL();
5092 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5093 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5096 return WINED3D_OK;
5099 /* Implementation details at http://developer.nvidia.com/attach/6494
5101 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5102 hmm.. no longer supported use
5103 OpenGL evaluators or tessellate surfaces within your application.
5106 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5107 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5109 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5110 FIXME("(%p) : Stub\n", This);
5111 return WINED3D_OK;
5115 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5116 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5118 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5119 FIXME("(%p) : Stub\n", This);
5120 return WINED3D_OK;
5123 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5125 TRACE("(%p) Handle(%d)\n", This, Handle);
5126 FIXME("(%p) : Stub\n", This);
5127 return WINED3D_OK;
5130 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5131 HRESULT hr;
5132 IWineD3DSwapChain *swapchain;
5134 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5135 if (SUCCEEDED(hr)) {
5136 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5137 return swapchain;
5140 return NULL;
5143 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5146 if (!*fbo) {
5147 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5148 checkGLcall("glGenFramebuffersEXT()");
5150 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5151 checkGLcall("glBindFramebuffer()");
5154 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5155 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5156 GLenum texttarget, target;
5157 GLint old_binding;
5159 texttarget = surface_impl->glDescription.target;
5160 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5161 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5163 IWineD3DSurface_PreLoad(surface);
5165 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5166 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5167 glBindTexture(target, old_binding);
5169 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5171 checkGLcall("attach_surface_fbo");
5174 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5176 IWineD3DSwapChain *swapchain;
5178 swapchain = get_swapchain(surface);
5179 if (swapchain) {
5180 GLenum buffer;
5182 TRACE("Surface %p is onscreen\n", surface);
5184 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5185 buffer = surface_get_gl_buffer(surface, swapchain);
5186 glDrawBuffer(buffer);
5187 checkGLcall("glDrawBuffer()");
5188 } else {
5189 TRACE("Surface %p is offscreen\n", surface);
5190 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5191 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5194 if (rect) {
5195 glEnable(GL_SCISSOR_TEST);
5196 if(!swapchain) {
5197 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5198 } else {
5199 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5200 rect->x2 - rect->x1, rect->y2 - rect->y1);
5202 checkGLcall("glScissor");
5203 } else {
5204 glDisable(GL_SCISSOR_TEST);
5206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5208 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5211 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5212 glClear(GL_COLOR_BUFFER_BIT);
5213 checkGLcall("glClear");
5215 if (This->render_offscreen) {
5216 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5217 } else {
5218 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5219 checkGLcall("glBindFramebuffer()");
5222 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5223 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5224 glDrawBuffer(GL_BACK);
5225 checkGLcall("glDrawBuffer()");
5229 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5231 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5232 WINEDDBLTFX BltFx;
5233 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5235 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5236 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5237 return WINED3DERR_INVALIDCALL;
5240 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5241 color_fill_fbo(iface, pSurface, pRect, color);
5242 return WINED3D_OK;
5243 } else {
5244 /* Just forward this to the DirectDraw blitting engine */
5245 memset(&BltFx, 0, sizeof(BltFx));
5246 BltFx.dwSize = sizeof(BltFx);
5247 BltFx.u5.dwFillColor = color;
5248 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5252 /* rendertarget and deptth stencil functions */
5253 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5256 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5257 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5258 return WINED3DERR_INVALIDCALL;
5261 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5262 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5263 /* Note inc ref on returned surface */
5264 if(*ppRenderTarget != NULL)
5265 IWineD3DSurface_AddRef(*ppRenderTarget);
5266 return WINED3D_OK;
5269 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5271 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5272 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5273 IWineD3DSwapChainImpl *Swapchain;
5274 HRESULT hr;
5276 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5278 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5279 if(hr != WINED3D_OK) {
5280 ERR("Can't get the swapchain\n");
5281 return hr;
5284 /* Make sure to release the swapchain */
5285 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5287 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5288 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5289 return WINED3DERR_INVALIDCALL;
5291 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5292 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5293 return WINED3DERR_INVALIDCALL;
5296 if(Swapchain->frontBuffer != Front) {
5297 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5299 if(Swapchain->frontBuffer)
5300 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5301 Swapchain->frontBuffer = Front;
5303 if(Swapchain->frontBuffer) {
5304 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5308 if(Back && !Swapchain->backBuffer) {
5309 /* We need memory for the back buffer array - only one back buffer this way */
5310 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5311 if(!Swapchain->backBuffer) {
5312 ERR("Out of memory\n");
5313 return E_OUTOFMEMORY;
5317 if(Swapchain->backBuffer[0] != Back) {
5318 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5320 /* What to do about the context here in the case of multithreading? Not sure.
5321 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5323 ENTER_GL();
5324 if(!Swapchain->backBuffer[0]) {
5325 /* GL was told to draw to the front buffer at creation,
5326 * undo that
5328 glDrawBuffer(GL_BACK);
5329 checkGLcall("glDrawBuffer(GL_BACK)");
5330 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5331 Swapchain->presentParms.BackBufferCount = 1;
5332 } else if (!Back) {
5333 /* That makes problems - disable for now */
5334 /* glDrawBuffer(GL_FRONT); */
5335 checkGLcall("glDrawBuffer(GL_FRONT)");
5336 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5337 Swapchain->presentParms.BackBufferCount = 0;
5339 LEAVE_GL();
5341 if(Swapchain->backBuffer[0])
5342 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5343 Swapchain->backBuffer[0] = Back;
5345 if(Swapchain->backBuffer[0]) {
5346 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5347 } else {
5348 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5353 return WINED3D_OK;
5356 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5358 *ppZStencilSurface = This->depthStencilBuffer;
5359 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5361 if(*ppZStencilSurface != NULL) {
5362 /* Note inc ref on returned surface */
5363 IWineD3DSurface_AddRef(*ppZStencilSurface);
5365 return WINED3D_OK;
5368 /* TODO: Handle stencil attachments */
5369 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5371 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5373 TRACE("Set depth stencil to %p\n", depth_stencil);
5375 if (depth_stencil_impl) {
5376 if (depth_stencil_impl->current_renderbuffer) {
5377 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5378 checkGLcall("glFramebufferRenderbufferEXT()");
5379 } else {
5380 GLenum texttarget, target;
5381 GLint old_binding = 0;
5383 texttarget = depth_stencil_impl->glDescription.target;
5384 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5385 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5387 IWineD3DSurface_PreLoad(depth_stencil);
5389 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5390 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5391 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5392 glBindTexture(target, old_binding);
5394 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5395 checkGLcall("glFramebufferTexture2DEXT()");
5397 } else {
5398 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5399 checkGLcall("glFramebufferTexture2DEXT()");
5403 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5405 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5407 TRACE("Set render target %u to %p\n", idx, render_target);
5409 if (rtimpl) {
5410 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5411 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5412 } else {
5413 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5414 checkGLcall("glFramebufferTexture2DEXT()");
5416 This->draw_buffers[idx] = GL_NONE;
5420 static void check_fbo_status(IWineD3DDevice *iface) {
5421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5422 GLenum status;
5424 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5425 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5426 TRACE("FBO complete\n");
5427 } else {
5428 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5430 /* Dump the FBO attachments */
5431 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5432 IWineD3DSurfaceImpl *attachment;
5433 int i;
5435 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5436 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5437 if (attachment) {
5438 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5439 attachment->pow2Width, attachment->pow2Height);
5442 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5443 if (attachment) {
5444 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5445 attachment->pow2Width, attachment->pow2Height);
5451 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5453 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5454 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5456 if (!ds_impl) return FALSE;
5458 if (ds_impl->current_renderbuffer) {
5459 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5460 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5463 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5464 rt_impl->pow2Height != ds_impl->pow2Height);
5467 void apply_fbo_state(IWineD3DDevice *iface) {
5468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5469 unsigned int i;
5471 if (This->render_offscreen) {
5472 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5474 /* Apply render targets */
5475 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5476 IWineD3DSurface *render_target = This->render_targets[i];
5477 if (This->fbo_color_attachments[i] != render_target) {
5478 set_render_target_fbo(iface, i, render_target);
5479 This->fbo_color_attachments[i] = render_target;
5483 /* Apply depth targets */
5484 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5485 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5486 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5488 if (This->stencilBufferTarget) {
5489 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5491 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5492 This->fbo_depth_attachment = This->stencilBufferTarget;
5495 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5496 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5497 checkGLcall("glDrawBuffers()");
5498 } else {
5499 glDrawBuffer(This->draw_buffers[0]);
5500 checkGLcall("glDrawBuffer()");
5502 } else {
5503 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5506 check_fbo_status(iface);
5509 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5510 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5512 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5513 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5514 GLenum gl_filter;
5516 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5517 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5518 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5519 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5521 glDisable(GL_SCISSOR_TEST);
5522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5524 switch (filter) {
5525 case WINED3DTEXF_LINEAR:
5526 gl_filter = GL_LINEAR;
5527 break;
5529 default:
5530 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5531 case WINED3DTEXF_NONE:
5532 case WINED3DTEXF_POINT:
5533 gl_filter = GL_NEAREST;
5534 break;
5537 /* Attach src surface to src fbo */
5538 src_swapchain = get_swapchain(src_surface);
5539 if (src_swapchain) {
5540 GLenum buffer;
5542 TRACE("Source surface %p is onscreen\n", src_surface);
5544 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5545 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5546 glReadBuffer(buffer);
5547 checkGLcall("glReadBuffer()");
5549 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5550 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5551 } else {
5552 TRACE("Source surface %p is offscreen\n", src_surface);
5553 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5554 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5555 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5556 checkGLcall("glReadBuffer()");
5559 /* Attach dst surface to dst fbo */
5560 dst_swapchain = get_swapchain(dst_surface);
5561 if (dst_swapchain) {
5562 GLenum buffer;
5564 TRACE("Destination surface %p is onscreen\n", dst_surface);
5566 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5567 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5568 glDrawBuffer(buffer);
5569 checkGLcall("glDrawBuffer()");
5571 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5572 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5573 } else {
5574 TRACE("Destination surface %p is offscreen\n", dst_surface);
5575 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5576 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5577 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5578 checkGLcall("glDrawBuffer()");
5581 if (flip) {
5582 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5583 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5584 } else {
5585 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5586 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5589 if (This->render_offscreen) {
5590 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5591 } else {
5592 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5593 checkGLcall("glBindFramebuffer()");
5596 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5597 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5598 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5599 glDrawBuffer(GL_BACK);
5600 checkGLcall("glDrawBuffer()");
5604 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5606 WINED3DVIEWPORT viewport;
5608 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5610 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5611 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5612 return WINED3DERR_INVALIDCALL;
5615 /* MSDN says that null disables the render target
5616 but a device must always be associated with a render target
5617 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5619 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5620 for more details
5622 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5623 FIXME("Trying to set render target 0 to NULL\n");
5624 return WINED3DERR_INVALIDCALL;
5626 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5627 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);
5628 return WINED3DERR_INVALIDCALL;
5631 /* If we are trying to set what we already have, don't bother */
5632 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5633 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5634 return WINED3D_OK;
5636 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5637 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5638 This->render_targets[RenderTargetIndex] = pRenderTarget;
5640 /* Render target 0 is special */
5641 if(RenderTargetIndex == 0) {
5642 /* Finally, reset the viewport as the MSDN states. */
5643 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5644 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5645 viewport.X = 0;
5646 viewport.Y = 0;
5647 viewport.MaxZ = 1.0f;
5648 viewport.MinZ = 0.0f;
5649 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5650 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5651 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5655 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5656 * ctx properly.
5657 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5658 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5660 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5662 return WINED3D_OK;
5665 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5667 HRESULT hr = WINED3D_OK;
5668 IWineD3DSurface *tmp;
5670 TRACE("(%p) Swapping z-buffer\n",This);
5672 if (pNewZStencil == This->stencilBufferTarget) {
5673 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5674 } else {
5675 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5676 * depending on the renter target implementation being used.
5677 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5678 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5679 * stencil buffer and incure an extra memory overhead
5680 ******************************************************/
5682 tmp = This->stencilBufferTarget;
5683 This->stencilBufferTarget = pNewZStencil;
5684 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5685 /* should we be calling the parent or the wined3d surface? */
5686 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5687 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5688 hr = WINED3D_OK;
5690 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5691 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5694 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5698 return hr;
5701 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5702 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5704 /* TODO: the use of Impl is deprecated. */
5705 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5707 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5709 /* some basic validation checks */
5710 if(This->cursorTexture) {
5711 ENTER_GL();
5712 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5713 glDeleteTextures(1, &This->cursorTexture);
5714 LEAVE_GL();
5715 This->cursorTexture = 0;
5718 if(pCursorBitmap) {
5719 WINED3DLOCKED_RECT rect;
5721 /* MSDN: Cursor must be A8R8G8B8 */
5722 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5723 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5724 return WINED3DERR_INVALIDCALL;
5727 /* MSDN: Cursor must be smaller than the display mode */
5728 if(pSur->currentDesc.Width > This->ddraw_width ||
5729 pSur->currentDesc.Height > This->ddraw_height) {
5730 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);
5731 return WINED3DERR_INVALIDCALL;
5734 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5736 /* Do not store the surface's pointer because the application may release
5737 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5738 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5740 This->cursorWidth = pSur->currentDesc.Width;
5741 This->cursorHeight = pSur->currentDesc.Height;
5742 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5744 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5745 char *mem, *bits = (char *)rect.pBits;
5746 GLint intfmt = tableEntry->glInternal;
5747 GLint format = tableEntry->glFormat;
5748 GLint type = tableEntry->glType;
5749 INT height = This->cursorHeight;
5750 INT width = This->cursorWidth;
5751 INT bpp = tableEntry->bpp;
5752 INT i;
5754 /* Reformat the texture memory (pitch and width can be different) */
5755 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5756 for(i = 0; i < height; i++)
5757 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5758 IWineD3DSurface_UnlockRect(pCursorBitmap);
5759 ENTER_GL();
5761 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5762 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5763 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5766 /* Make sure that a proper texture unit is selected */
5767 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5768 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5769 checkGLcall("glActiveTextureARB");
5771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5772 /* Create a new cursor texture */
5773 glGenTextures(1, &This->cursorTexture);
5774 checkGLcall("glGenTextures");
5775 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5776 checkGLcall("glBindTexture");
5777 /* Copy the bitmap memory into the cursor texture */
5778 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5779 HeapFree(GetProcessHeap(), 0, mem);
5780 checkGLcall("glTexImage2D");
5782 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5783 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5784 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5787 LEAVE_GL();
5789 else
5791 FIXME("A cursor texture was not returned.\n");
5792 This->cursorTexture = 0;
5797 This->xHotSpot = XHotSpot;
5798 This->yHotSpot = YHotSpot;
5799 return WINED3D_OK;
5802 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5804 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5806 This->xScreenSpace = XScreenSpace;
5807 This->yScreenSpace = YScreenSpace;
5809 return;
5813 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5815 BOOL oldVisible = This->bCursorVisible;
5816 POINT pt;
5818 TRACE("(%p) : visible(%d)\n", This, bShow);
5820 if(This->cursorTexture)
5821 This->bCursorVisible = bShow;
5823 * When ShowCursor is first called it should make the cursor appear at the OS's last
5824 * known cursor position. Because of this, some applications just repetitively call
5825 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5827 GetCursorPos(&pt);
5828 This->xScreenSpace = pt.x;
5829 This->yScreenSpace = pt.y;
5831 return oldVisible;
5834 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5836 TRACE("(%p) : state (%u)\n", This, This->state);
5837 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5838 switch (This->state) {
5839 case WINED3D_OK:
5840 return WINED3D_OK;
5841 case WINED3DERR_DEVICELOST:
5843 ResourceList *resourceList = This->resources;
5844 while (NULL != resourceList) {
5845 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5846 return WINED3DERR_DEVICENOTRESET;
5847 resourceList = resourceList->next;
5849 return WINED3DERR_DEVICELOST;
5851 case WINED3DERR_DRIVERINTERNALERROR:
5852 return WINED3DERR_DRIVERINTERNALERROR;
5855 /* Unknown state */
5856 return WINED3DERR_DRIVERINTERNALERROR;
5860 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5862 /** FIXME: Resource tracking needs to be done,
5863 * The closes we can do to this is set the priorities of all managed textures low
5864 * and then reset them.
5865 ***********************************************************/
5866 FIXME("(%p) : stub\n", This);
5867 return WINED3D_OK;
5870 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5871 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5873 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5874 if(surface->Flags & SFLAG_DIBSECTION) {
5875 /* Release the DC */
5876 SelectObject(surface->hDC, surface->dib.holdbitmap);
5877 DeleteDC(surface->hDC);
5878 /* Release the DIB section */
5879 DeleteObject(surface->dib.DIBsection);
5880 surface->dib.bitmap_data = NULL;
5881 surface->resource.allocatedMemory = NULL;
5882 surface->Flags &= ~SFLAG_DIBSECTION;
5884 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5885 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5886 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5887 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5888 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5889 } else {
5890 surface->pow2Width = surface->pow2Height = 1;
5891 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5892 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5894 if(surface->glDescription.textureName) {
5895 ENTER_GL();
5896 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5897 glDeleteTextures(1, &surface->glDescription.textureName);
5898 LEAVE_GL();
5899 surface->glDescription.textureName = 0;
5900 surface->Flags &= ~SFLAG_CLIENT;
5902 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5903 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5904 surface->Flags |= SFLAG_NONPOW2;
5905 } else {
5906 surface->Flags &= ~SFLAG_NONPOW2;
5908 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5909 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5912 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5914 IWineD3DSwapChainImpl *swapchain;
5915 HRESULT hr;
5916 BOOL DisplayModeChanged = FALSE;
5917 WINED3DDISPLAYMODE mode;
5918 TRACE("(%p)\n", This);
5920 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5921 if(FAILED(hr)) {
5922 ERR("Failed to get the first implicit swapchain\n");
5923 return hr;
5926 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5927 * on an existing gl context, so there's no real need for recreation.
5929 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5931 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5933 TRACE("New params:\n");
5934 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5935 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5936 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5937 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5938 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5939 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5940 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5941 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5942 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5943 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5944 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5945 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5946 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5948 /* No special treatment of these parameters. Just store them */
5949 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5950 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5951 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5952 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5954 /* What to do about these? */
5955 if(pPresentationParameters->BackBufferCount != 0 &&
5956 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5957 ERR("Cannot change the back buffer count yet\n");
5959 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5960 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5961 ERR("Cannot change the back buffer format yet\n");
5963 if(pPresentationParameters->hDeviceWindow != NULL &&
5964 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5965 ERR("Cannot change the device window yet\n");
5967 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5968 ERR("What do do about a changed auto depth stencil parameter?\n");
5971 if(pPresentationParameters->Windowed) {
5972 mode.Width = swapchain->orig_width;
5973 mode.Height = swapchain->orig_height;
5974 mode.RefreshRate = 0;
5975 mode.Format = swapchain->presentParms.BackBufferFormat;
5976 } else {
5977 mode.Width = pPresentationParameters->BackBufferWidth;
5978 mode.Height = pPresentationParameters->BackBufferHeight;
5979 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5980 mode.Format = swapchain->presentParms.BackBufferFormat;
5983 /* Should Width == 800 && Height == 0 set 800x600? */
5984 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5985 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5986 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5988 WINED3DVIEWPORT vp;
5989 int i;
5991 vp.X = 0;
5992 vp.Y = 0;
5993 vp.Width = pPresentationParameters->BackBufferWidth;
5994 vp.Height = pPresentationParameters->BackBufferHeight;
5995 vp.MinZ = 0;
5996 vp.MaxZ = 1;
5998 if(!pPresentationParameters->Windowed) {
5999 DisplayModeChanged = TRUE;
6001 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6002 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6004 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6005 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6006 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6009 /* Now set the new viewport */
6010 IWineD3DDevice_SetViewport(iface, &vp);
6013 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6014 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6015 DisplayModeChanged) {
6017 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6018 if(!pPresentationParameters->Windowed) {
6019 IWineD3DDevice_SetFullscreen(iface, TRUE);
6022 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6024 /* Switching out of fullscreen mode? First set the original res, then change the window */
6025 if(pPresentationParameters->Windowed) {
6026 IWineD3DDevice_SetFullscreen(iface, FALSE);
6028 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6031 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6032 return WINED3D_OK;
6035 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6037 /** FIXME: always true at the moment **/
6038 if(!bEnableDialogs) {
6039 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6041 return WINED3D_OK;
6045 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6047 TRACE("(%p) : pParameters %p\n", This, pParameters);
6049 *pParameters = This->createParms;
6050 return WINED3D_OK;
6053 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6054 IWineD3DSwapChain *swapchain;
6055 HRESULT hrc = WINED3D_OK;
6057 TRACE("Relaying to swapchain\n");
6059 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6060 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6061 IWineD3DSwapChain_Release(swapchain);
6063 return;
6066 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6067 IWineD3DSwapChain *swapchain;
6068 HRESULT hrc = WINED3D_OK;
6070 TRACE("Relaying to swapchain\n");
6072 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6073 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6074 IWineD3DSwapChain_Release(swapchain);
6076 return;
6080 /** ********************************************************
6081 * Notification functions
6082 ** ********************************************************/
6083 /** This function must be called in the release of a resource when ref == 0,
6084 * the contents of resource must still be correct,
6085 * any handels to other resource held by the caller must be closed
6086 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6087 *****************************************************/
6088 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6090 ResourceList* resourceList;
6092 TRACE("(%p) : resource %p\n", This, resource);
6093 /* add a new texture to the frot of the linked list */
6094 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6095 resourceList->resource = resource;
6097 /* Get the old head */
6098 resourceList->next = This->resources;
6100 This->resources = resourceList;
6101 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6103 return;
6106 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6108 ResourceList* resourceList = NULL;
6109 ResourceList* previousResourceList = NULL;
6111 TRACE("(%p) : resource %p\n", This, resource);
6113 resourceList = This->resources;
6115 while (resourceList != NULL) {
6116 if(resourceList->resource == resource) break;
6117 previousResourceList = resourceList;
6118 resourceList = resourceList->next;
6121 if (resourceList == NULL) {
6122 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6123 return;
6124 } else {
6125 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6127 /* make sure we don't leave a hole in the list */
6128 if (previousResourceList != NULL) {
6129 previousResourceList->next = resourceList->next;
6130 } else {
6131 This->resources = resourceList->next;
6134 return;
6138 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6140 int counter;
6142 TRACE("(%p) : resource %p\n", This, resource);
6143 switch(IWineD3DResource_GetType(resource)){
6144 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6145 case WINED3DRTYPE_SURFACE: {
6146 unsigned int i;
6148 /* Cleanup any FBO attachments */
6149 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6150 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6151 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6152 set_render_target_fbo(iface, i, NULL);
6153 This->fbo_color_attachments[i] = NULL;
6156 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6157 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6158 set_depth_stencil_fbo(iface, NULL);
6159 This->fbo_depth_attachment = NULL;
6162 break;
6165 case WINED3DRTYPE_TEXTURE:
6166 case WINED3DRTYPE_CUBETEXTURE:
6167 case WINED3DRTYPE_VOLUMETEXTURE:
6168 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6169 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6170 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6171 This->stateBlock->textures[counter] = NULL;
6173 if (This->updateStateBlock != This->stateBlock ){
6174 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6175 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6176 This->updateStateBlock->textures[counter] = NULL;
6180 break;
6181 case WINED3DRTYPE_VOLUME:
6182 /* TODO: nothing really? */
6183 break;
6184 case WINED3DRTYPE_VERTEXBUFFER:
6185 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6187 int streamNumber;
6188 TRACE("Cleaning up stream pointers\n");
6190 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6191 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6192 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6194 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6195 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6196 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6197 This->updateStateBlock->streamSource[streamNumber] = 0;
6198 /* Set changed flag? */
6201 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) */
6202 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6203 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6204 This->stateBlock->streamSource[streamNumber] = 0;
6207 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6208 else { /* This shouldn't happen */
6209 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6211 #endif
6215 break;
6216 case WINED3DRTYPE_INDEXBUFFER:
6217 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6218 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6219 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6220 This->updateStateBlock->pIndexData = NULL;
6223 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6224 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6225 This->stateBlock->pIndexData = NULL;
6229 break;
6230 default:
6231 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6232 break;
6236 /* Remove the resoruce from the resourceStore */
6237 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6239 TRACE("Resource released\n");
6243 /**********************************************************
6244 * IWineD3DDevice VTbl follows
6245 **********************************************************/
6247 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6249 /*** IUnknown methods ***/
6250 IWineD3DDeviceImpl_QueryInterface,
6251 IWineD3DDeviceImpl_AddRef,
6252 IWineD3DDeviceImpl_Release,
6253 /*** IWineD3DDevice methods ***/
6254 IWineD3DDeviceImpl_GetParent,
6255 /*** Creation methods**/
6256 IWineD3DDeviceImpl_CreateVertexBuffer,
6257 IWineD3DDeviceImpl_CreateIndexBuffer,
6258 IWineD3DDeviceImpl_CreateStateBlock,
6259 IWineD3DDeviceImpl_CreateSurface,
6260 IWineD3DDeviceImpl_CreateTexture,
6261 IWineD3DDeviceImpl_CreateVolumeTexture,
6262 IWineD3DDeviceImpl_CreateVolume,
6263 IWineD3DDeviceImpl_CreateCubeTexture,
6264 IWineD3DDeviceImpl_CreateQuery,
6265 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6266 IWineD3DDeviceImpl_CreateVertexDeclaration,
6267 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6268 IWineD3DDeviceImpl_CreateVertexShader,
6269 IWineD3DDeviceImpl_CreatePixelShader,
6270 IWineD3DDeviceImpl_CreatePalette,
6271 /*** Odd functions **/
6272 IWineD3DDeviceImpl_Init3D,
6273 IWineD3DDeviceImpl_Uninit3D,
6274 IWineD3DDeviceImpl_SetFullscreen,
6275 IWineD3DDeviceImpl_SetMultithreaded,
6276 IWineD3DDeviceImpl_EvictManagedResources,
6277 IWineD3DDeviceImpl_GetAvailableTextureMem,
6278 IWineD3DDeviceImpl_GetBackBuffer,
6279 IWineD3DDeviceImpl_GetCreationParameters,
6280 IWineD3DDeviceImpl_GetDeviceCaps,
6281 IWineD3DDeviceImpl_GetDirect3D,
6282 IWineD3DDeviceImpl_GetDisplayMode,
6283 IWineD3DDeviceImpl_SetDisplayMode,
6284 IWineD3DDeviceImpl_GetHWND,
6285 IWineD3DDeviceImpl_SetHWND,
6286 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6287 IWineD3DDeviceImpl_GetRasterStatus,
6288 IWineD3DDeviceImpl_GetSwapChain,
6289 IWineD3DDeviceImpl_Reset,
6290 IWineD3DDeviceImpl_SetDialogBoxMode,
6291 IWineD3DDeviceImpl_SetCursorProperties,
6292 IWineD3DDeviceImpl_SetCursorPosition,
6293 IWineD3DDeviceImpl_ShowCursor,
6294 IWineD3DDeviceImpl_TestCooperativeLevel,
6295 /*** Getters and setters **/
6296 IWineD3DDeviceImpl_SetClipPlane,
6297 IWineD3DDeviceImpl_GetClipPlane,
6298 IWineD3DDeviceImpl_SetClipStatus,
6299 IWineD3DDeviceImpl_GetClipStatus,
6300 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6301 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6302 IWineD3DDeviceImpl_SetDepthStencilSurface,
6303 IWineD3DDeviceImpl_GetDepthStencilSurface,
6304 IWineD3DDeviceImpl_SetFVF,
6305 IWineD3DDeviceImpl_GetFVF,
6306 IWineD3DDeviceImpl_SetGammaRamp,
6307 IWineD3DDeviceImpl_GetGammaRamp,
6308 IWineD3DDeviceImpl_SetIndices,
6309 IWineD3DDeviceImpl_GetIndices,
6310 IWineD3DDeviceImpl_SetBasevertexIndex,
6311 IWineD3DDeviceImpl_SetLight,
6312 IWineD3DDeviceImpl_GetLight,
6313 IWineD3DDeviceImpl_SetLightEnable,
6314 IWineD3DDeviceImpl_GetLightEnable,
6315 IWineD3DDeviceImpl_SetMaterial,
6316 IWineD3DDeviceImpl_GetMaterial,
6317 IWineD3DDeviceImpl_SetNPatchMode,
6318 IWineD3DDeviceImpl_GetNPatchMode,
6319 IWineD3DDeviceImpl_SetPaletteEntries,
6320 IWineD3DDeviceImpl_GetPaletteEntries,
6321 IWineD3DDeviceImpl_SetPixelShader,
6322 IWineD3DDeviceImpl_GetPixelShader,
6323 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6324 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6325 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6326 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6327 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6328 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6329 IWineD3DDeviceImpl_SetRenderState,
6330 IWineD3DDeviceImpl_GetRenderState,
6331 IWineD3DDeviceImpl_SetRenderTarget,
6332 IWineD3DDeviceImpl_GetRenderTarget,
6333 IWineD3DDeviceImpl_SetFrontBackBuffers,
6334 IWineD3DDeviceImpl_SetSamplerState,
6335 IWineD3DDeviceImpl_GetSamplerState,
6336 IWineD3DDeviceImpl_SetScissorRect,
6337 IWineD3DDeviceImpl_GetScissorRect,
6338 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6339 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6340 IWineD3DDeviceImpl_SetStreamSource,
6341 IWineD3DDeviceImpl_GetStreamSource,
6342 IWineD3DDeviceImpl_SetStreamSourceFreq,
6343 IWineD3DDeviceImpl_GetStreamSourceFreq,
6344 IWineD3DDeviceImpl_SetTexture,
6345 IWineD3DDeviceImpl_GetTexture,
6346 IWineD3DDeviceImpl_SetTextureStageState,
6347 IWineD3DDeviceImpl_GetTextureStageState,
6348 IWineD3DDeviceImpl_SetTransform,
6349 IWineD3DDeviceImpl_GetTransform,
6350 IWineD3DDeviceImpl_SetVertexDeclaration,
6351 IWineD3DDeviceImpl_GetVertexDeclaration,
6352 IWineD3DDeviceImpl_SetVertexShader,
6353 IWineD3DDeviceImpl_GetVertexShader,
6354 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6355 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6356 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6357 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6358 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6359 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6360 IWineD3DDeviceImpl_SetViewport,
6361 IWineD3DDeviceImpl_GetViewport,
6362 IWineD3DDeviceImpl_MultiplyTransform,
6363 IWineD3DDeviceImpl_ValidateDevice,
6364 IWineD3DDeviceImpl_ProcessVertices,
6365 /*** State block ***/
6366 IWineD3DDeviceImpl_BeginStateBlock,
6367 IWineD3DDeviceImpl_EndStateBlock,
6368 /*** Scene management ***/
6369 IWineD3DDeviceImpl_BeginScene,
6370 IWineD3DDeviceImpl_EndScene,
6371 IWineD3DDeviceImpl_Present,
6372 IWineD3DDeviceImpl_Clear,
6373 /*** Drawing ***/
6374 IWineD3DDeviceImpl_DrawPrimitive,
6375 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6376 IWineD3DDeviceImpl_DrawPrimitiveUP,
6377 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6378 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6379 IWineD3DDeviceImpl_DrawRectPatch,
6380 IWineD3DDeviceImpl_DrawTriPatch,
6381 IWineD3DDeviceImpl_DeletePatch,
6382 IWineD3DDeviceImpl_ColorFill,
6383 IWineD3DDeviceImpl_UpdateTexture,
6384 IWineD3DDeviceImpl_UpdateSurface,
6385 IWineD3DDeviceImpl_GetFrontBufferData,
6386 /*** object tracking ***/
6387 IWineD3DDeviceImpl_ResourceReleased
6391 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6392 WINED3DRS_ALPHABLENDENABLE ,
6393 WINED3DRS_ALPHAFUNC ,
6394 WINED3DRS_ALPHAREF ,
6395 WINED3DRS_ALPHATESTENABLE ,
6396 WINED3DRS_BLENDOP ,
6397 WINED3DRS_COLORWRITEENABLE ,
6398 WINED3DRS_DESTBLEND ,
6399 WINED3DRS_DITHERENABLE ,
6400 WINED3DRS_FILLMODE ,
6401 WINED3DRS_FOGDENSITY ,
6402 WINED3DRS_FOGEND ,
6403 WINED3DRS_FOGSTART ,
6404 WINED3DRS_LASTPIXEL ,
6405 WINED3DRS_SHADEMODE ,
6406 WINED3DRS_SRCBLEND ,
6407 WINED3DRS_STENCILENABLE ,
6408 WINED3DRS_STENCILFAIL ,
6409 WINED3DRS_STENCILFUNC ,
6410 WINED3DRS_STENCILMASK ,
6411 WINED3DRS_STENCILPASS ,
6412 WINED3DRS_STENCILREF ,
6413 WINED3DRS_STENCILWRITEMASK ,
6414 WINED3DRS_STENCILZFAIL ,
6415 WINED3DRS_TEXTUREFACTOR ,
6416 WINED3DRS_WRAP0 ,
6417 WINED3DRS_WRAP1 ,
6418 WINED3DRS_WRAP2 ,
6419 WINED3DRS_WRAP3 ,
6420 WINED3DRS_WRAP4 ,
6421 WINED3DRS_WRAP5 ,
6422 WINED3DRS_WRAP6 ,
6423 WINED3DRS_WRAP7 ,
6424 WINED3DRS_ZENABLE ,
6425 WINED3DRS_ZFUNC ,
6426 WINED3DRS_ZWRITEENABLE
6429 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6430 WINED3DTSS_ADDRESSW ,
6431 WINED3DTSS_ALPHAARG0 ,
6432 WINED3DTSS_ALPHAARG1 ,
6433 WINED3DTSS_ALPHAARG2 ,
6434 WINED3DTSS_ALPHAOP ,
6435 WINED3DTSS_BUMPENVLOFFSET ,
6436 WINED3DTSS_BUMPENVLSCALE ,
6437 WINED3DTSS_BUMPENVMAT00 ,
6438 WINED3DTSS_BUMPENVMAT01 ,
6439 WINED3DTSS_BUMPENVMAT10 ,
6440 WINED3DTSS_BUMPENVMAT11 ,
6441 WINED3DTSS_COLORARG0 ,
6442 WINED3DTSS_COLORARG1 ,
6443 WINED3DTSS_COLORARG2 ,
6444 WINED3DTSS_COLOROP ,
6445 WINED3DTSS_RESULTARG ,
6446 WINED3DTSS_TEXCOORDINDEX ,
6447 WINED3DTSS_TEXTURETRANSFORMFLAGS
6450 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6451 WINED3DSAMP_ADDRESSU ,
6452 WINED3DSAMP_ADDRESSV ,
6453 WINED3DSAMP_ADDRESSW ,
6454 WINED3DSAMP_BORDERCOLOR ,
6455 WINED3DSAMP_MAGFILTER ,
6456 WINED3DSAMP_MINFILTER ,
6457 WINED3DSAMP_MIPFILTER ,
6458 WINED3DSAMP_MIPMAPLODBIAS ,
6459 WINED3DSAMP_MAXMIPLEVEL ,
6460 WINED3DSAMP_MAXANISOTROPY ,
6461 WINED3DSAMP_SRGBTEXTURE ,
6462 WINED3DSAMP_ELEMENTINDEX
6465 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6466 WINED3DRS_AMBIENT ,
6467 WINED3DRS_AMBIENTMATERIALSOURCE ,
6468 WINED3DRS_CLIPPING ,
6469 WINED3DRS_CLIPPLANEENABLE ,
6470 WINED3DRS_COLORVERTEX ,
6471 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6472 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6473 WINED3DRS_FOGDENSITY ,
6474 WINED3DRS_FOGEND ,
6475 WINED3DRS_FOGSTART ,
6476 WINED3DRS_FOGTABLEMODE ,
6477 WINED3DRS_FOGVERTEXMODE ,
6478 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6479 WINED3DRS_LIGHTING ,
6480 WINED3DRS_LOCALVIEWER ,
6481 WINED3DRS_MULTISAMPLEANTIALIAS ,
6482 WINED3DRS_MULTISAMPLEMASK ,
6483 WINED3DRS_NORMALIZENORMALS ,
6484 WINED3DRS_PATCHEDGESTYLE ,
6485 WINED3DRS_POINTSCALE_A ,
6486 WINED3DRS_POINTSCALE_B ,
6487 WINED3DRS_POINTSCALE_C ,
6488 WINED3DRS_POINTSCALEENABLE ,
6489 WINED3DRS_POINTSIZE ,
6490 WINED3DRS_POINTSIZE_MAX ,
6491 WINED3DRS_POINTSIZE_MIN ,
6492 WINED3DRS_POINTSPRITEENABLE ,
6493 WINED3DRS_RANGEFOGENABLE ,
6494 WINED3DRS_SPECULARMATERIALSOURCE ,
6495 WINED3DRS_TWEENFACTOR ,
6496 WINED3DRS_VERTEXBLEND
6499 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6500 WINED3DTSS_TEXCOORDINDEX ,
6501 WINED3DTSS_TEXTURETRANSFORMFLAGS
6504 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6505 WINED3DSAMP_DMAPOFFSET
6508 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6509 DWORD rep = StateTable[state].representative;
6510 DWORD idx;
6511 BYTE shift;
6512 UINT i;
6513 WineD3DContext *context;
6515 if(!rep) return;
6516 for(i = 0; i < This->numContexts; i++) {
6517 context = This->contexts[i];
6518 if(isStateDirty(context, rep)) continue;
6520 context->dirtyArray[context->numDirtyEntries++] = rep;
6521 idx = rep >> 5;
6522 shift = rep & 0x1f;
6523 context->isStateDirty[idx] |= (1 << shift);