push 735ae92a6c6e93f1d42ab1ae3fd17e22de57873e
[wine/hacks.git] / dlls / wined3d / device.c
blob3964bf2ed08881b41c9f6aef3b4587f6c7f03f38
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 /* 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");
226 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
227 if (This->haveHardwareCursor) This->haveHardwareCursor = FALSE;
229 IWineD3D_Release(This->wineD3D);
230 This->wineD3D = NULL;
231 HeapFree(GetProcessHeap(), 0, This);
232 TRACE("Freed device %p\n", This);
233 This = NULL;
235 return refCount;
238 /**********************************************************
239 * IWineD3DDevice implementation follows
240 **********************************************************/
241 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
243 *pParent = This->parent;
244 IUnknown_AddRef(This->parent);
245 return WINED3D_OK;
248 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
249 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
250 GLenum error, glUsage;
251 DWORD vboUsage = object->resource.usage;
252 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
253 WARN("Creating a vbo failed once, not trying again\n");
254 return;
257 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
259 ENTER_GL();
260 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
261 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
263 /* Make sure that the gl error is cleared. Do not use checkGLcall
264 * here because checkGLcall just prints a fixme and continues. However,
265 * if an error during VBO creation occurs we can fall back to non-vbo operation
266 * with full functionality(but performance loss)
268 while(glGetError() != GL_NO_ERROR);
270 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
271 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
272 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
273 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
274 * to check if the rhw and color values are in the correct format.
277 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
278 error = glGetError();
279 if(object->vbo == 0 || error != GL_NO_ERROR) {
280 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
281 goto error;
284 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
285 error = glGetError();
286 if(error != GL_NO_ERROR) {
287 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
288 goto error;
291 /* Don't use static, because dx apps tend to update the buffer
292 * quite often even if they specify 0 usage. Because we always keep the local copy
293 * we never read from the vbo and can create a write only opengl buffer.
295 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
296 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
297 case WINED3DUSAGE_DYNAMIC:
298 TRACE("Gl usage = GL_STREAM_DRAW\n");
299 glUsage = GL_STREAM_DRAW_ARB;
300 break;
301 case WINED3DUSAGE_WRITEONLY:
302 default:
303 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
304 glUsage = GL_DYNAMIC_DRAW_ARB;
305 break;
308 /* Reserve memory for the buffer. The amount of data won't change
309 * so we are safe with calling glBufferData once with a NULL ptr and
310 * calling glBufferSubData on updates
312 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
313 error = glGetError();
314 if(error != GL_NO_ERROR) {
315 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
316 goto error;
319 LEAVE_GL();
321 return;
322 error:
323 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
324 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
325 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
326 object->vbo = 0;
327 object->Flags |= VBFLAG_VBOCREATEFAIL;
328 LEAVE_GL();
329 return;
332 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
333 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
334 IUnknown *parent) {
335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
336 IWineD3DVertexBufferImpl *object;
337 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
338 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
339 BOOL conv;
341 if(Size == 0) {
342 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
343 *ppVertexBuffer = NULL;
344 return WINED3DERR_INVALIDCALL;
347 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
349 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
350 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
352 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
353 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
355 object->fvf = FVF;
357 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
358 * drawStridedFast (half-life 2).
360 * Basically converting the vertices in the buffer is quite expensive, and observations
361 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
362 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
364 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
365 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
366 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
367 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
368 * dx7 apps.
369 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
370 * more. In this call we can convert dx7 buffers too.
372 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
373 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
374 (dxVersion > 7 || !conv) ) {
375 CreateVBO(object);
377 return WINED3D_OK;
380 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
381 GLenum error, glUsage;
382 TRACE("Creating VBO for Index Buffer %p\n", object);
384 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
385 * restored on the next draw
387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
389 ENTER_GL();
390 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
391 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
393 while(glGetError());
395 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
396 error = glGetError();
397 if(error != GL_NO_ERROR || object->vbo == 0) {
398 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
399 goto out;
402 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
403 error = glGetError();
404 if(error != GL_NO_ERROR) {
405 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
406 goto out;
409 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
410 * copy no readback will be needed
412 glUsage = GL_STATIC_DRAW_ARB;
413 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
414 error = glGetError();
415 if(error != GL_NO_ERROR) {
416 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
417 goto out;
419 LEAVE_GL();
420 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
421 return;
423 out:
424 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
425 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
426 LEAVE_GL();
427 object->vbo = 0;
430 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
431 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
432 HANDLE *sharedHandle, IUnknown *parent) {
433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
434 IWineD3DIndexBufferImpl *object;
435 TRACE("(%p) Creating index buffer\n", This);
437 /* Allocate the storage for the device */
438 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
440 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
441 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
444 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
445 CreateIndexBufferVBO(This, object);
448 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
449 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
450 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
452 return WINED3D_OK;
455 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
458 IWineD3DStateBlockImpl *object;
459 int i, j;
460 HRESULT temp_result;
462 D3DCREATEOBJECTINSTANCE(object, StateBlock)
463 object->blockType = Type;
465 for(i = 0; i < LIGHTMAP_SIZE; i++) {
466 list_init(&object->lightMap[i]);
469 /* Special case - Used during initialization to produce a placeholder stateblock
470 so other functions called can update a state block */
471 if (Type == WINED3DSBT_INIT) {
472 /* Don't bother increasing the reference count otherwise a device will never
473 be freed due to circular dependencies */
474 return WINED3D_OK;
477 temp_result = allocate_shader_constants(object);
478 if (WINED3D_OK != temp_result)
479 return temp_result;
481 /* Otherwise, might as well set the whole state block to the appropriate values */
482 if (This->stateBlock != NULL)
483 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
484 else
485 memset(object->streamFreq, 1, sizeof(object->streamFreq));
487 /* Reset the ref and type after kludging it */
488 object->wineD3DDevice = This;
489 object->ref = 1;
490 object->blockType = Type;
492 TRACE("Updating changed flags appropriate for type %d\n", Type);
494 if (Type == WINED3DSBT_ALL) {
496 TRACE("ALL => Pretend everything has changed\n");
497 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
499 /* Lights are not part of the changed / set structure */
500 for(j = 0; j < LIGHTMAP_SIZE; j++) {
501 struct list *e;
502 LIST_FOR_EACH(e, &object->lightMap[j]) {
503 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
504 light->changed = TRUE;
505 light->enabledChanged = TRUE;
508 } else if (Type == WINED3DSBT_PIXELSTATE) {
510 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
511 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
513 object->changed.pixelShader = TRUE;
515 /* Pixel Shader Constants */
516 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
517 object->changed.pixelShaderConstantsF[i] = TRUE;
518 for (i = 0; i < MAX_CONST_B; ++i)
519 object->changed.pixelShaderConstantsB[i] = TRUE;
520 for (i = 0; i < MAX_CONST_I; ++i)
521 object->changed.pixelShaderConstantsI[i] = TRUE;
523 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
524 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
526 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
527 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
528 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
531 for (j = 0 ; j < 16; j++) {
532 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
534 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
538 } else if (Type == WINED3DSBT_VERTEXSTATE) {
540 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
541 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
543 object->changed.vertexShader = TRUE;
545 /* Vertex Shader Constants */
546 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
547 object->changed.vertexShaderConstantsF[i] = TRUE;
548 for (i = 0; i < MAX_CONST_B; ++i)
549 object->changed.vertexShaderConstantsB[i] = TRUE;
550 for (i = 0; i < MAX_CONST_I; ++i)
551 object->changed.vertexShaderConstantsI[i] = TRUE;
553 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
554 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
556 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
557 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
558 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
561 for (j = 0 ; j < 16; j++){
562 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
563 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
567 for(j = 0; j < LIGHTMAP_SIZE; j++) {
568 struct list *e;
569 LIST_FOR_EACH(e, &object->lightMap[j]) {
570 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
571 light->changed = TRUE;
572 light->enabledChanged = TRUE;
575 } else {
576 FIXME("Unrecognized state block type %d\n", Type);
579 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
580 return WINED3D_OK;
583 /* ************************************
584 MSDN:
585 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
587 Discard
588 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
590 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.
592 ******************************** */
594 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) {
595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
596 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
597 unsigned int pow2Width, pow2Height;
598 unsigned int Size = 1;
599 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
600 TRACE("(%p) Create surface\n",This);
602 /** FIXME: Check ranges on the inputs are valid
603 * MSDN
604 * MultisampleQuality
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
609 * must all match.
610 *******************************/
614 * TODO: Discard MSDN
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality < 0) {
625 FIXME("Invalid multisample level %d\n", MultisampleQuality);
626 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
629 if(MultisampleQuality > 0) {
630 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
631 MultisampleQuality=0;
634 /** FIXME: Check that the format is supported
635 * by the device.
636 *******************************/
638 /* Non-power2 support */
639 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
640 pow2Width = Width;
641 pow2Height = Height;
642 } else {
643 /* Find the nearest pow2 match */
644 pow2Width = pow2Height = 1;
645 while (pow2Width < Width) pow2Width <<= 1;
646 while (pow2Height < Height) pow2Height <<= 1;
649 if (pow2Width > Width || pow2Height > Height) {
650 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
651 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
652 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
653 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
654 This, Width, Height);
655 return WINED3DERR_NOTAVAILABLE;
659 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
660 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
661 * space!
662 *********************************/
663 if (WINED3DFMT_UNKNOWN == Format) {
664 Size = 0;
665 } else if (Format == WINED3DFMT_DXT1) {
666 /* DXT1 is half byte per pixel */
667 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
669 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
670 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
671 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
672 } else {
673 /* The pitch is a multiple of 4 bytes */
674 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
675 Size *= Height;
678 /** Create and initialise the surface resource **/
679 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
680 /* "Standalone" surface */
681 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
683 object->currentDesc.Width = Width;
684 object->currentDesc.Height = Height;
685 object->currentDesc.MultiSampleType = MultiSample;
686 object->currentDesc.MultiSampleQuality = MultisampleQuality;
688 /* Setup some glformat defaults */
689 object->glDescription.glFormat = tableEntry->glFormat;
690 object->glDescription.glFormatInternal = tableEntry->glInternal;
691 object->glDescription.glType = tableEntry->glType;
693 object->glDescription.textureName = 0;
694 object->glDescription.level = Level;
695 object->glDescription.target = GL_TEXTURE_2D;
697 /* Internal data */
698 object->pow2Width = pow2Width;
699 object->pow2Height = pow2Height;
701 /* Flags */
702 object->Flags = SFLAG_DYNLOCK;
703 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
704 object->Flags |= Discard ? SFLAG_DISCARD : 0;
705 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
706 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
709 if (WINED3DFMT_UNKNOWN != Format) {
710 object->bytesPerPixel = tableEntry->bpp;
711 } else {
712 object->bytesPerPixel = 0;
715 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
717 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
719 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
720 * this function is too deep to need to care about things like this.
721 * Levels need to be checked too, and possibly Type since they all affect what can be done.
722 * ****************************************/
723 switch(Pool) {
724 case WINED3DPOOL_SCRATCH:
725 if(!Lockable)
726 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
727 "which are mutually exclusive, setting lockable to TRUE\n");
728 Lockable = TRUE;
729 break;
730 case WINED3DPOOL_SYSTEMMEM:
731 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
732 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
733 case WINED3DPOOL_MANAGED:
734 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
735 "Usage of DYNAMIC which are mutually exclusive, not doing "
736 "anything just telling you.\n");
737 break;
738 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
739 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
740 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
741 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
742 break;
743 default:
744 FIXME("(%p) Unknown pool %d\n", This, Pool);
745 break;
748 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
749 FIXME("Trying to create a render target that isn't in the default pool\n");
752 /* mark the texture as dirty so that it gets loaded first time around*/
753 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
754 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
755 This, Width, Height, Format, debug_d3dformat(Format),
756 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
758 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
759 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
760 This->ddraw_primary = (IWineD3DSurface *) object;
762 /* Look at the implementation and set the correct Vtable */
763 switch(Impl) {
764 case SURFACE_OPENGL:
765 /* Nothing to do, it's set already */
766 break;
768 case SURFACE_GDI:
769 object->lpVtbl = &IWineGDISurface_Vtbl;
770 break;
772 default:
773 /* To be sure to catch this */
774 ERR("Unknown requested surface implementation %d!\n", Impl);
775 IWineD3DSurface_Release((IWineD3DSurface *) object);
776 return WINED3DERR_INVALIDCALL;
779 list_init(&object->renderbuffers);
781 /* Call the private setup routine */
782 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
786 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
787 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
788 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
789 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
792 IWineD3DTextureImpl *object;
793 unsigned int i;
794 UINT tmpW;
795 UINT tmpH;
796 HRESULT hr;
797 unsigned int pow2Width;
798 unsigned int pow2Height;
801 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
802 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
803 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
805 /* TODO: It should only be possible to create textures for formats
806 that are reported as supported */
807 if (WINED3DFMT_UNKNOWN >= Format) {
808 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
809 return WINED3DERR_INVALIDCALL;
812 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
813 D3DINITIALIZEBASETEXTURE(object->baseTexture);
814 object->width = Width;
815 object->height = Height;
817 /** Non-power2 support **/
818 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
819 pow2Width = Width;
820 pow2Height = Height;
821 } else {
822 /* Find the nearest pow2 match */
823 pow2Width = pow2Height = 1;
824 while (pow2Width < Width) pow2Width <<= 1;
825 while (pow2Height < Height) pow2Height <<= 1;
828 /** FIXME: add support for real non-power-two if it's provided by the video card **/
829 /* Precalculated scaling for 'faked' non power of two texture coords */
830 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
831 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
832 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
834 /* Calculate levels for mip mapping */
835 if (Levels == 0) {
836 TRACE("calculating levels %d\n", object->baseTexture.levels);
837 object->baseTexture.levels++;
838 tmpW = Width;
839 tmpH = Height;
840 while (tmpW > 1 || tmpH > 1) {
841 tmpW = max(1, tmpW >> 1);
842 tmpH = max(1, tmpH >> 1);
843 object->baseTexture.levels++;
845 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
848 /* Generate all the surfaces */
849 tmpW = Width;
850 tmpH = Height;
851 for (i = 0; i < object->baseTexture.levels; i++)
853 /* use the callback to create the texture surface */
854 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
855 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
856 FIXME("Failed to create surface %p\n", object);
857 /* clean up */
858 object->surfaces[i] = NULL;
859 IWineD3DTexture_Release((IWineD3DTexture *)object);
861 *ppTexture = NULL;
862 return hr;
865 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
866 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
867 /* calculate the next mipmap level */
868 tmpW = max(1, tmpW >> 1);
869 tmpH = max(1, tmpH >> 1);
872 TRACE("(%p) : Created texture %p\n", This, object);
873 return WINED3D_OK;
876 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
877 UINT Width, UINT Height, UINT Depth,
878 UINT Levels, DWORD Usage,
879 WINED3DFORMAT Format, WINED3DPOOL Pool,
880 IWineD3DVolumeTexture **ppVolumeTexture,
881 HANDLE *pSharedHandle, IUnknown *parent,
882 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
885 IWineD3DVolumeTextureImpl *object;
886 unsigned int i;
887 UINT tmpW;
888 UINT tmpH;
889 UINT tmpD;
891 /* TODO: It should only be possible to create textures for formats
892 that are reported as supported */
893 if (WINED3DFMT_UNKNOWN >= Format) {
894 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
895 return WINED3DERR_INVALIDCALL;
898 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
899 D3DINITIALIZEBASETEXTURE(object->baseTexture);
901 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
902 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
904 object->width = Width;
905 object->height = Height;
906 object->depth = Depth;
908 /* Calculate levels for mip mapping */
909 if (Levels == 0) {
910 object->baseTexture.levels++;
911 tmpW = Width;
912 tmpH = Height;
913 tmpD = Depth;
914 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
915 tmpW = max(1, tmpW >> 1);
916 tmpH = max(1, tmpH >> 1);
917 tmpD = max(1, tmpD >> 1);
918 object->baseTexture.levels++;
920 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
923 /* Generate all the surfaces */
924 tmpW = Width;
925 tmpH = Height;
926 tmpD = Depth;
928 for (i = 0; i < object->baseTexture.levels; i++)
930 HRESULT hr;
931 /* Create the volume */
932 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
933 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
935 if(FAILED(hr)) {
936 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
937 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
938 *ppVolumeTexture = NULL;
939 return hr;
942 /* Set its container to this object */
943 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
945 /* calcualte the next mipmap level */
946 tmpW = max(1, tmpW >> 1);
947 tmpH = max(1, tmpH >> 1);
948 tmpD = max(1, tmpD >> 1);
951 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
952 TRACE("(%p) : Created volume texture %p\n", This, object);
953 return WINED3D_OK;
956 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
957 UINT Width, UINT Height, UINT Depth,
958 DWORD Usage,
959 WINED3DFORMAT Format, WINED3DPOOL Pool,
960 IWineD3DVolume** ppVolume,
961 HANDLE* pSharedHandle, IUnknown *parent) {
963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
964 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
965 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
967 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
969 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
970 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
972 object->currentDesc.Width = Width;
973 object->currentDesc.Height = Height;
974 object->currentDesc.Depth = Depth;
975 object->bytesPerPixel = formatDesc->bpp;
977 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
978 object->lockable = TRUE;
979 object->locked = FALSE;
980 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
981 object->dirty = TRUE;
983 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
986 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
987 UINT Levels, DWORD Usage,
988 WINED3DFORMAT Format, WINED3DPOOL Pool,
989 IWineD3DCubeTexture **ppCubeTexture,
990 HANDLE *pSharedHandle, IUnknown *parent,
991 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
994 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
995 unsigned int i, j;
996 UINT tmpW;
997 HRESULT hr;
998 unsigned int pow2EdgeLength = EdgeLength;
1000 /* TODO: It should only be possible to create textures for formats
1001 that are reported as supported */
1002 if (WINED3DFMT_UNKNOWN >= Format) {
1003 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1004 return WINED3DERR_INVALIDCALL;
1007 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1008 WARN("(%p) : Tried to create not supported cube texture\n", This);
1009 return WINED3DERR_INVALIDCALL;
1012 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1013 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1015 TRACE("(%p) Create Cube Texture\n", This);
1017 /** Non-power2 support **/
1019 /* Find the nearest pow2 match */
1020 pow2EdgeLength = 1;
1021 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1023 object->edgeLength = EdgeLength;
1024 /* TODO: support for native non-power 2 */
1025 /* Precalculated scaling for 'faked' non power of two texture coords */
1026 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1028 /* Calculate levels for mip mapping */
1029 if (Levels == 0) {
1030 object->baseTexture.levels++;
1031 tmpW = EdgeLength;
1032 while (tmpW > 1) {
1033 tmpW = max(1, tmpW >> 1);
1034 object->baseTexture.levels++;
1036 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1039 /* Generate all the surfaces */
1040 tmpW = EdgeLength;
1041 for (i = 0; i < object->baseTexture.levels; i++) {
1043 /* Create the 6 faces */
1044 for (j = 0; j < 6; j++) {
1046 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1047 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1049 if(hr!= WINED3D_OK) {
1050 /* clean up */
1051 int k;
1052 int l;
1053 for (l = 0; l < j; l++) {
1054 IWineD3DSurface_Release(object->surfaces[j][i]);
1056 for (k = 0; k < i; k++) {
1057 for (l = 0; l < 6; l++) {
1058 IWineD3DSurface_Release(object->surfaces[l][j]);
1062 FIXME("(%p) Failed to create surface\n",object);
1063 HeapFree(GetProcessHeap(),0,object);
1064 *ppCubeTexture = NULL;
1065 return hr;
1067 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1068 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1070 tmpW = max(1, tmpW >> 1);
1073 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1074 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1075 return WINED3D_OK;
1078 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1080 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1081 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1083 /* Just a check to see if we support this type of query */
1084 switch(Type) {
1085 case WINED3DQUERYTYPE_OCCLUSION:
1086 TRACE("(%p) occlusion query\n", This);
1087 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1088 hr = WINED3D_OK;
1089 else
1090 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1091 break;
1093 case WINED3DQUERYTYPE_EVENT:
1094 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1095 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1096 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1098 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1100 hr = WINED3D_OK;
1101 break;
1103 case WINED3DQUERYTYPE_VCACHE:
1104 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1105 case WINED3DQUERYTYPE_VERTEXSTATS:
1106 case WINED3DQUERYTYPE_TIMESTAMP:
1107 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1108 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1109 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1110 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1111 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1112 case WINED3DQUERYTYPE_PIXELTIMINGS:
1113 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1114 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1115 default:
1116 FIXME("(%p) Unhandled query type %d\n", This, Type);
1118 if(NULL == ppQuery || hr != WINED3D_OK) {
1119 return hr;
1122 D3DCREATEOBJECTINSTANCE(object, Query)
1123 object->type = Type;
1124 /* allocated the 'extended' data based on the type of query requested */
1125 switch(Type){
1126 case WINED3DQUERYTYPE_OCCLUSION:
1127 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1128 TRACE("(%p) Allocating data for an occlusion query\n", This);
1129 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1130 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1131 break;
1133 case WINED3DQUERYTYPE_EVENT:
1134 /* TODO: GL_APPLE_fence */
1135 if(GL_SUPPORT(APPLE_FENCE)) {
1136 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1137 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1138 checkGLcall("glGenFencesAPPLE");
1139 } else if(GL_SUPPORT(NV_FENCE)) {
1140 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1141 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1142 checkGLcall("glGenFencesNV");
1144 break;
1146 case WINED3DQUERYTYPE_VCACHE:
1147 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1148 case WINED3DQUERYTYPE_VERTEXSTATS:
1149 case WINED3DQUERYTYPE_TIMESTAMP:
1150 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1151 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1152 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1153 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1154 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1155 case WINED3DQUERYTYPE_PIXELTIMINGS:
1156 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1157 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1158 default:
1159 object->extendedData = 0;
1160 FIXME("(%p) Unhandled query type %d\n",This , Type);
1162 TRACE("(%p) : Created Query %p\n", This, object);
1163 return WINED3D_OK;
1166 /*****************************************************************************
1167 * IWineD3DDeviceImpl_SetupFullscreenWindow
1169 * Helper function that modifies a HWND's Style and ExStyle for proper
1170 * fullscreen use.
1172 * Params:
1173 * iface: Pointer to the IWineD3DDevice interface
1174 * window: Window to setup
1176 *****************************************************************************/
1177 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1180 LONG style, exStyle;
1181 /* Don't do anything if an original style is stored.
1182 * That shouldn't happen
1184 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1185 if (This->style || This->exStyle) {
1186 ERR("(%p): Want to change the window parameters of HWND %p, but "
1187 "another style is stored for restoration afterwards\n", This, window);
1190 /* Get the parameters and save them */
1191 style = GetWindowLongW(window, GWL_STYLE);
1192 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1193 This->style = style;
1194 This->exStyle = exStyle;
1196 /* Filter out window decorations */
1197 style &= ~WS_CAPTION;
1198 style &= ~WS_THICKFRAME;
1199 exStyle &= ~WS_EX_WINDOWEDGE;
1200 exStyle &= ~WS_EX_CLIENTEDGE;
1202 /* Make sure the window is managed, otherwise we won't get keyboard input */
1203 style |= WS_POPUP | WS_SYSMENU;
1205 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1206 This->style, This->exStyle, style, exStyle);
1208 SetWindowLongW(window, GWL_STYLE, style);
1209 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1211 /* Inform the window about the update. */
1212 SetWindowPos(window, HWND_TOP, 0, 0,
1213 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1214 ShowWindow(window, SW_NORMAL);
1217 /*****************************************************************************
1218 * IWineD3DDeviceImpl_RestoreWindow
1220 * Helper function that restores a windows' properties when taking it out
1221 * of fullscreen mode
1223 * Params:
1224 * iface: Pointer to the IWineD3DDevice interface
1225 * window: Window to setup
1227 *****************************************************************************/
1228 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1231 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1232 * switch, do nothing
1234 if (!This->style && !This->exStyle) return;
1236 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1237 This, window, This->style, This->exStyle);
1239 SetWindowLongW(window, GWL_STYLE, This->style);
1240 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1242 /* Delete the old values */
1243 This->style = 0;
1244 This->exStyle = 0;
1246 /* Inform the window about the update */
1247 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1248 0, 0, 0, 0, /* Pos, Size, ignored */
1249 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1252 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1253 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1254 IUnknown* parent,
1255 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1256 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1259 HDC hDc;
1260 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1261 HRESULT hr = WINED3D_OK;
1262 IUnknown *bufferParent;
1263 Display *display;
1265 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1267 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1268 * does a device hold a reference to a swap chain giving them a lifetime of the device
1269 * or does the swap chain notify the device of its destruction.
1270 *******************************/
1272 /* Check the params */
1273 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1274 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1275 return WINED3DERR_INVALIDCALL;
1276 } else if (pPresentationParameters->BackBufferCount > 1) {
1277 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");
1280 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1282 /*********************
1283 * Lookup the window Handle and the relating X window handle
1284 ********************/
1286 /* Setup hwnd we are using, plus which display this equates to */
1287 object->win_handle = pPresentationParameters->hDeviceWindow;
1288 if (!object->win_handle) {
1289 object->win_handle = This->createParms.hFocusWindow;
1292 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1293 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1294 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1295 return WINED3DERR_NOTAVAILABLE;
1297 hDc = GetDC(object->win_handle);
1298 display = get_display(hDc);
1299 ReleaseDC(object->win_handle, hDc);
1300 TRACE("Using a display of %p %p\n", display, hDc);
1302 if (NULL == display || NULL == hDc) {
1303 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1304 return WINED3DERR_NOTAVAILABLE;
1307 if (object->win == 0) {
1308 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1309 return WINED3DERR_NOTAVAILABLE;
1312 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1313 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1314 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1316 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1317 * then the corresponding dimension of the client area of the hDeviceWindow
1318 * (or the focus window, if hDeviceWindow is NULL) is taken.
1319 **********************/
1321 if (pPresentationParameters->Windowed &&
1322 ((pPresentationParameters->BackBufferWidth == 0) ||
1323 (pPresentationParameters->BackBufferHeight == 0))) {
1325 RECT Rect;
1326 GetClientRect(object->win_handle, &Rect);
1328 if (pPresentationParameters->BackBufferWidth == 0) {
1329 pPresentationParameters->BackBufferWidth = Rect.right;
1330 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1332 if (pPresentationParameters->BackBufferHeight == 0) {
1333 pPresentationParameters->BackBufferHeight = Rect.bottom;
1334 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1338 /* Put the correct figures in the presentation parameters */
1339 TRACE("Copying across presentation parameters\n");
1340 object->presentParms = *pPresentationParameters;
1342 TRACE("calling rendertarget CB\n");
1343 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1344 parent,
1345 object->presentParms.BackBufferWidth,
1346 object->presentParms.BackBufferHeight,
1347 object->presentParms.BackBufferFormat,
1348 object->presentParms.MultiSampleType,
1349 object->presentParms.MultiSampleQuality,
1350 TRUE /* Lockable */,
1351 &object->frontBuffer,
1352 NULL /* pShared (always null)*/);
1353 if (object->frontBuffer != NULL) {
1354 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1355 } else {
1356 ERR("Failed to create the front buffer\n");
1357 goto error;
1361 * Create an opengl context for the display visual
1362 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1363 * use different properties after that point in time. FIXME: How to handle when requested format
1364 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1365 * it chooses is identical to the one already being used!
1366 **********************************/
1367 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1369 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1370 if(!object->context) {
1372 object->num_contexts = 1;
1374 ENTER_GL();
1375 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1376 LEAVE_GL();
1378 if (!object->context) {
1379 ERR("Failed to create a new context\n");
1380 hr = WINED3DERR_NOTAVAILABLE;
1381 goto error;
1382 } else {
1383 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1384 object->win_handle, object->context[0]->glCtx, object->win);
1387 /*********************
1388 * Windowed / Fullscreen
1389 *******************/
1392 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1393 * so we should really check to see if there is a fullscreen swapchain already
1394 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1395 **************************************/
1397 if (!pPresentationParameters->Windowed) {
1399 DEVMODEW devmode;
1400 HDC hdc;
1401 int bpp = 0;
1402 RECT clip_rc;
1404 /* Get info on the current display setup */
1405 hdc = GetDC(0);
1406 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1407 ReleaseDC(0, hdc);
1409 /* Change the display settings */
1410 memset(&devmode, 0, sizeof(DEVMODEW));
1411 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1412 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1413 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1414 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1415 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1416 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1418 /* For GetDisplayMode */
1419 This->ddraw_width = devmode.dmPelsWidth;
1420 This->ddraw_height = devmode.dmPelsHeight;
1421 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1423 IWineD3DDevice_SetFullscreen(iface, TRUE);
1425 /* And finally clip mouse to our screen */
1426 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1427 ClipCursor(&clip_rc);
1430 /*********************
1431 * Create the back, front and stencil buffers
1432 *******************/
1433 if(object->presentParms.BackBufferCount > 0) {
1434 int i;
1436 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1437 if(!object->backBuffer) {
1438 ERR("Out of memory\n");
1439 hr = E_OUTOFMEMORY;
1440 goto error;
1443 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1444 TRACE("calling rendertarget CB\n");
1445 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1446 parent,
1447 object->presentParms.BackBufferWidth,
1448 object->presentParms.BackBufferHeight,
1449 object->presentParms.BackBufferFormat,
1450 object->presentParms.MultiSampleType,
1451 object->presentParms.MultiSampleQuality,
1452 TRUE /* Lockable */,
1453 &object->backBuffer[i],
1454 NULL /* pShared (always null)*/);
1455 if(hr == WINED3D_OK && object->backBuffer[i]) {
1456 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1457 } else {
1458 ERR("Cannot create new back buffer\n");
1459 goto error;
1461 ENTER_GL();
1462 glDrawBuffer(GL_BACK);
1463 checkGLcall("glDrawBuffer(GL_BACK)");
1464 LEAVE_GL();
1466 } else {
1467 object->backBuffer = NULL;
1469 /* Single buffering - draw to front buffer */
1470 ENTER_GL();
1471 glDrawBuffer(GL_FRONT);
1472 checkGLcall("glDrawBuffer(GL_FRONT)");
1473 LEAVE_GL();
1476 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1477 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1478 TRACE("Creating depth stencil buffer\n");
1479 if (This->depthStencilBuffer == NULL ) {
1480 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1481 parent,
1482 object->presentParms.BackBufferWidth,
1483 object->presentParms.BackBufferHeight,
1484 object->presentParms.AutoDepthStencilFormat,
1485 object->presentParms.MultiSampleType,
1486 object->presentParms.MultiSampleQuality,
1487 FALSE /* FIXME: Discard */,
1488 &This->depthStencilBuffer,
1489 NULL /* pShared (always null)*/ );
1490 if (This->depthStencilBuffer != NULL)
1491 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1494 /** TODO: A check on width, height and multisample types
1495 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1496 ****************************/
1497 object->wantsDepthStencilBuffer = TRUE;
1498 } else {
1499 object->wantsDepthStencilBuffer = FALSE;
1502 TRACE("Created swapchain %p\n", object);
1503 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1504 return WINED3D_OK;
1506 error:
1507 if (object->backBuffer) {
1508 int i;
1509 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1510 if(object->backBuffer[i]) {
1511 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1512 IUnknown_Release(bufferParent); /* once for the get parent */
1513 if (IUnknown_Release(bufferParent) > 0) {
1514 FIXME("(%p) Something's still holding the back buffer\n",This);
1518 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1519 object->backBuffer = NULL;
1521 if(object->context) {
1522 DestroyContext(This, object->context[0]);
1524 if(object->frontBuffer) {
1525 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1526 IUnknown_Release(bufferParent); /* once for the get parent */
1527 if (IUnknown_Release(bufferParent) > 0) {
1528 FIXME("(%p) Something's still holding the front buffer\n",This);
1531 HeapFree(GetProcessHeap(), 0, object);
1532 return hr;
1535 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1536 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 TRACE("(%p)\n", This);
1540 return This->NumberOfSwapChains;
1543 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1545 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1547 if(iSwapChain < This->NumberOfSwapChains) {
1548 *pSwapChain = This->swapchains[iSwapChain];
1549 IWineD3DSwapChain_AddRef(*pSwapChain);
1550 TRACE("(%p) returning %p\n", This, *pSwapChain);
1551 return WINED3D_OK;
1552 } else {
1553 TRACE("Swapchain out of range\n");
1554 *pSwapChain = NULL;
1555 return WINED3DERR_INVALIDCALL;
1559 /*****
1560 * Vertex Declaration
1561 *****/
1562 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1563 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1565 IWineD3DVertexDeclarationImpl *object = NULL;
1566 HRESULT hr = WINED3D_OK;
1568 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1569 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1571 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1573 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1575 return hr;
1578 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1580 unsigned int idx, idx2;
1581 unsigned int offset;
1582 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1583 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1584 BOOL has_blend_idx = has_blend &&
1585 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1586 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1587 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1588 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1589 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1590 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1591 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1593 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1594 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1596 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1597 WINED3DVERTEXELEMENT *elements = NULL;
1599 unsigned int size;
1600 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1601 if (has_blend_idx) num_blends--;
1603 /* Compute declaration size */
1604 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1605 has_psize + has_diffuse + has_specular + num_textures + 1;
1607 /* convert the declaration */
1608 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1609 if (!elements)
1610 return 0;
1612 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1613 idx = 0;
1614 if (has_pos) {
1615 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1616 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1617 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1619 else {
1620 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1621 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1623 elements[idx].UsageIndex = 0;
1624 idx++;
1626 if (has_blend && (num_blends > 0)) {
1627 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1628 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1629 else
1630 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1631 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1632 elements[idx].UsageIndex = 0;
1633 idx++;
1635 if (has_blend_idx) {
1636 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1637 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1638 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1639 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1640 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1641 else
1642 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1643 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1644 elements[idx].UsageIndex = 0;
1645 idx++;
1647 if (has_normal) {
1648 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1649 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1650 elements[idx].UsageIndex = 0;
1651 idx++;
1653 if (has_psize) {
1654 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1655 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1656 elements[idx].UsageIndex = 0;
1657 idx++;
1659 if (has_diffuse) {
1660 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1661 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1662 elements[idx].UsageIndex = 0;
1663 idx++;
1665 if (has_specular) {
1666 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1667 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1668 elements[idx].UsageIndex = 1;
1669 idx++;
1671 for (idx2 = 0; idx2 < num_textures; idx2++) {
1672 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1673 switch (numcoords) {
1674 case WINED3DFVF_TEXTUREFORMAT1:
1675 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1676 break;
1677 case WINED3DFVF_TEXTUREFORMAT2:
1678 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1679 break;
1680 case WINED3DFVF_TEXTUREFORMAT3:
1681 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1682 break;
1683 case WINED3DFVF_TEXTUREFORMAT4:
1684 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1685 break;
1687 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1688 elements[idx].UsageIndex = idx2;
1689 idx++;
1692 /* Now compute offsets, and initialize the rest of the fields */
1693 for (idx = 0, offset = 0; idx < size-1; idx++) {
1694 elements[idx].Stream = 0;
1695 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1696 elements[idx].Offset = offset;
1697 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1700 *ppVertexElements = elements;
1701 return size;
1704 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1705 WINED3DVERTEXELEMENT* elements = NULL;
1706 size_t size;
1707 DWORD hr;
1709 size = ConvertFvfToDeclaration(Fvf, &elements);
1710 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1712 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1713 HeapFree(GetProcessHeap(), 0, elements);
1714 if (hr != S_OK) return hr;
1716 return WINED3D_OK;
1719 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1723 HRESULT hr = WINED3D_OK;
1724 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1725 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1727 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1729 if (vertex_declaration) {
1730 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1733 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1735 if (WINED3D_OK != hr) {
1736 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1737 IWineD3DVertexShader_Release(*ppVertexShader);
1738 return WINED3DERR_INVALIDCALL;
1741 return WINED3D_OK;
1744 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1746 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1747 HRESULT hr = WINED3D_OK;
1749 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1750 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1751 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1752 if (WINED3D_OK == hr) {
1753 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1754 } else {
1755 WARN("(%p) : Failed to create pixel shader\n", This);
1758 return hr;
1761 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1763 IWineD3DPaletteImpl *object;
1764 HRESULT hr;
1765 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1767 /* Create the new object */
1768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1769 if(!object) {
1770 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1771 return E_OUTOFMEMORY;
1774 object->lpVtbl = &IWineD3DPalette_Vtbl;
1775 object->ref = 1;
1776 object->Flags = Flags;
1777 object->parent = Parent;
1778 object->wineD3DDevice = This;
1779 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1781 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1783 if(!object->hpal) {
1784 HeapFree( GetProcessHeap(), 0, object);
1785 return E_OUTOFMEMORY;
1788 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1789 if(FAILED(hr)) {
1790 IWineD3DPalette_Release((IWineD3DPalette *) object);
1791 return hr;
1794 *Palette = (IWineD3DPalette *) object;
1796 return WINED3D_OK;
1799 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1801 IWineD3DSwapChainImpl *swapchain;
1802 DWORD state;
1804 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1805 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1807 /* TODO: Test if OpenGL is compiled in and loaded */
1809 /* Initialize the texture unit mapping to a 1:1 mapping */
1810 for(state = 0; state < MAX_SAMPLERS; state++) {
1811 This->texUnitMap[state] = state;
1813 This->oneToOneTexUnitMap = TRUE;
1815 /* Setup the implicit swapchain */
1816 TRACE("Creating implicit swapchain\n");
1817 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1818 WARN("Failed to create implicit swapchain\n");
1819 return WINED3DERR_INVALIDCALL;
1822 This->NumberOfSwapChains = 1;
1823 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1824 if(!This->swapchains) {
1825 ERR("Out of memory!\n");
1826 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1827 return E_OUTOFMEMORY;
1829 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1831 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1833 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1834 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1835 This->render_targets[0] = swapchain->backBuffer[0];
1836 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1838 else {
1839 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1840 This->render_targets[0] = swapchain->frontBuffer;
1841 This->lastActiveRenderTarget = swapchain->frontBuffer;
1843 IWineD3DSurface_AddRef(This->render_targets[0]);
1844 This->activeContext = swapchain->context[0];
1846 /* Depth Stencil support */
1847 This->stencilBufferTarget = This->depthStencilBuffer;
1848 if (NULL != This->stencilBufferTarget) {
1849 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1852 /* Set up some starting GL setup */
1853 ENTER_GL();
1855 * Initialize openGL extension related variables
1856 * with Default values
1859 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1860 /* Setup all the devices defaults */
1861 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1862 #if 0
1863 IWineD3DImpl_CheckGraphicsMemory();
1864 #endif
1866 { /* Set a default viewport */
1867 WINED3DVIEWPORT vp;
1868 vp.X = 0;
1869 vp.Y = 0;
1870 vp.Width = pPresentationParameters->BackBufferWidth;
1871 vp.Height = pPresentationParameters->BackBufferHeight;
1872 vp.MinZ = 0.0f;
1873 vp.MaxZ = 1.0f;
1874 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1877 /* Initialize the current view state */
1878 This->view_ident = 1;
1879 This->contexts[0]->last_was_rhw = 0;
1880 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1881 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1883 switch(wined3d_settings.offscreen_rendering_mode) {
1884 case ORM_FBO:
1885 case ORM_PBUFFER:
1886 This->offscreenBuffer = GL_BACK;
1887 break;
1889 case ORM_BACKBUFFER:
1891 if(GL_LIMITS(aux_buffers) > 0) {
1892 TRACE("Using auxilliary buffer for offscreen rendering\n");
1893 This->offscreenBuffer = GL_AUX0;
1894 } else {
1895 TRACE("Using back buffer for offscreen rendering\n");
1896 This->offscreenBuffer = GL_BACK;
1901 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1902 LEAVE_GL();
1904 /* Clear the screen */
1905 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1906 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1907 0x00, 1.0, 0);
1909 This->d3d_initialized = TRUE;
1910 return WINED3D_OK;
1913 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1915 int sampler;
1916 uint i;
1917 TRACE("(%p)\n", This);
1919 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1921 ENTER_GL();
1922 /* I don't think that the interface guarants that the device is destroyed from the same thread
1923 * it was created. Thus make sure a context is active for the glDelete* calls
1925 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1926 LEAVE_GL();
1928 /* Delete the pbuffer context if there is any */
1929 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1931 /* Delete the mouse cursor texture */
1932 if(This->cursorTexture) {
1933 ENTER_GL();
1934 glDeleteTextures(1, &This->cursorTexture);
1935 LEAVE_GL();
1936 This->cursorTexture = 0;
1939 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1940 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1943 /* Release the buffers (with sanity checks)*/
1944 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1945 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1946 if(This->depthStencilBuffer != This->stencilBufferTarget)
1947 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1949 This->stencilBufferTarget = NULL;
1951 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1952 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1953 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1955 TRACE("Setting rendertarget to NULL\n");
1956 This->render_targets[0] = NULL;
1958 if (This->depthStencilBuffer) {
1959 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1960 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1962 This->depthStencilBuffer = NULL;
1965 for(i=0; i < This->NumberOfSwapChains; i++) {
1966 TRACE("Releasing the implicit swapchain %d\n", i);
1967 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1968 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1972 HeapFree(GetProcessHeap(), 0, This->swapchains);
1973 This->swapchains = NULL;
1974 This->NumberOfSwapChains = 0;
1976 This->d3d_initialized = FALSE;
1977 return WINED3D_OK;
1980 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1982 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1984 /* Setup the window for fullscreen mode */
1985 if(fullscreen && !This->ddraw_fullscreen) {
1986 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1987 } else if(!fullscreen && This->ddraw_fullscreen) {
1988 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1991 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1992 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1993 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1994 * separately.
1996 This->ddraw_fullscreen = fullscreen;
1999 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2000 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2001 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2003 * There is no way to deactivate thread safety once it is enabled
2005 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2007 FIXME("No thread safety in wined3d yet\n");
2009 /*For now just store the flag(needed in case of ddraw) */
2010 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2012 return;
2015 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2016 DEVMODEW devmode;
2017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2018 LONG ret;
2019 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2020 RECT clip_rc;
2022 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2024 /* Resize the screen even without a window:
2025 * The app could have unset it with SetCooperativeLevel, but not called
2026 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2027 * but we don't have any hwnd
2030 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2031 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2032 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2033 devmode.dmPelsWidth = pMode->Width;
2034 devmode.dmPelsHeight = pMode->Height;
2036 devmode.dmDisplayFrequency = pMode->RefreshRate;
2037 if (pMode->RefreshRate != 0) {
2038 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2041 /* Only change the mode if necessary */
2042 if( (This->ddraw_width == pMode->Width) &&
2043 (This->ddraw_height == pMode->Height) &&
2044 (This->ddraw_format == pMode->Format) &&
2045 (pMode->RefreshRate == 0) ) {
2046 return WINED3D_OK;
2049 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2050 if (ret != DISP_CHANGE_SUCCESSFUL) {
2051 if(devmode.dmDisplayFrequency != 0) {
2052 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2053 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2054 devmode.dmDisplayFrequency = 0;
2055 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2057 if(ret != DISP_CHANGE_SUCCESSFUL) {
2058 return WINED3DERR_NOTAVAILABLE;
2062 /* Store the new values */
2063 This->ddraw_width = pMode->Width;
2064 This->ddraw_height = pMode->Height;
2065 This->ddraw_format = pMode->Format;
2067 /* Only do this with a window of course */
2068 if(This->ddraw_window)
2069 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2071 /* And finally clip mouse to our screen */
2072 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2073 ClipCursor(&clip_rc);
2075 return WINED3D_OK;
2078 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2080 *ppD3D= This->wineD3D;
2081 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2082 IWineD3D_AddRef(*ppD3D);
2083 return WINED3D_OK;
2086 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2087 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2088 * into the video ram as possible and seeing how many fit
2089 * you can also get the correct initial value from nvidia and ATI's driver via X
2090 * texture memory is video memory + AGP memory
2091 *******************/
2092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 static BOOL showfixmes = TRUE;
2094 if (showfixmes) {
2095 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2096 (wined3d_settings.emulated_textureram/(1024*1024)),
2097 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2098 showfixmes = FALSE;
2100 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2101 (wined3d_settings.emulated_textureram/(1024*1024)),
2102 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2103 /* return simulated texture memory left */
2104 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2109 /*****
2110 * Get / Set FVF
2111 *****/
2112 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2115 /* Update the current state block */
2116 This->updateStateBlock->changed.fvf = TRUE;
2117 This->updateStateBlock->set.fvf = TRUE;
2119 if(This->updateStateBlock->fvf == fvf) {
2120 TRACE("Application is setting the old fvf over, nothing to do\n");
2121 return WINED3D_OK;
2124 This->updateStateBlock->fvf = fvf;
2125 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2127 return WINED3D_OK;
2131 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2133 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2134 *pfvf = This->stateBlock->fvf;
2135 return WINED3D_OK;
2138 /*****
2139 * Get / Set Stream Source
2140 *****/
2141 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2143 IWineD3DVertexBuffer *oldSrc;
2145 if (StreamNumber >= MAX_STREAMS) {
2146 WARN("Stream out of range %d\n", StreamNumber);
2147 return WINED3DERR_INVALIDCALL;
2150 oldSrc = This->stateBlock->streamSource[StreamNumber];
2151 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2153 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2154 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2156 if(oldSrc == pStreamData &&
2157 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2158 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2159 TRACE("Application is setting the old values over, nothing to do\n");
2160 return WINED3D_OK;
2163 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2164 if (pStreamData) {
2165 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2166 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2169 /* Handle recording of state blocks */
2170 if (This->isRecordingState) {
2171 TRACE("Recording... not performing anything\n");
2172 return WINED3D_OK;
2175 /* Need to do a getParent and pass the reffs up */
2176 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2177 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2178 so for now, just count internally */
2179 if (pStreamData != NULL) {
2180 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2181 InterlockedIncrement(&vbImpl->bindCount);
2183 if (oldSrc != NULL) {
2184 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2189 return WINED3D_OK;
2192 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2195 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2196 This->stateBlock->streamSource[StreamNumber],
2197 This->stateBlock->streamOffset[StreamNumber],
2198 This->stateBlock->streamStride[StreamNumber]);
2200 if (StreamNumber >= MAX_STREAMS) {
2201 WARN("Stream out of range %d\n", StreamNumber);
2202 return WINED3DERR_INVALIDCALL;
2204 *pStream = This->stateBlock->streamSource[StreamNumber];
2205 *pStride = This->stateBlock->streamStride[StreamNumber];
2206 if (pOffset) {
2207 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2210 if (*pStream != NULL) {
2211 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2213 return WINED3D_OK;
2216 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2218 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2219 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2221 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2222 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2224 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2225 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2226 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2228 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2229 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2233 return WINED3D_OK;
2236 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2239 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2240 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2242 TRACE("(%p) : returning %d\n", This, *Divider);
2244 return WINED3D_OK;
2247 /*****
2248 * Get / Set & Multiply Transform
2249 *****/
2250 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 /* Most of this routine, comments included copied from ddraw tree initially: */
2254 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2256 /* Handle recording of state blocks */
2257 if (This->isRecordingState) {
2258 TRACE("Recording... not performing anything\n");
2259 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2260 This->updateStateBlock->set.transform[d3dts] = TRUE;
2261 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2262 return WINED3D_OK;
2266 * If the new matrix is the same as the current one,
2267 * we cut off any further processing. this seems to be a reasonable
2268 * optimization because as was noticed, some apps (warcraft3 for example)
2269 * tend towards setting the same matrix repeatedly for some reason.
2271 * From here on we assume that the new matrix is different, wherever it matters.
2273 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2274 TRACE("The app is setting the same matrix over again\n");
2275 return WINED3D_OK;
2276 } else {
2277 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2281 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2282 where ViewMat = Camera space, WorldMat = world space.
2284 In OpenGL, camera and world space is combined into GL_MODELVIEW
2285 matrix. The Projection matrix stay projection matrix.
2288 /* Capture the times we can just ignore the change for now */
2289 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2290 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2291 /* Handled by the state manager */
2294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2295 return WINED3D_OK;
2298 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2300 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2301 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2302 return WINED3D_OK;
2305 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2306 WINED3DMATRIX *mat = NULL;
2307 WINED3DMATRIX temp;
2309 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2310 * below means it will be recorded in a state block change, but it
2311 * works regardless where it is recorded.
2312 * If this is found to be wrong, change to StateBlock.
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2315 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2317 if (State < HIGHEST_TRANSFORMSTATE)
2319 mat = &This->updateStateBlock->transforms[State];
2320 } else {
2321 FIXME("Unhandled transform state!!\n");
2324 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2326 /* Apply change via set transform - will reapply to eg. lights this way */
2327 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2330 /*****
2331 * Get / Set Light
2332 *****/
2333 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2334 you can reference any indexes you want as long as that number max are enabled at any
2335 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2336 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2337 but when recording, just build a chain pretty much of commands to be replayed. */
2339 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2340 float rho;
2341 PLIGHTINFOEL *object = NULL;
2342 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2343 struct list *e;
2345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2346 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2348 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2349 * the gl driver.
2351 if(!pLight) {
2352 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2353 return WINED3DERR_INVALIDCALL;
2356 switch(pLight->Type) {
2357 case WINED3DLIGHT_POINT:
2358 case WINED3DLIGHT_SPOT:
2359 case WINED3DLIGHT_PARALLELPOINT:
2360 case WINED3DLIGHT_GLSPOT:
2361 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2362 * most wanted
2364 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2365 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2368 break;
2370 case WINED3DLIGHT_DIRECTIONAL:
2371 /* Ignores attenuation */
2372 break;
2374 default:
2375 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2376 return WINED3DERR_INVALIDCALL;
2379 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2380 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2381 if(object->OriginalIndex == Index) break;
2382 object = NULL;
2385 if(!object) {
2386 TRACE("Adding new light\n");
2387 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2388 if(!object) {
2389 ERR("Out of memory error when allocating a light\n");
2390 return E_OUTOFMEMORY;
2392 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2393 object->glIndex = -1;
2394 object->OriginalIndex = Index;
2395 object->changed = TRUE;
2398 /* Initialize the object */
2399 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2400 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2401 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2402 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2403 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2404 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2405 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2407 /* Save away the information */
2408 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2410 switch (pLight->Type) {
2411 case WINED3DLIGHT_POINT:
2412 /* Position */
2413 object->lightPosn[0] = pLight->Position.x;
2414 object->lightPosn[1] = pLight->Position.y;
2415 object->lightPosn[2] = pLight->Position.z;
2416 object->lightPosn[3] = 1.0f;
2417 object->cutoff = 180.0f;
2418 /* FIXME: Range */
2419 break;
2421 case WINED3DLIGHT_DIRECTIONAL:
2422 /* Direction */
2423 object->lightPosn[0] = -pLight->Direction.x;
2424 object->lightPosn[1] = -pLight->Direction.y;
2425 object->lightPosn[2] = -pLight->Direction.z;
2426 object->lightPosn[3] = 0.0;
2427 object->exponent = 0.0f;
2428 object->cutoff = 180.0f;
2429 break;
2431 case WINED3DLIGHT_SPOT:
2432 /* Position */
2433 object->lightPosn[0] = pLight->Position.x;
2434 object->lightPosn[1] = pLight->Position.y;
2435 object->lightPosn[2] = pLight->Position.z;
2436 object->lightPosn[3] = 1.0;
2438 /* Direction */
2439 object->lightDirn[0] = pLight->Direction.x;
2440 object->lightDirn[1] = pLight->Direction.y;
2441 object->lightDirn[2] = pLight->Direction.z;
2442 object->lightDirn[3] = 1.0;
2445 * opengl-ish and d3d-ish spot lights use too different models for the
2446 * light "intensity" as a function of the angle towards the main light direction,
2447 * so we only can approximate very roughly.
2448 * however spot lights are rather rarely used in games (if ever used at all).
2449 * furthermore if still used, probably nobody pays attention to such details.
2451 if (pLight->Falloff == 0) {
2452 rho = 6.28f;
2453 } else {
2454 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2456 if (rho < 0.0001) rho = 0.0001f;
2457 object->exponent = -0.3/log(cos(rho/2));
2458 if (object->exponent > 128.0) {
2459 object->exponent = 128.0;
2461 object->cutoff = pLight->Phi*90/M_PI;
2463 /* FIXME: Range */
2464 break;
2466 default:
2467 FIXME("Unrecognized light type %d\n", pLight->Type);
2470 /* Update the live definitions if the light is currently assigned a glIndex */
2471 if (object->glIndex != -1 && !This->isRecordingState) {
2472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2474 return WINED3D_OK;
2477 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2478 PLIGHTINFOEL *lightInfo = NULL;
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2480 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2481 struct list *e;
2482 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2484 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2485 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2486 if(lightInfo->OriginalIndex == Index) break;
2487 lightInfo = NULL;
2490 if (lightInfo == NULL) {
2491 TRACE("Light information requested but light not defined\n");
2492 return WINED3DERR_INVALIDCALL;
2495 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2496 return WINED3D_OK;
2499 /*****
2500 * Get / Set Light Enable
2501 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2502 *****/
2503 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2504 PLIGHTINFOEL *lightInfo = NULL;
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2507 struct list *e;
2508 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2510 /* Tests show true = 128...not clear why */
2511 Enable = Enable? 128: 0;
2513 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2514 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2515 if(lightInfo->OriginalIndex == Index) break;
2516 lightInfo = NULL;
2518 TRACE("Found light: %p\n", lightInfo);
2520 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2521 if (lightInfo == NULL) {
2523 TRACE("Light enabled requested but light not defined, so defining one!\n");
2524 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2526 /* Search for it again! Should be fairly quick as near head of list */
2527 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2528 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2529 if(lightInfo->OriginalIndex == Index) break;
2530 lightInfo = NULL;
2532 if (lightInfo == NULL) {
2533 FIXME("Adding default lights has failed dismally\n");
2534 return WINED3DERR_INVALIDCALL;
2538 lightInfo->enabledChanged = TRUE;
2539 if(!Enable) {
2540 if(lightInfo->glIndex != -1) {
2541 if(!This->isRecordingState) {
2542 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2545 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2546 lightInfo->glIndex = -1;
2547 } else {
2548 TRACE("Light already disabled, nothing to do\n");
2550 } else {
2551 if (lightInfo->glIndex != -1) {
2552 /* nop */
2553 TRACE("Nothing to do as light was enabled\n");
2554 } else {
2555 int i;
2556 /* Find a free gl light */
2557 for(i = 0; i < This->maxConcurrentLights; i++) {
2558 if(This->stateBlock->activeLights[i] == NULL) {
2559 This->stateBlock->activeLights[i] = lightInfo;
2560 lightInfo->glIndex = i;
2561 break;
2564 if(lightInfo->glIndex == -1) {
2565 ERR("Too many concurrently active lights\n");
2566 return WINED3DERR_INVALIDCALL;
2569 /* i == lightInfo->glIndex */
2570 if(!This->isRecordingState) {
2571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2576 return WINED3D_OK;
2579 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2581 PLIGHTINFOEL *lightInfo = NULL;
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 struct list *e;
2584 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2585 TRACE("(%p) : for idx(%d)\n", This, Index);
2587 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2588 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2589 if(lightInfo->OriginalIndex == Index) break;
2590 lightInfo = NULL;
2593 if (lightInfo == NULL) {
2594 TRACE("Light enabled state requested but light not defined\n");
2595 return WINED3DERR_INVALIDCALL;
2597 /* true is 128 according to SetLightEnable */
2598 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2599 return WINED3D_OK;
2602 /*****
2603 * Get / Set Clip Planes
2604 *****/
2605 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2609 /* Validate Index */
2610 if (Index >= GL_LIMITS(clipplanes)) {
2611 TRACE("Application has requested clipplane this device doesn't support\n");
2612 return WINED3DERR_INVALIDCALL;
2615 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2616 This->updateStateBlock->set.clipplane[Index] = TRUE;
2618 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2619 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2620 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2621 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2622 TRACE("Application is setting old values over, nothing to do\n");
2623 return WINED3D_OK;
2626 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2627 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2628 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2629 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2631 /* Handle recording of state blocks */
2632 if (This->isRecordingState) {
2633 TRACE("Recording... not performing anything\n");
2634 return WINED3D_OK;
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2639 return WINED3D_OK;
2642 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2644 TRACE("(%p) : for idx %d\n", This, Index);
2646 /* Validate Index */
2647 if (Index >= GL_LIMITS(clipplanes)) {
2648 TRACE("Application has requested clipplane this device doesn't support\n");
2649 return WINED3DERR_INVALIDCALL;
2652 pPlane[0] = This->stateBlock->clipplane[Index][0];
2653 pPlane[1] = This->stateBlock->clipplane[Index][1];
2654 pPlane[2] = This->stateBlock->clipplane[Index][2];
2655 pPlane[3] = This->stateBlock->clipplane[Index][3];
2656 return WINED3D_OK;
2659 /*****
2660 * Get / Set Clip Plane Status
2661 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2662 *****/
2663 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2665 FIXME("(%p) : stub\n", This);
2666 if (NULL == pClipStatus) {
2667 return WINED3DERR_INVALIDCALL;
2669 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2670 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2671 return WINED3D_OK;
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 FIXME("(%p) : stub\n", This);
2677 if (NULL == pClipStatus) {
2678 return WINED3DERR_INVALIDCALL;
2680 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2681 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2682 return WINED3D_OK;
2685 /*****
2686 * Get / Set Material
2687 *****/
2688 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 This->updateStateBlock->changed.material = TRUE;
2692 This->updateStateBlock->set.material = TRUE;
2693 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2695 /* Handle recording of state blocks */
2696 if (This->isRecordingState) {
2697 TRACE("Recording... not performing anything\n");
2698 return WINED3D_OK;
2701 ENTER_GL();
2702 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2703 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2704 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2705 pMaterial->Ambient.b, pMaterial->Ambient.a);
2706 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2707 pMaterial->Specular.b, pMaterial->Specular.a);
2708 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2709 pMaterial->Emissive.b, pMaterial->Emissive.a);
2710 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2712 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2713 checkGLcall("glMaterialfv(GL_AMBIENT)");
2714 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2715 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2717 /* Only change material color if specular is enabled, otherwise it is set to black */
2718 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2719 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2720 checkGLcall("glMaterialfv(GL_SPECULAR");
2721 } else {
2722 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2723 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2724 checkGLcall("glMaterialfv(GL_SPECULAR");
2726 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2727 checkGLcall("glMaterialfv(GL_EMISSION)");
2728 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2729 checkGLcall("glMaterialf(GL_SHININESS");
2731 LEAVE_GL();
2732 return WINED3D_OK;
2735 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2738 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2739 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2740 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2741 pMaterial->Ambient.b, pMaterial->Ambient.a);
2742 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2743 pMaterial->Specular.b, pMaterial->Specular.a);
2744 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2745 pMaterial->Emissive.b, pMaterial->Emissive.a);
2746 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2748 return WINED3D_OK;
2751 /*****
2752 * Get / Set Indices
2753 *****/
2754 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2755 UINT BaseVertexIndex) {
2756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2757 IWineD3DIndexBuffer *oldIdxs;
2758 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2760 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2761 oldIdxs = This->updateStateBlock->pIndexData;
2763 This->updateStateBlock->changed.indices = TRUE;
2764 This->updateStateBlock->set.indices = TRUE;
2765 This->updateStateBlock->pIndexData = pIndexData;
2766 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2768 /* Handle recording of state blocks */
2769 if (This->isRecordingState) {
2770 TRACE("Recording... not performing anything\n");
2771 return WINED3D_OK;
2774 /* The base vertex index affects the stream sources, while
2775 * The index buffer is a seperate index buffer state
2777 if(BaseVertexIndex != oldBaseIndex) {
2778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2780 if(oldIdxs != pIndexData) {
2781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2783 return WINED3D_OK;
2786 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 *ppIndexData = This->stateBlock->pIndexData;
2791 /* up ref count on ppindexdata */
2792 if (*ppIndexData) {
2793 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2794 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2795 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2796 }else{
2797 TRACE("(%p) No index data set\n", This);
2799 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2801 return WINED3D_OK;
2804 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2805 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 TRACE("(%p)->(%d)\n", This, BaseIndex);
2809 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2810 TRACE("Application is setting the old value over, nothing to do\n");
2811 return WINED3D_OK;
2814 This->updateStateBlock->baseVertexIndex = BaseIndex;
2816 if (This->isRecordingState) {
2817 TRACE("Recording... not performing anything\n");
2818 return WINED3D_OK;
2820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2821 return WINED3D_OK;
2824 /*****
2825 * Get / Set Viewports
2826 *****/
2827 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830 TRACE("(%p)\n", This);
2831 This->updateStateBlock->changed.viewport = TRUE;
2832 This->updateStateBlock->set.viewport = TRUE;
2833 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2835 /* Handle recording of state blocks */
2836 if (This->isRecordingState) {
2837 TRACE("Recording... not performing anything\n");
2838 return WINED3D_OK;
2841 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2842 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2845 return WINED3D_OK;
2849 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2851 TRACE("(%p)\n", This);
2852 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2853 return WINED3D_OK;
2856 /*****
2857 * Get / Set Render States
2858 * TODO: Verify against dx9 definitions
2859 *****/
2860 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 DWORD oldValue = This->stateBlock->renderState[State];
2865 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2867 This->updateStateBlock->changed.renderState[State] = TRUE;
2868 This->updateStateBlock->set.renderState[State] = TRUE;
2869 This->updateStateBlock->renderState[State] = Value;
2871 /* Handle recording of state blocks */
2872 if (This->isRecordingState) {
2873 TRACE("Recording... not performing anything\n");
2874 return WINED3D_OK;
2877 /* Compared here and not before the assignment to allow proper stateblock recording */
2878 if(Value == oldValue) {
2879 TRACE("Application is setting the old value over, nothing to do\n");
2880 } else {
2881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2884 return WINED3D_OK;
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2890 *pValue = This->stateBlock->renderState[State];
2891 return WINED3D_OK;
2894 /*****
2895 * Get / Set Sampler States
2896 * TODO: Verify against dx9 definitions
2897 *****/
2899 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2904 * SetSampler is designed to allow for more than the standard up to 8 textures
2905 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2906 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2908 * http://developer.nvidia.com/object/General_FAQ.html#t6
2910 * There are two new settings for GForce
2911 * the sampler one:
2912 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2913 * and the texture one:
2914 * GL_MAX_TEXTURE_COORDS_ARB.
2915 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2916 ******************/
2918 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2919 debug_d3dsamplerstate(Type), Type, Value);
2920 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2921 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2922 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2924 /* Handle recording of state blocks */
2925 if (This->isRecordingState) {
2926 TRACE("Recording... not performing anything\n");
2927 return WINED3D_OK;
2930 if(oldValue == Value) {
2931 TRACE("Application is setting the old value over, nothing to do\n");
2932 return WINED3D_OK;
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2937 return WINED3D_OK;
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2942 *Value = This->stateBlock->samplerState[Sampler][Type];
2943 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2945 return WINED3D_OK;
2948 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2951 This->updateStateBlock->set.scissorRect = TRUE;
2952 This->updateStateBlock->changed.scissorRect = TRUE;
2953 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2954 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2955 return WINED3D_OK;
2957 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2959 if(This->isRecordingState) {
2960 TRACE("Recording... not performing anything\n");
2961 return WINED3D_OK;
2964 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2966 return WINED3D_OK;
2969 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2972 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2973 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2979 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2981 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2983 This->updateStateBlock->vertexDecl = pDecl;
2984 This->updateStateBlock->changed.vertexDecl = TRUE;
2985 This->updateStateBlock->set.vertexDecl = TRUE;
2987 if (This->isRecordingState) {
2988 TRACE("Recording... not performing anything\n");
2989 return WINED3D_OK;
2990 } else if(pDecl == oldDecl) {
2991 /* Checked after the assignment to allow proper stateblock recording */
2992 TRACE("Application is setting the old declaration over, nothing to do\n");
2993 return WINED3D_OK;
2996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2997 return WINED3D_OK;
3000 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3005 *ppDecl = This->stateBlock->vertexDecl;
3006 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3007 return WINED3D_OK;
3010 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3012 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3014 This->updateStateBlock->vertexShader = pShader;
3015 This->updateStateBlock->changed.vertexShader = TRUE;
3016 This->updateStateBlock->set.vertexShader = TRUE;
3018 if (This->isRecordingState) {
3019 TRACE("Recording... not performing anything\n");
3020 return WINED3D_OK;
3021 } else if(oldShader == pShader) {
3022 /* Checked here to allow proper stateblock recording */
3023 TRACE("App is setting the old shader over, nothing to do\n");
3024 return WINED3D_OK;
3027 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3031 return WINED3D_OK;
3034 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3037 if (NULL == ppShader) {
3038 return WINED3DERR_INVALIDCALL;
3040 *ppShader = This->stateBlock->vertexShader;
3041 if( NULL != *ppShader)
3042 IWineD3DVertexShader_AddRef(*ppShader);
3044 TRACE("(%p) : returning %p\n", This, *ppShader);
3045 return WINED3D_OK;
3048 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3049 IWineD3DDevice *iface,
3050 UINT start,
3051 CONST BOOL *srcData,
3052 UINT count) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 int i, cnt = min(count, MAX_CONST_B - start);
3057 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3058 iface, srcData, start, count);
3060 if (srcData == NULL || cnt < 0)
3061 return WINED3DERR_INVALIDCALL;
3063 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3064 for (i = 0; i < cnt; i++)
3065 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3067 for (i = start; i < cnt + start; ++i) {
3068 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3069 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3074 return WINED3D_OK;
3077 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3078 IWineD3DDevice *iface,
3079 UINT start,
3080 BOOL *dstData,
3081 UINT count) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 int cnt = min(count, MAX_CONST_B - start);
3086 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3087 iface, dstData, start, count);
3089 if (dstData == NULL || cnt < 0)
3090 return WINED3DERR_INVALIDCALL;
3092 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3093 return WINED3D_OK;
3096 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3097 IWineD3DDevice *iface,
3098 UINT start,
3099 CONST int *srcData,
3100 UINT count) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 int i, cnt = min(count, MAX_CONST_I - start);
3105 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3106 iface, srcData, start, count);
3108 if (srcData == NULL || cnt < 0)
3109 return WINED3DERR_INVALIDCALL;
3111 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3112 for (i = 0; i < cnt; i++)
3113 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3114 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3116 for (i = start; i < cnt + start; ++i) {
3117 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3118 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3123 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3127 IWineD3DDevice *iface,
3128 UINT start,
3129 int *dstData,
3130 UINT count) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 int cnt = min(count, MAX_CONST_I - start);
3135 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3136 iface, dstData, start, count);
3138 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3139 return WINED3DERR_INVALIDCALL;
3141 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3142 return WINED3D_OK;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3146 IWineD3DDevice *iface,
3147 UINT start,
3148 CONST float *srcData,
3149 UINT count) {
3151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 int i;
3154 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3155 iface, srcData, start, count);
3157 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3158 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3159 return WINED3DERR_INVALIDCALL;
3161 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3162 if(TRACE_ON(d3d)) {
3163 for (i = 0; i < count; i++)
3164 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3165 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3168 for (i = start; i < count + start; ++i) {
3169 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3170 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3171 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3172 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3173 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3175 ptr->idx[ptr->count++] = i;
3176 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3178 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3183 return WINED3D_OK;
3186 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3187 IWineD3DDevice *iface,
3188 UINT start,
3189 float *dstData,
3190 UINT count) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3195 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3196 iface, dstData, start, count);
3198 if (dstData == NULL || cnt < 0)
3199 return WINED3DERR_INVALIDCALL;
3201 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3202 return WINED3D_OK;
3205 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3206 DWORD i;
3207 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3212 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3213 DWORD i, tex;
3214 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3215 * it is never called.
3217 * Rules are:
3218 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3219 * that would be really messy and require shader recompilation
3220 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3221 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3222 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3223 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3225 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3226 if(This->oneToOneTexUnitMap) {
3227 TRACE("Not touching 1:1 map\n");
3228 return;
3230 TRACE("Restoring 1:1 texture unit mapping\n");
3231 /* Restore a 1:1 mapping */
3232 for(i = 0; i < MAX_SAMPLERS; i++) {
3233 if(This->texUnitMap[i] != i) {
3234 This->texUnitMap[i] = i;
3235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3236 markTextureStagesDirty(This, i);
3239 This->oneToOneTexUnitMap = TRUE;
3240 return;
3241 } else {
3242 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3243 * First, see if we can succeed at all
3245 tex = 0;
3246 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3247 if(This->stateBlock->textures[i] == NULL) tex++;
3250 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3251 FIXME("Too many bound textures to support the combiner settings\n");
3252 return;
3255 /* Now work out the mapping */
3256 tex = 0;
3257 This->oneToOneTexUnitMap = FALSE;
3258 WARN("Non 1:1 mapping UNTESTED!\n");
3259 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3260 /* Skip NULL textures */
3261 if (!This->stateBlock->textures[i]) {
3262 /* Map to -1, so the check below doesn't fail if a non-NULL
3263 * texture is set on this stage */
3264 TRACE("Mapping texture stage %d to -1\n", i);
3265 This->texUnitMap[i] = -1;
3267 continue;
3270 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3271 if(This->texUnitMap[i] != tex) {
3272 This->texUnitMap[i] = tex;
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3274 markTextureStagesDirty(This, i);
3277 ++tex;
3282 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3284 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3285 This->updateStateBlock->pixelShader = pShader;
3286 This->updateStateBlock->changed.pixelShader = TRUE;
3287 This->updateStateBlock->set.pixelShader = TRUE;
3289 /* Handle recording of state blocks */
3290 if (This->isRecordingState) {
3291 TRACE("Recording... not performing anything\n");
3294 if (This->isRecordingState) {
3295 TRACE("Recording... not performing anything\n");
3296 return WINED3D_OK;
3299 if(pShader == oldShader) {
3300 TRACE("App is setting the old pixel shader over, nothing to do\n");
3301 return WINED3D_OK;
3304 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3307 /* Rebuild the texture unit mapping if nvrc's are supported */
3308 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3309 IWineD3DDeviceImpl_FindTexUnitMap(This);
3312 return WINED3D_OK;
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 if (NULL == ppShader) {
3319 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3320 return WINED3DERR_INVALIDCALL;
3323 *ppShader = This->stateBlock->pixelShader;
3324 if (NULL != *ppShader) {
3325 IWineD3DPixelShader_AddRef(*ppShader);
3327 TRACE("(%p) : returning %p\n", This, *ppShader);
3328 return WINED3D_OK;
3331 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3332 IWineD3DDevice *iface,
3333 UINT start,
3334 CONST BOOL *srcData,
3335 UINT count) {
3337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 int i, cnt = min(count, MAX_CONST_B - start);
3340 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3341 iface, srcData, start, count);
3343 if (srcData == NULL || cnt < 0)
3344 return WINED3DERR_INVALIDCALL;
3346 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3347 for (i = 0; i < cnt; i++)
3348 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3350 for (i = start; i < cnt + start; ++i) {
3351 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3352 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3357 return WINED3D_OK;
3360 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3361 IWineD3DDevice *iface,
3362 UINT start,
3363 BOOL *dstData,
3364 UINT count) {
3366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3367 int cnt = min(count, MAX_CONST_B - start);
3369 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3370 iface, dstData, start, count);
3372 if (dstData == NULL || cnt < 0)
3373 return WINED3DERR_INVALIDCALL;
3375 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3376 return WINED3D_OK;
3379 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3380 IWineD3DDevice *iface,
3381 UINT start,
3382 CONST int *srcData,
3383 UINT count) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 int i, cnt = min(count, MAX_CONST_I - start);
3388 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3389 iface, srcData, start, count);
3391 if (srcData == NULL || cnt < 0)
3392 return WINED3DERR_INVALIDCALL;
3394 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3395 for (i = 0; i < cnt; i++)
3396 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3397 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3399 for (i = start; i < cnt + start; ++i) {
3400 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3401 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3406 return WINED3D_OK;
3409 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3410 IWineD3DDevice *iface,
3411 UINT start,
3412 int *dstData,
3413 UINT count) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 int cnt = min(count, MAX_CONST_I - start);
3418 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3419 iface, dstData, start, count);
3421 if (dstData == NULL || cnt < 0)
3422 return WINED3DERR_INVALIDCALL;
3424 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3425 return WINED3D_OK;
3428 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3429 IWineD3DDevice *iface,
3430 UINT start,
3431 CONST float *srcData,
3432 UINT count) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 int i;
3437 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3438 iface, srcData, start, count);
3440 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3441 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3442 return WINED3DERR_INVALIDCALL;
3444 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3445 if(TRACE_ON(d3d)) {
3446 for (i = 0; i < count; i++)
3447 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3448 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3451 for (i = start; i < count + start; ++i) {
3452 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3453 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3454 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3455 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3456 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3458 ptr->idx[ptr->count++] = i;
3459 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3461 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3466 return WINED3D_OK;
3469 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3470 IWineD3DDevice *iface,
3471 UINT start,
3472 float *dstData,
3473 UINT count) {
3475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3476 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3478 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3479 iface, dstData, start, count);
3481 if (dstData == NULL || cnt < 0)
3482 return WINED3DERR_INVALIDCALL;
3484 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3485 return WINED3D_OK;
3488 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3489 static HRESULT
3490 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3491 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3492 unsigned int i;
3493 DWORD DestFVF = dest->fvf;
3494 WINED3DVIEWPORT vp;
3495 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3496 BOOL doClip;
3497 int numTextures;
3499 if (lpStrideData->u.s.normal.lpData) {
3500 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3503 if (lpStrideData->u.s.position.lpData == NULL) {
3504 ERR("Source has no position mask\n");
3505 return WINED3DERR_INVALIDCALL;
3508 /* We might access VBOs from this code, so hold the lock */
3509 ENTER_GL();
3511 if (dest->resource.allocatedMemory == NULL) {
3512 /* This may happen if we do direct locking into a vbo. Unlikely,
3513 * but theoretically possible(ddraw processvertices test)
3515 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3516 if(!dest->resource.allocatedMemory) {
3517 LEAVE_GL();
3518 ERR("Out of memory\n");
3519 return E_OUTOFMEMORY;
3521 if(dest->vbo) {
3522 void *src;
3523 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3524 checkGLcall("glBindBufferARB");
3525 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3526 if(src) {
3527 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3529 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3530 checkGLcall("glUnmapBufferARB");
3534 /* Get a pointer into the destination vbo(create one if none exists) and
3535 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3537 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3538 CreateVBO(dest);
3541 if(dest->vbo) {
3542 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3543 if(!dest_conv_addr) {
3544 ERR("Out of memory\n");
3545 /* Continue without storing converted vertices */
3547 dest_conv = dest_conv_addr;
3550 /* Should I clip?
3551 * a) WINED3DRS_CLIPPING is enabled
3552 * b) WINED3DVOP_CLIP is passed
3554 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3555 static BOOL warned = FALSE;
3557 * The clipping code is not quite correct. Some things need
3558 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3559 * so disable clipping for now.
3560 * (The graphics in Half-Life are broken, and my processvertices
3561 * test crashes with IDirect3DDevice3)
3562 doClip = TRUE;
3564 doClip = FALSE;
3565 if(!warned) {
3566 warned = TRUE;
3567 FIXME("Clipping is broken and disabled for now\n");
3569 } else doClip = FALSE;
3570 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3572 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3573 WINED3DTS_VIEW,
3574 &view_mat);
3575 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3576 WINED3DTS_PROJECTION,
3577 &proj_mat);
3578 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3579 WINED3DTS_WORLDMATRIX(0),
3580 &world_mat);
3582 TRACE("View mat:\n");
3583 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);
3584 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);
3585 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);
3586 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);
3588 TRACE("Proj mat:\n");
3589 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);
3590 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);
3591 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);
3592 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);
3594 TRACE("World mat:\n");
3595 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);
3596 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);
3597 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);
3598 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);
3600 /* Get the viewport */
3601 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3602 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3603 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3605 multiply_matrix(&mat,&view_mat,&world_mat);
3606 multiply_matrix(&mat,&proj_mat,&mat);
3608 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3610 for (i = 0; i < dwCount; i+= 1) {
3611 unsigned int tex_index;
3613 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3614 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3615 /* The position first */
3616 float *p =
3617 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3618 float x, y, z, rhw;
3619 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3621 /* Multiplication with world, view and projection matrix */
3622 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);
3623 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);
3624 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);
3625 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);
3627 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3629 /* WARNING: The following things are taken from d3d7 and were not yet checked
3630 * against d3d8 or d3d9!
3633 /* Clipping conditions: From
3634 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3636 * A vertex is clipped if it does not match the following requirements
3637 * -rhw < x <= rhw
3638 * -rhw < y <= rhw
3639 * 0 < z <= rhw
3640 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3642 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3643 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3647 if( !doClip ||
3648 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3649 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3650 ( rhw > eps ) ) ) {
3652 /* "Normal" viewport transformation (not clipped)
3653 * 1) The values are divided by rhw
3654 * 2) The y axis is negative, so multiply it with -1
3655 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3656 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3657 * 4) Multiply x with Width/2 and add Width/2
3658 * 5) The same for the height
3659 * 6) Add the viewpoint X and Y to the 2D coordinates and
3660 * The minimum Z value to z
3661 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3663 * Well, basically it's simply a linear transformation into viewport
3664 * coordinates
3667 x /= rhw;
3668 y /= rhw;
3669 z /= rhw;
3671 y *= -1;
3673 x *= vp.Width / 2;
3674 y *= vp.Height / 2;
3675 z *= vp.MaxZ - vp.MinZ;
3677 x += vp.Width / 2 + vp.X;
3678 y += vp.Height / 2 + vp.Y;
3679 z += vp.MinZ;
3681 rhw = 1 / rhw;
3682 } else {
3683 /* That vertex got clipped
3684 * Contrary to OpenGL it is not dropped completely, it just
3685 * undergoes a different calculation.
3687 TRACE("Vertex got clipped\n");
3688 x += rhw;
3689 y += rhw;
3691 x /= 2;
3692 y /= 2;
3694 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3695 * outside of the main vertex buffer memory. That needs some more
3696 * investigation...
3700 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3703 ( (float *) dest_ptr)[0] = x;
3704 ( (float *) dest_ptr)[1] = y;
3705 ( (float *) dest_ptr)[2] = z;
3706 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3708 dest_ptr += 3 * sizeof(float);
3710 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3711 dest_ptr += sizeof(float);
3714 if(dest_conv) {
3715 float w = 1 / rhw;
3716 ( (float *) dest_conv)[0] = x * w;
3717 ( (float *) dest_conv)[1] = y * w;
3718 ( (float *) dest_conv)[2] = z * w;
3719 ( (float *) dest_conv)[3] = w;
3721 dest_conv += 3 * sizeof(float);
3723 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3724 dest_conv += sizeof(float);
3728 if (DestFVF & WINED3DFVF_PSIZE) {
3729 dest_ptr += sizeof(DWORD);
3730 if(dest_conv) dest_conv += sizeof(DWORD);
3732 if (DestFVF & WINED3DFVF_NORMAL) {
3733 float *normal =
3734 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3735 /* AFAIK this should go into the lighting information */
3736 FIXME("Didn't expect the destination to have a normal\n");
3737 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3738 if(dest_conv) {
3739 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3743 if (DestFVF & WINED3DFVF_DIFFUSE) {
3744 DWORD *color_d =
3745 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3746 if(!color_d) {
3747 static BOOL warned = FALSE;
3749 if(!warned) {
3750 ERR("No diffuse color in source, but destination has one\n");
3751 warned = TRUE;
3754 *( (DWORD *) dest_ptr) = 0xffffffff;
3755 dest_ptr += sizeof(DWORD);
3757 if(dest_conv) {
3758 *( (DWORD *) dest_conv) = 0xffffffff;
3759 dest_conv += sizeof(DWORD);
3762 else {
3763 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3764 if(dest_conv) {
3765 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3766 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3767 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3768 dest_conv += sizeof(DWORD);
3773 if (DestFVF & WINED3DFVF_SPECULAR) {
3774 /* What's the color value in the feedback buffer? */
3775 DWORD *color_s =
3776 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3777 if(!color_s) {
3778 static BOOL warned = FALSE;
3780 if(!warned) {
3781 ERR("No specular color in source, but destination has one\n");
3782 warned = TRUE;
3785 *( (DWORD *) dest_ptr) = 0xFF000000;
3786 dest_ptr += sizeof(DWORD);
3788 if(dest_conv) {
3789 *( (DWORD *) dest_conv) = 0xFF000000;
3790 dest_conv += sizeof(DWORD);
3793 else {
3794 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3795 if(dest_conv) {
3796 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3797 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3798 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3799 dest_conv += sizeof(DWORD);
3804 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3805 float *tex_coord =
3806 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3807 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3808 if(!tex_coord) {
3809 ERR("No source texture, but destination requests one\n");
3810 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3811 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3813 else {
3814 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3815 if(dest_conv) {
3816 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3822 if(dest_conv) {
3823 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3824 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3825 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3826 dwCount * get_flexible_vertex_size(DestFVF),
3827 dest_conv_addr));
3828 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3829 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3832 LEAVE_GL();
3834 return WINED3D_OK;
3836 #undef copy_and_next
3838 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3840 WineDirect3DVertexStridedData strided;
3841 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3842 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3844 if(pVertexDecl) {
3845 ERR("Output vertex declaration not implemented yet\n");
3848 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3849 * and this call is quite performance critical, so don't call needlessly
3851 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3852 ENTER_GL();
3853 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3854 LEAVE_GL();
3857 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3858 * control the streamIsUP flag, thus restore it afterwards.
3860 This->stateBlock->streamIsUP = FALSE;
3861 memset(&strided, 0, sizeof(strided));
3862 if(This->stateBlock->vertexDecl) {
3863 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3864 } else {
3865 primitiveConvertToStridedData(iface, &strided, &vbo);
3867 This->stateBlock->streamIsUP = streamWasUP;
3869 if(vbo || SrcStartIndex) {
3870 unsigned int i;
3871 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3872 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3874 * Also get the start index in, but only loop over all elements if there's something to add at all.
3876 for(i=0; i < 16; i++) {
3877 if(strided.u.input[i].VBO) {
3878 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.input[i].streamNo];
3880 /* The vertex buffer is supposed to have a system memory copy */
3881 strided.u.input[i].VBO = 0;
3882 strided.u.input[i].lpData = (BYTE *) ((unsigned long) strided.u.input[i].lpData + (unsigned long) vb->resource.allocatedMemory);
3883 ENTER_GL();
3884 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo));
3885 vb->vbo = 0;
3886 LEAVE_GL();
3888 /* To be safe. An app could technically draw, then call ProcessVertices, then draw again without ever changing the stream sources */
3889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3891 if(strided.u.input[i].lpData) {
3892 strided.u.input[i].lpData += strided.u.input[i].dwStride * SrcStartIndex;
3897 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3900 /*****
3901 * Get / Set Texture Stage States
3902 * TODO: Verify against dx9 definitions
3903 *****/
3904 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3906 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3908 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3910 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3912 if (Stage >= MAX_TEXTURES) {
3913 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3914 return WINED3D_OK;
3917 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3918 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3919 This->updateStateBlock->textureState[Stage][Type] = Value;
3921 if (This->isRecordingState) {
3922 TRACE("Recording... not performing anything\n");
3923 return WINED3D_OK;
3926 /* Checked after the assignments to allow proper stateblock recording */
3927 if(oldValue == Value) {
3928 TRACE("App is setting the old value over, nothing to do\n");
3929 return WINED3D_OK;
3932 if(Stage > This->stateBlock->lowest_disabled_stage &&
3933 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3934 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3935 * Changes in other states are important on disabled stages too
3937 return WINED3D_OK;
3940 if(Type == WINED3DTSS_COLOROP) {
3941 int i;
3943 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3944 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3945 * they have to be disabled
3947 * The current stage is dirtified below.
3949 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3950 TRACE("Additionally dirtifying stage %d\n", i);
3951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3953 This->stateBlock->lowest_disabled_stage = Stage;
3954 TRACE("New lowest disabled: %d\n", Stage);
3955 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3956 /* Previously disabled stage enabled. Stages above it may need enabling
3957 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3958 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3960 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3963 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3964 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3965 break;
3967 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3970 This->stateBlock->lowest_disabled_stage = i;
3971 TRACE("New lowest disabled: %d\n", i);
3973 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3974 /* TODO: Built a stage -> texture unit mapping for register combiners */
3978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3980 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3981 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3982 * will call FindTexUnitMap too.
3984 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3985 IWineD3DDeviceImpl_FindTexUnitMap(This);
3987 return WINED3D_OK;
3990 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3993 *pValue = This->updateStateBlock->textureState[Stage][Type];
3994 return WINED3D_OK;
3997 /*****
3998 * Get / Set Texture
3999 *****/
4000 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4003 IWineD3DBaseTexture *oldTexture;
4005 oldTexture = This->updateStateBlock->textures[Stage];
4006 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4008 #if 0 /* TODO: check so vertex textures */
4009 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4010 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4011 return WINED3D_OK;
4013 #endif
4015 if(pTexture != NULL) {
4016 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4018 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4019 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4020 return WINED3DERR_INVALIDCALL;
4022 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4025 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4026 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4028 This->updateStateBlock->set.textures[Stage] = TRUE;
4029 This->updateStateBlock->changed.textures[Stage] = TRUE;
4030 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4031 This->updateStateBlock->textures[Stage] = pTexture;
4033 /* Handle recording of state blocks */
4034 if (This->isRecordingState) {
4035 TRACE("Recording... not performing anything\n");
4036 return WINED3D_OK;
4039 if(oldTexture == pTexture) {
4040 TRACE("App is setting the same texture again, nothing to do\n");
4041 return WINED3D_OK;
4044 /** NOTE: MSDN says that setTexture increases the reference count,
4045 * and the the application nust set the texture back to null (or have a leaky application),
4046 * This means we should pass the refcount up to the parent
4047 *******************************/
4048 if (NULL != This->updateStateBlock->textures[Stage]) {
4049 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4050 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4052 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4053 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4054 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4055 * so the COLOROP and ALPHAOP have to be dirtified.
4057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4060 if(bindCount == 1) {
4061 new->baseTexture.sampler = Stage;
4063 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4067 if (NULL != oldTexture) {
4068 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4069 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4071 IWineD3DBaseTexture_Release(oldTexture);
4072 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4077 if(bindCount && old->baseTexture.sampler == Stage) {
4078 int i;
4079 /* Have to do a search for the other sampler(s) where the texture is bound to
4080 * Shouldn't happen as long as apps bind a texture only to one stage
4082 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4083 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4084 if(This->updateStateBlock->textures[i] == oldTexture) {
4085 old->baseTexture.sampler = i;
4086 break;
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4094 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4095 * pixel shader is used
4097 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4098 IWineD3DDeviceImpl_FindTexUnitMap(This);
4101 return WINED3D_OK;
4104 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4106 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4108 *ppTexture=This->stateBlock->textures[Stage];
4109 if (*ppTexture)
4110 IWineD3DBaseTexture_AddRef(*ppTexture);
4112 return WINED3D_OK;
4115 /*****
4116 * Get Back Buffer
4117 *****/
4118 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4119 IWineD3DSurface **ppBackBuffer) {
4120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4121 IWineD3DSwapChain *swapChain;
4122 HRESULT hr;
4124 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4126 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4127 if (hr == WINED3D_OK) {
4128 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4129 IWineD3DSwapChain_Release(swapChain);
4130 } else {
4131 *ppBackBuffer = NULL;
4133 return hr;
4136 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4138 WARN("(%p) : stub, calling idirect3d for now\n", This);
4139 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4142 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4144 IWineD3DSwapChain *swapChain;
4145 HRESULT hr;
4147 if(iSwapChain > 0) {
4148 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4149 if (hr == WINED3D_OK) {
4150 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4151 IWineD3DSwapChain_Release(swapChain);
4152 } else {
4153 FIXME("(%p) Error getting display mode\n", This);
4155 } else {
4156 /* Don't read the real display mode,
4157 but return the stored mode instead. X11 can't change the color
4158 depth, and some apps are pretty angry if they SetDisplayMode from
4159 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4161 Also don't relay to the swapchain because with ddraw it's possible
4162 that there isn't a swapchain at all */
4163 pMode->Width = This->ddraw_width;
4164 pMode->Height = This->ddraw_height;
4165 pMode->Format = This->ddraw_format;
4166 pMode->RefreshRate = 0;
4167 hr = WINED3D_OK;
4170 return hr;
4173 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4174 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4175 TRACE("(%p)->(%p)\n", This, hWnd);
4177 if(This->ddraw_fullscreen) {
4178 if(This->ddraw_window && This->ddraw_window != hWnd) {
4179 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4181 if(hWnd && This->ddraw_window != hWnd) {
4182 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4186 This->ddraw_window = hWnd;
4187 return WINED3D_OK;
4190 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4192 TRACE("(%p)->(%p)\n", This, hWnd);
4194 *hWnd = This->ddraw_window;
4195 return WINED3D_OK;
4198 /*****
4199 * Stateblock related functions
4200 *****/
4202 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4204 IWineD3DStateBlockImpl *object;
4205 HRESULT temp_result;
4206 int i;
4208 TRACE("(%p)\n", This);
4210 if (This->isRecordingState) {
4211 return WINED3DERR_INVALIDCALL;
4214 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4215 if (NULL == object ) {
4216 FIXME("(%p)Error allocating memory for stateblock\n", This);
4217 return E_OUTOFMEMORY;
4219 TRACE("(%p) created object %p\n", This, object);
4220 object->wineD3DDevice= This;
4221 /** FIXME: object->parent = parent; **/
4222 object->parent = NULL;
4223 object->blockType = WINED3DSBT_ALL;
4224 object->ref = 1;
4225 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4227 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4228 list_init(&object->lightMap[i]);
4231 temp_result = allocate_shader_constants(object);
4232 if (WINED3D_OK != temp_result)
4233 return temp_result;
4235 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4236 This->updateStateBlock = object;
4237 This->isRecordingState = TRUE;
4239 TRACE("(%p) recording stateblock %p\n",This , object);
4240 return WINED3D_OK;
4243 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4246 if (!This->isRecordingState) {
4247 FIXME("(%p) not recording! returning error\n", This);
4248 *ppStateBlock = NULL;
4249 return WINED3DERR_INVALIDCALL;
4252 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4253 This->isRecordingState = FALSE;
4254 This->updateStateBlock = This->stateBlock;
4255 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4256 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4257 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4258 return WINED3D_OK;
4261 /*****
4262 * Scene related functions
4263 *****/
4264 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4265 /* At the moment we have no need for any functionality at the beginning
4266 of a scene */
4267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4268 TRACE("(%p)\n", This);
4270 if(This->inScene) {
4271 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4272 return WINED3DERR_INVALIDCALL;
4274 This->inScene = TRUE;
4275 return WINED3D_OK;
4278 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4280 TRACE("(%p)\n", This);
4282 if(!This->inScene) {
4283 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4284 return WINED3DERR_INVALIDCALL;
4287 ENTER_GL();
4288 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4289 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4291 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4292 glFlush();
4293 checkGLcall("glFlush");
4294 LEAVE_GL();
4296 This->inScene = FALSE;
4297 return WINED3D_OK;
4300 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4301 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4302 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4304 IWineD3DSwapChain *swapChain = NULL;
4305 int i;
4306 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4308 TRACE("(%p) Presenting the frame\n", This);
4310 for(i = 0 ; i < swapchains ; i ++) {
4312 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4313 TRACE("presentinng chain %d, %p\n", i, swapChain);
4314 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4315 IWineD3DSwapChain_Release(swapChain);
4318 return WINED3D_OK;
4321 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4322 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4324 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4326 GLbitfield glMask = 0;
4327 unsigned int i;
4328 CONST WINED3DRECT* curRect;
4330 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4331 Count, pRects, Flags, Z, Stencil);
4333 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4334 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4335 /* TODO: What about depth stencil buffers without stencil bits? */
4336 return WINED3DERR_INVALIDCALL;
4339 ENTER_GL();
4340 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4341 * and not the last active one.
4344 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4345 apply_fbo_state(iface);
4348 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4350 glEnable(GL_SCISSOR_TEST);
4351 checkGLcall("glEnable GL_SCISSOR_TEST");
4352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4355 if (Count > 0 && pRects) {
4356 curRect = pRects;
4357 } else {
4358 curRect = NULL;
4361 /* Only set the values up once, as they are not changing */
4362 if (Flags & WINED3DCLEAR_STENCIL) {
4363 glClearStencil(Stencil);
4364 checkGLcall("glClearStencil");
4365 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4366 glStencilMask(0xFFFFFFFF);
4369 if (Flags & WINED3DCLEAR_ZBUFFER) {
4370 glDepthMask(GL_TRUE);
4371 glClearDepth(Z);
4372 checkGLcall("glClearDepth");
4373 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4377 if (Flags & WINED3DCLEAR_TARGET) {
4378 TRACE("Clearing screen with glClear to color %x\n", Color);
4379 glClearColor(D3DCOLOR_R(Color),
4380 D3DCOLOR_G(Color),
4381 D3DCOLOR_B(Color),
4382 D3DCOLOR_A(Color));
4383 checkGLcall("glClearColor");
4385 /* Clear ALL colors! */
4386 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4387 glMask = glMask | GL_COLOR_BUFFER_BIT;
4390 if (!curRect) {
4391 /* In drawable flag is set below */
4393 glScissor(This->stateBlock->viewport.X,
4394 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4395 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4396 This->stateBlock->viewport.Width,
4397 This->stateBlock->viewport.Height);
4398 checkGLcall("glScissor");
4399 glClear(glMask);
4400 checkGLcall("glClear");
4401 } else {
4402 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4403 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4405 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4406 curRect[0].x2 < target->currentDesc.Width ||
4407 curRect[0].y2 < target->currentDesc.Height) {
4408 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4409 blt_to_drawable(This, target);
4413 /* Now process each rect in turn */
4414 for (i = 0; i < Count; i++) {
4415 /* Note gl uses lower left, width/height */
4416 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4417 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4418 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4419 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4421 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4422 * The rectangle is not cleared, no error is returned, but further rectanlges are
4423 * still cleared if they are valid
4425 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4426 TRACE("Rectangle with negative dimensions, ignoring\n");
4427 continue;
4430 if(This->render_offscreen) {
4431 glScissor(curRect[i].x1, curRect[i].y1,
4432 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4433 } else {
4434 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4435 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4437 checkGLcall("glScissor");
4439 glClear(glMask);
4440 checkGLcall("glClear");
4444 /* Restore the old values (why..?) */
4445 if (Flags & WINED3DCLEAR_STENCIL) {
4446 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4448 if (Flags & WINED3DCLEAR_TARGET) {
4449 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4450 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4451 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4452 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4453 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4456 LEAVE_GL();
4458 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4459 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4461 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4462 target->Flags |= SFLAG_INTEXTURE;
4463 target->Flags &= ~SFLAG_INSYSMEM;
4464 } else {
4465 target->Flags |= SFLAG_INDRAWABLE;
4466 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4468 return WINED3D_OK;
4471 /*****
4472 * Drawing functions
4473 *****/
4474 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4475 UINT PrimitiveCount) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4479 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4480 debug_d3dprimitivetype(PrimitiveType),
4481 StartVertex, PrimitiveCount);
4483 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4484 if(This->stateBlock->streamIsUP) {
4485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4486 This->stateBlock->streamIsUP = FALSE;
4489 if(This->stateBlock->loadBaseVertexIndex != 0) {
4490 This->stateBlock->loadBaseVertexIndex = 0;
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4493 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4494 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4495 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4496 return WINED3D_OK;
4499 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4500 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4501 WINED3DPRIMITIVETYPE PrimitiveType,
4502 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 UINT idxStride = 2;
4506 IWineD3DIndexBuffer *pIB;
4507 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4508 GLuint vbo;
4510 if(This->stateBlock->streamIsUP) {
4511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4512 This->stateBlock->streamIsUP = FALSE;
4514 pIB = This->stateBlock->pIndexData;
4515 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4517 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4518 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4519 minIndex, NumVertices, startIndex, primCount);
4521 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4522 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4523 idxStride = 2;
4524 } else {
4525 idxStride = 4;
4528 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4529 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4533 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4534 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4536 return WINED3D_OK;
4539 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4540 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4541 UINT VertexStreamZeroStride) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4544 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4545 debug_d3dprimitivetype(PrimitiveType),
4546 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4548 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4549 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4550 This->stateBlock->streamOffset[0] = 0;
4551 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4552 This->stateBlock->streamIsUP = TRUE;
4553 This->stateBlock->loadBaseVertexIndex = 0;
4555 /* TODO: Only mark dirty if drawing from a different UP address */
4556 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4558 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4559 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4561 /* MSDN specifies stream zero settings must be set to NULL */
4562 This->stateBlock->streamStride[0] = 0;
4563 This->stateBlock->streamSource[0] = NULL;
4565 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4566 * the new stream sources or use UP drawing again
4568 return WINED3D_OK;
4571 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4572 UINT MinVertexIndex, UINT NumVertices,
4573 UINT PrimitiveCount, CONST void* pIndexData,
4574 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4575 UINT VertexStreamZeroStride) {
4576 int idxStride;
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4580 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4581 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4582 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4584 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4585 idxStride = 2;
4586 } else {
4587 idxStride = 4;
4590 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4591 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4592 This->stateBlock->streamIsUP = TRUE;
4593 This->stateBlock->streamOffset[0] = 0;
4594 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4596 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4597 This->stateBlock->baseVertexIndex = 0;
4598 This->stateBlock->loadBaseVertexIndex = 0;
4599 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4600 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4603 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4605 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4606 This->stateBlock->streamSource[0] = NULL;
4607 This->stateBlock->streamStride[0] = 0;
4608 This->stateBlock->pIndexData = NULL;
4609 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4610 * SetStreamSource to specify a vertex buffer
4613 return WINED3D_OK;
4616 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4619 /* Mark the state dirty until we have nicer tracking
4620 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4621 * that value.
4623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4625 This->stateBlock->baseVertexIndex = 0;
4626 This->up_strided = DrawPrimStrideData;
4627 This->stateBlock->streamIsUP = TRUE;
4628 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4629 This->up_strided = NULL;
4630 return WINED3D_OK;
4632 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4633 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4635 HRESULT hr = WINED3D_OK;
4636 WINED3DRESOURCETYPE sourceType;
4637 WINED3DRESOURCETYPE destinationType;
4638 int i ,levels;
4640 /* TODO: think about moving the code into IWineD3DBaseTexture */
4642 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4644 /* verify that the source and destination textures aren't NULL */
4645 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4646 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4647 This, pSourceTexture, pDestinationTexture);
4648 hr = WINED3DERR_INVALIDCALL;
4651 if (pSourceTexture == pDestinationTexture) {
4652 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4653 This, pSourceTexture, pDestinationTexture);
4654 hr = WINED3DERR_INVALIDCALL;
4656 /* Verify that the source and destination textures are the same type */
4657 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4658 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4660 if (sourceType != destinationType) {
4661 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4662 This);
4663 hr = WINED3DERR_INVALIDCALL;
4666 /* check that both textures have the identical numbers of levels */
4667 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4668 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4669 hr = WINED3DERR_INVALIDCALL;
4672 if (WINED3D_OK == hr) {
4674 /* Make sure that the destination texture is loaded */
4675 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4677 /* Update every surface level of the texture */
4678 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4680 switch (sourceType) {
4681 case WINED3DRTYPE_TEXTURE:
4683 IWineD3DSurface *srcSurface;
4684 IWineD3DSurface *destSurface;
4686 for (i = 0 ; i < levels ; ++i) {
4687 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4688 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4689 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4690 IWineD3DSurface_Release(srcSurface);
4691 IWineD3DSurface_Release(destSurface);
4692 if (WINED3D_OK != hr) {
4693 WARN("(%p) : Call to update surface failed\n", This);
4694 return hr;
4698 break;
4699 case WINED3DRTYPE_CUBETEXTURE:
4701 IWineD3DSurface *srcSurface;
4702 IWineD3DSurface *destSurface;
4703 WINED3DCUBEMAP_FACES faceType;
4705 for (i = 0 ; i < levels ; ++i) {
4706 /* Update each cube face */
4707 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4708 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4709 if (WINED3D_OK != hr) {
4710 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4711 } else {
4712 TRACE("Got srcSurface %p\n", srcSurface);
4714 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4715 if (WINED3D_OK != hr) {
4716 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4717 } else {
4718 TRACE("Got desrSurface %p\n", destSurface);
4720 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4721 IWineD3DSurface_Release(srcSurface);
4722 IWineD3DSurface_Release(destSurface);
4723 if (WINED3D_OK != hr) {
4724 WARN("(%p) : Call to update surface failed\n", This);
4725 return hr;
4730 break;
4731 #if 0 /* TODO: Add support for volume textures */
4732 case WINED3DRTYPE_VOLUMETEXTURE:
4734 IWineD3DVolume srcVolume = NULL;
4735 IWineD3DSurface destVolume = NULL;
4737 for (i = 0 ; i < levels ; ++i) {
4738 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4739 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4740 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4741 IWineD3DVolume_Release(srcSurface);
4742 IWineD3DVolume_Release(destSurface);
4743 if (WINED3D_OK != hr) {
4744 WARN("(%p) : Call to update volume failed\n", This);
4745 return hr;
4749 break;
4750 #endif
4751 default:
4752 FIXME("(%p) : Unsupported source and destination type\n", This);
4753 hr = WINED3DERR_INVALIDCALL;
4757 return hr;
4760 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4761 IWineD3DSwapChain *swapChain;
4762 HRESULT hr;
4763 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4764 if(hr == WINED3D_OK) {
4765 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4766 IWineD3DSwapChain_Release(swapChain);
4768 return hr;
4771 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4773 /* return a sensible default */
4774 *pNumPasses = 1;
4775 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4776 FIXME("(%p) : stub\n", This);
4777 return WINED3D_OK;
4780 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4782 int j;
4783 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4784 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4785 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4786 return WINED3DERR_INVALIDCALL;
4788 for (j = 0; j < 256; ++j) {
4789 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4790 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4791 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4792 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4794 TRACE("(%p) : returning\n", This);
4795 return WINED3D_OK;
4798 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, 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 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4808 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4809 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4810 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4812 TRACE("(%p) : returning\n", This);
4813 return WINED3D_OK;
4816 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4818 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4819 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4820 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4821 return WINED3DERR_INVALIDCALL;
4823 /*TODO: stateblocks */
4824 This->currentPalette = PaletteNumber;
4825 TRACE("(%p) : returning\n", This);
4826 return WINED3D_OK;
4829 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4831 if (PaletteNumber == NULL) {
4832 WARN("(%p) : returning Invalid Call\n", This);
4833 return WINED3DERR_INVALIDCALL;
4835 /*TODO: stateblocks */
4836 *PaletteNumber = This->currentPalette;
4837 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4838 return WINED3D_OK;
4841 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4843 static BOOL showFixmes = TRUE;
4844 if (showFixmes) {
4845 FIXME("(%p) : stub\n", This);
4846 showFixmes = FALSE;
4849 This->softwareVertexProcessing = bSoftware;
4850 return WINED3D_OK;
4854 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 static BOOL showFixmes = TRUE;
4857 if (showFixmes) {
4858 FIXME("(%p) : stub\n", This);
4859 showFixmes = FALSE;
4861 return This->softwareVertexProcessing;
4865 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4867 IWineD3DSwapChain *swapChain;
4868 HRESULT hr;
4870 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4872 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4873 if(hr == WINED3D_OK){
4874 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4875 IWineD3DSwapChain_Release(swapChain);
4876 }else{
4877 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4879 return hr;
4883 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4885 static BOOL showfixmes = TRUE;
4886 if(nSegments != 0.0f) {
4887 if( showfixmes) {
4888 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4889 showfixmes = FALSE;
4892 return WINED3D_OK;
4895 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4897 static BOOL showfixmes = TRUE;
4898 if( showfixmes) {
4899 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4900 showfixmes = FALSE;
4902 return 0.0f;
4905 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4907 /** TODO: remove casts to IWineD3DSurfaceImpl
4908 * NOTE: move code to surface to accomplish this
4909 ****************************************/
4910 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4911 int srcWidth, srcHeight;
4912 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4913 WINED3DFORMAT destFormat, srcFormat;
4914 UINT destSize;
4915 int srcLeft, destLeft, destTop;
4916 WINED3DPOOL srcPool, destPool;
4917 int offset = 0;
4918 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4919 glDescriptor *glDescription = NULL;
4921 WINED3DSURFACE_DESC winedesc;
4923 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4924 memset(&winedesc, 0, sizeof(winedesc));
4925 winedesc.Width = &srcSurfaceWidth;
4926 winedesc.Height = &srcSurfaceHeight;
4927 winedesc.Pool = &srcPool;
4928 winedesc.Format = &srcFormat;
4930 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4932 winedesc.Width = &destSurfaceWidth;
4933 winedesc.Height = &destSurfaceHeight;
4934 winedesc.Pool = &destPool;
4935 winedesc.Format = &destFormat;
4936 winedesc.Size = &destSize;
4938 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4940 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4941 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4942 return WINED3DERR_INVALIDCALL;
4945 if (destFormat == WINED3DFMT_UNKNOWN) {
4946 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4947 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4949 /* Get the update surface description */
4950 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4953 ENTER_GL();
4955 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4957 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4958 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4959 checkGLcall("glActiveTextureARB");
4962 /* Make sure the surface is loaded and up to date */
4963 IWineD3DSurface_PreLoad(pDestinationSurface);
4965 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4967 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4968 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4969 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4970 srcLeft = pSourceRect ? pSourceRect->left : 0;
4971 destLeft = pDestPoint ? pDestPoint->x : 0;
4972 destTop = pDestPoint ? pDestPoint->y : 0;
4975 /* This function doesn't support compressed textures
4976 the pitch is just bytesPerPixel * width */
4977 if(srcWidth != srcSurfaceWidth || srcLeft ){
4978 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4979 offset += srcLeft * pSrcSurface->bytesPerPixel;
4980 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4982 /* TODO DXT formats */
4984 if(pSourceRect != NULL && pSourceRect->top != 0){
4985 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4987 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4988 ,This
4989 ,glDescription->level
4990 ,destLeft
4991 ,destTop
4992 ,srcWidth
4993 ,srcHeight
4994 ,glDescription->glFormat
4995 ,glDescription->glType
4996 ,IWineD3DSurface_GetData(pSourceSurface)
4999 /* Sanity check */
5000 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5002 /* need to lock the surface to get the data */
5003 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5006 /* TODO: Cube and volume support */
5007 if(rowoffset != 0){
5008 /* not a whole row so we have to do it a line at a time */
5009 int j;
5011 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5012 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5014 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5016 glTexSubImage2D(glDescription->target
5017 ,glDescription->level
5018 ,destLeft
5020 ,srcWidth
5022 ,glDescription->glFormat
5023 ,glDescription->glType
5024 ,data /* could be quicker using */
5026 data += rowoffset;
5029 } else { /* Full width, so just write out the whole texture */
5031 if (WINED3DFMT_DXT1 == destFormat ||
5032 WINED3DFMT_DXT2 == destFormat ||
5033 WINED3DFMT_DXT3 == destFormat ||
5034 WINED3DFMT_DXT4 == destFormat ||
5035 WINED3DFMT_DXT5 == destFormat) {
5036 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5037 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5038 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5039 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5040 } if (destFormat != srcFormat) {
5041 FIXME("Updating mixed format compressed texture is not curretly support\n");
5042 } else {
5043 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5044 glDescription->level,
5045 glDescription->glFormatInternal,
5046 srcWidth,
5047 srcHeight,
5049 destSize,
5050 IWineD3DSurface_GetData(pSourceSurface));
5052 } else {
5053 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5057 } else {
5058 glTexSubImage2D(glDescription->target
5059 ,glDescription->level
5060 ,destLeft
5061 ,destTop
5062 ,srcWidth
5063 ,srcHeight
5064 ,glDescription->glFormat
5065 ,glDescription->glType
5066 ,IWineD3DSurface_GetData(pSourceSurface)
5070 checkGLcall("glTexSubImage2D");
5072 LEAVE_GL();
5074 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5075 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5078 return WINED3D_OK;
5081 /* Implementation details at http://developer.nvidia.com/attach/6494
5083 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5084 hmm.. no longer supported use
5085 OpenGL evaluators or tessellate surfaces within your application.
5088 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5089 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5091 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5092 FIXME("(%p) : Stub\n", This);
5093 return WINED3D_OK;
5097 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5098 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5100 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5101 FIXME("(%p) : Stub\n", This);
5102 return WINED3D_OK;
5105 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5107 TRACE("(%p) Handle(%d)\n", This, Handle);
5108 FIXME("(%p) : Stub\n", This);
5109 return WINED3D_OK;
5112 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5113 HRESULT hr;
5114 IWineD3DSwapChain *swapchain;
5116 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5117 if (SUCCEEDED(hr)) {
5118 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5119 return swapchain;
5122 return NULL;
5125 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5128 if (!*fbo) {
5129 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5130 checkGLcall("glGenFramebuffersEXT()");
5132 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5133 checkGLcall("glBindFramebuffer()");
5136 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5137 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5138 GLenum texttarget, target;
5139 GLint old_binding;
5141 texttarget = surface_impl->glDescription.target;
5142 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5143 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5145 IWineD3DSurface_PreLoad(surface);
5147 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5148 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5149 glBindTexture(target, old_binding);
5151 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5153 checkGLcall("attach_surface_fbo");
5156 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5158 IWineD3DSwapChain *swapchain;
5160 swapchain = get_swapchain(surface);
5161 if (swapchain) {
5162 GLenum buffer;
5164 TRACE("Surface %p is onscreen\n", surface);
5166 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5167 buffer = surface_get_gl_buffer(surface, swapchain);
5168 glDrawBuffer(buffer);
5169 checkGLcall("glDrawBuffer()");
5170 } else {
5171 TRACE("Surface %p is offscreen\n", surface);
5172 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5173 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5176 if (rect) {
5177 glEnable(GL_SCISSOR_TEST);
5178 if(!swapchain) {
5179 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5180 } else {
5181 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5182 rect->x2 - rect->x1, rect->y2 - rect->y1);
5184 checkGLcall("glScissor");
5185 } else {
5186 glDisable(GL_SCISSOR_TEST);
5188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5190 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5193 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5194 glClear(GL_COLOR_BUFFER_BIT);
5195 checkGLcall("glClear");
5197 if (This->render_offscreen) {
5198 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5199 } else {
5200 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5201 checkGLcall("glBindFramebuffer()");
5204 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5205 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5206 glDrawBuffer(GL_BACK);
5207 checkGLcall("glDrawBuffer()");
5211 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5213 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5214 WINEDDBLTFX BltFx;
5215 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5217 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5218 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5219 return WINED3DERR_INVALIDCALL;
5222 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5223 color_fill_fbo(iface, pSurface, pRect, color);
5224 return WINED3D_OK;
5225 } else {
5226 /* Just forward this to the DirectDraw blitting engine */
5227 memset(&BltFx, 0, sizeof(BltFx));
5228 BltFx.dwSize = sizeof(BltFx);
5229 BltFx.u5.dwFillColor = color;
5230 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5234 /* rendertarget and deptth stencil functions */
5235 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5238 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5239 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5240 return WINED3DERR_INVALIDCALL;
5243 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5244 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5245 /* Note inc ref on returned surface */
5246 if(*ppRenderTarget != NULL)
5247 IWineD3DSurface_AddRef(*ppRenderTarget);
5248 return WINED3D_OK;
5251 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5254 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5255 IWineD3DSwapChainImpl *Swapchain;
5256 HRESULT hr;
5258 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5260 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5261 if(hr != WINED3D_OK) {
5262 ERR("Can't get the swapchain\n");
5263 return hr;
5266 /* Make sure to release the swapchain */
5267 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5269 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5270 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5271 return WINED3DERR_INVALIDCALL;
5273 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5274 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5275 return WINED3DERR_INVALIDCALL;
5278 if(Swapchain->frontBuffer != Front) {
5279 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5281 if(Swapchain->frontBuffer)
5282 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5283 Swapchain->frontBuffer = Front;
5285 if(Swapchain->frontBuffer) {
5286 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5290 if(Back && !Swapchain->backBuffer) {
5291 /* We need memory for the back buffer array - only one back buffer this way */
5292 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5293 if(!Swapchain->backBuffer) {
5294 ERR("Out of memory\n");
5295 return E_OUTOFMEMORY;
5299 if(Swapchain->backBuffer[0] != Back) {
5300 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5302 /* What to do about the context here in the case of multithreading? Not sure.
5303 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5305 ENTER_GL();
5306 if(!Swapchain->backBuffer[0]) {
5307 /* GL was told to draw to the front buffer at creation,
5308 * undo that
5310 glDrawBuffer(GL_BACK);
5311 checkGLcall("glDrawBuffer(GL_BACK)");
5312 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5313 Swapchain->presentParms.BackBufferCount = 1;
5314 } else if (!Back) {
5315 /* That makes problems - disable for now */
5316 /* glDrawBuffer(GL_FRONT); */
5317 checkGLcall("glDrawBuffer(GL_FRONT)");
5318 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5319 Swapchain->presentParms.BackBufferCount = 0;
5321 LEAVE_GL();
5323 if(Swapchain->backBuffer[0])
5324 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5325 Swapchain->backBuffer[0] = Back;
5327 if(Swapchain->backBuffer[0]) {
5328 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5329 } else {
5330 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5335 return WINED3D_OK;
5338 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5340 *ppZStencilSurface = This->depthStencilBuffer;
5341 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5343 if(*ppZStencilSurface != NULL) {
5344 /* Note inc ref on returned surface */
5345 IWineD3DSurface_AddRef(*ppZStencilSurface);
5347 return WINED3D_OK;
5350 /* TODO: Handle stencil attachments */
5351 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5353 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5355 TRACE("Set depth stencil to %p\n", depth_stencil);
5357 if (depth_stencil_impl) {
5358 if (depth_stencil_impl->current_renderbuffer) {
5359 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5360 checkGLcall("glFramebufferRenderbufferEXT()");
5361 } else {
5362 GLenum texttarget, target;
5363 GLint old_binding = 0;
5365 texttarget = depth_stencil_impl->glDescription.target;
5366 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5367 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5369 IWineD3DSurface_PreLoad(depth_stencil);
5371 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5372 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5373 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5374 glBindTexture(target, old_binding);
5376 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5377 checkGLcall("glFramebufferTexture2DEXT()");
5379 } else {
5380 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5381 checkGLcall("glFramebufferTexture2DEXT()");
5385 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5387 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5389 TRACE("Set render target %u to %p\n", idx, render_target);
5391 if (rtimpl) {
5392 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5393 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5394 } else {
5395 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5396 checkGLcall("glFramebufferTexture2DEXT()");
5398 This->draw_buffers[idx] = GL_NONE;
5402 static void check_fbo_status(IWineD3DDevice *iface) {
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 GLenum status;
5406 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5407 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5408 TRACE("FBO complete\n");
5409 } else {
5410 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5412 /* Dump the FBO attachments */
5413 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5414 IWineD3DSurfaceImpl *attachment;
5415 int i;
5417 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5418 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5419 if (attachment) {
5420 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5421 attachment->pow2Width, attachment->pow2Height);
5424 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5425 if (attachment) {
5426 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5427 attachment->pow2Width, attachment->pow2Height);
5433 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5435 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5436 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5438 if (!ds_impl) return FALSE;
5440 if (ds_impl->current_renderbuffer) {
5441 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5442 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5445 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5446 rt_impl->pow2Height != ds_impl->pow2Height);
5449 void apply_fbo_state(IWineD3DDevice *iface) {
5450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5451 unsigned int i;
5453 if (This->render_offscreen) {
5454 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5456 /* Apply render targets */
5457 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5458 IWineD3DSurface *render_target = This->render_targets[i];
5459 if (This->fbo_color_attachments[i] != render_target) {
5460 set_render_target_fbo(iface, i, render_target);
5461 This->fbo_color_attachments[i] = render_target;
5465 /* Apply depth targets */
5466 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5467 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5468 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5470 if (This->stencilBufferTarget) {
5471 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5473 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5474 This->fbo_depth_attachment = This->stencilBufferTarget;
5477 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5478 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5479 checkGLcall("glDrawBuffers()");
5480 } else {
5481 glDrawBuffer(This->draw_buffers[0]);
5482 checkGLcall("glDrawBuffer()");
5484 } else {
5485 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5488 check_fbo_status(iface);
5491 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5492 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5494 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5495 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5496 GLenum gl_filter;
5498 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5499 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5500 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5501 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5503 glDisable(GL_SCISSOR_TEST);
5504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5506 switch (filter) {
5507 case WINED3DTEXF_LINEAR:
5508 gl_filter = GL_LINEAR;
5509 break;
5511 default:
5512 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5513 case WINED3DTEXF_NONE:
5514 case WINED3DTEXF_POINT:
5515 gl_filter = GL_NEAREST;
5516 break;
5519 /* Attach src surface to src fbo */
5520 src_swapchain = get_swapchain(src_surface);
5521 if (src_swapchain) {
5522 GLenum buffer;
5524 TRACE("Source surface %p is onscreen\n", src_surface);
5526 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5527 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5528 glReadBuffer(buffer);
5529 checkGLcall("glReadBuffer()");
5531 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5532 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5533 } else {
5534 TRACE("Source surface %p is offscreen\n", src_surface);
5535 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5536 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5537 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5538 checkGLcall("glReadBuffer()");
5541 /* Attach dst surface to dst fbo */
5542 dst_swapchain = get_swapchain(dst_surface);
5543 if (dst_swapchain) {
5544 GLenum buffer;
5546 TRACE("Destination surface %p is onscreen\n", dst_surface);
5548 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5549 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5550 glDrawBuffer(buffer);
5551 checkGLcall("glDrawBuffer()");
5553 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5554 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5555 } else {
5556 TRACE("Destination surface %p is offscreen\n", dst_surface);
5557 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5558 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5559 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5560 checkGLcall("glDrawBuffer()");
5563 if (flip) {
5564 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5565 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5566 } else {
5567 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5568 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5571 if (This->render_offscreen) {
5572 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5573 } else {
5574 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5575 checkGLcall("glBindFramebuffer()");
5578 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5579 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5580 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5581 glDrawBuffer(GL_BACK);
5582 checkGLcall("glDrawBuffer()");
5586 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5588 WINED3DVIEWPORT viewport;
5590 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5592 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5593 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5594 return WINED3DERR_INVALIDCALL;
5597 /* MSDN says that null disables the render target
5598 but a device must always be associated with a render target
5599 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5601 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5602 for more details
5604 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5605 FIXME("Trying to set render target 0 to NULL\n");
5606 return WINED3DERR_INVALIDCALL;
5608 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5609 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);
5610 return WINED3DERR_INVALIDCALL;
5613 /* If we are trying to set what we already have, don't bother */
5614 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5615 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5616 return WINED3D_OK;
5618 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5619 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5620 This->render_targets[RenderTargetIndex] = pRenderTarget;
5622 /* Render target 0 is special */
5623 if(RenderTargetIndex == 0) {
5624 /* Finally, reset the viewport as the MSDN states. */
5625 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5626 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5627 viewport.X = 0;
5628 viewport.Y = 0;
5629 viewport.MaxZ = 1.0f;
5630 viewport.MinZ = 0.0f;
5631 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5632 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5633 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5637 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5638 * ctx properly.
5639 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5640 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5642 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5644 return WINED3D_OK;
5647 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5649 HRESULT hr = WINED3D_OK;
5650 IWineD3DSurface *tmp;
5652 TRACE("(%p) Swapping z-buffer\n",This);
5654 if (pNewZStencil == This->stencilBufferTarget) {
5655 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5656 } else {
5657 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5658 * depending on the renter target implementation being used.
5659 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5660 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5661 * stencil buffer and incure an extra memory overhead
5662 ******************************************************/
5664 tmp = This->stencilBufferTarget;
5665 This->stencilBufferTarget = pNewZStencil;
5666 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5667 /* should we be calling the parent or the wined3d surface? */
5668 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5669 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5670 hr = WINED3D_OK;
5672 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5673 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5676 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5680 return hr;
5683 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5684 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5686 /* TODO: the use of Impl is deprecated. */
5687 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5688 WINED3DLOCKED_RECT lockedRect;
5690 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5692 /* some basic validation checks */
5693 if(This->cursorTexture) {
5694 ENTER_GL();
5695 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5696 glDeleteTextures(1, &This->cursorTexture);
5697 LEAVE_GL();
5698 This->cursorTexture = 0;
5701 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5702 This->haveHardwareCursor = TRUE;
5703 else
5704 This->haveHardwareCursor = FALSE;
5706 if(pCursorBitmap) {
5707 WINED3DLOCKED_RECT rect;
5709 /* MSDN: Cursor must be A8R8G8B8 */
5710 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5711 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5712 return WINED3DERR_INVALIDCALL;
5715 /* MSDN: Cursor must be smaller than the display mode */
5716 if(pSur->currentDesc.Width > This->ddraw_width ||
5717 pSur->currentDesc.Height > This->ddraw_height) {
5718 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);
5719 return WINED3DERR_INVALIDCALL;
5722 if (!This->haveHardwareCursor) {
5723 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5725 /* Do not store the surface's pointer because the application may
5726 * release it after setting the cursor image. Windows doesn't
5727 * addref the set surface, so we can't do this either without
5728 * creating circular refcount dependencies. Copy out the gl texture
5729 * instead.
5731 This->cursorWidth = pSur->currentDesc.Width;
5732 This->cursorHeight = pSur->currentDesc.Height;
5733 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5735 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5736 char *mem, *bits = (char *)rect.pBits;
5737 GLint intfmt = tableEntry->glInternal;
5738 GLint format = tableEntry->glFormat;
5739 GLint type = tableEntry->glType;
5740 INT height = This->cursorHeight;
5741 INT width = This->cursorWidth;
5742 INT bpp = tableEntry->bpp;
5743 INT i;
5745 /* Reformat the texture memory (pitch and width can be
5746 * different) */
5747 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5748 for(i = 0; i < height; i++)
5749 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5750 IWineD3DSurface_UnlockRect(pCursorBitmap);
5751 ENTER_GL();
5753 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5754 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5755 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5758 /* Make sure that a proper texture unit is selected */
5759 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5760 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5761 checkGLcall("glActiveTextureARB");
5763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5764 /* Create a new cursor texture */
5765 glGenTextures(1, &This->cursorTexture);
5766 checkGLcall("glGenTextures");
5767 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5768 checkGLcall("glBindTexture");
5769 /* Copy the bitmap memory into the cursor texture */
5770 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5771 HeapFree(GetProcessHeap(), 0, mem);
5772 checkGLcall("glTexImage2D");
5774 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5775 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5776 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5779 LEAVE_GL();
5781 else
5783 FIXME("A cursor texture was not returned.\n");
5784 This->cursorTexture = 0;
5787 else
5789 /* Draw a hardware cursor */
5790 ICONINFO cursorInfo;
5791 HCURSOR cursor;
5792 DWORD *maskBits = (DWORD *) HeapAlloc(GetProcessHeap(), 0,
5793 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5794 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5795 WINED3DLOCK_NO_DIRTY_UPDATE |
5796 WINED3DLOCK_READONLY
5798 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5799 pSur->currentDesc.Height);
5801 cursorInfo.fIcon = FALSE;
5802 cursorInfo.xHotspot = XHotSpot;
5803 cursorInfo.yHotspot = YHotSpot;
5805 /* Clear maskBits because it is not needed for 32-bit cursors.
5806 * 32x32 bits split into 32-bit chunks == 32 chunks. */
5807 ZeroMemory(maskBits,
5808 pSur->currentDesc.Width * pSur->currentDesc.Height / 8);
5809 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5810 pSur->currentDesc.Height, 1,
5811 1, &maskBits);
5812 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5813 pSur->currentDesc.Height, 1,
5814 32, lockedRect.pBits);
5815 IWineD3DSurface_UnlockRect(pCursorBitmap);
5816 /* Create our cursor and clean up. */
5817 cursor = CreateIconIndirect(&cursorInfo);
5818 SetCursor(cursor);
5819 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5820 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5821 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5822 This->hardwareCursor = cursor;
5823 HeapFree(GetProcessHeap(), 0, maskBits);
5827 This->xHotSpot = XHotSpot;
5828 This->yHotSpot = YHotSpot;
5829 return WINED3D_OK;
5832 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5834 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5836 This->xScreenSpace = XScreenSpace;
5837 This->yScreenSpace = YScreenSpace;
5839 return;
5843 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5845 BOOL oldVisible = This->bCursorVisible;
5846 POINT pt;
5848 TRACE("(%p) : visible(%d)\n", This, bShow);
5851 * When ShowCursor is first called it should make the cursor appear at the OS's last
5852 * known cursor position. Because of this, some applications just repetitively call
5853 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5855 GetCursorPos(&pt);
5856 This->xScreenSpace = pt.x;
5857 This->yScreenSpace = pt.y;
5859 if (This->haveHardwareCursor) {
5860 This->bCursorVisible = bShow;
5861 while (ShowCursor(TRUE) < 0) ;
5862 if (bShow)
5863 SetCursor(This->hardwareCursor);
5864 else
5865 SetCursor(NULL);
5867 else
5869 if (This->cursorTexture)
5870 This->bCursorVisible = bShow;
5871 if (This->bCursorVisible)
5872 while (ShowCursor(TRUE) < 0) ;
5873 else
5874 while (ShowCursor(FALSE) >= 0) ;
5877 return oldVisible;
5880 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5882 TRACE("(%p) : state (%u)\n", This, This->state);
5883 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5884 switch (This->state) {
5885 case WINED3D_OK:
5886 return WINED3D_OK;
5887 case WINED3DERR_DEVICELOST:
5889 ResourceList *resourceList = This->resources;
5890 while (NULL != resourceList) {
5891 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5892 return WINED3DERR_DEVICENOTRESET;
5893 resourceList = resourceList->next;
5895 return WINED3DERR_DEVICELOST;
5897 case WINED3DERR_DRIVERINTERNALERROR:
5898 return WINED3DERR_DRIVERINTERNALERROR;
5901 /* Unknown state */
5902 return WINED3DERR_DRIVERINTERNALERROR;
5906 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5908 /** FIXME: Resource tracking needs to be done,
5909 * The closes we can do to this is set the priorities of all managed textures low
5910 * and then reset them.
5911 ***********************************************************/
5912 FIXME("(%p) : stub\n", This);
5913 return WINED3D_OK;
5916 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5917 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5919 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5920 if(surface->Flags & SFLAG_DIBSECTION) {
5921 /* Release the DC */
5922 SelectObject(surface->hDC, surface->dib.holdbitmap);
5923 DeleteDC(surface->hDC);
5924 /* Release the DIB section */
5925 DeleteObject(surface->dib.DIBsection);
5926 surface->dib.bitmap_data = NULL;
5927 surface->resource.allocatedMemory = NULL;
5928 surface->Flags &= ~SFLAG_DIBSECTION;
5930 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5931 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5932 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5933 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5934 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5935 } else {
5936 surface->pow2Width = surface->pow2Height = 1;
5937 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5938 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5940 if(surface->glDescription.textureName) {
5941 ENTER_GL();
5942 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5943 glDeleteTextures(1, &surface->glDescription.textureName);
5944 LEAVE_GL();
5945 surface->glDescription.textureName = 0;
5946 surface->Flags &= ~SFLAG_CLIENT;
5948 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5949 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5950 surface->Flags |= SFLAG_NONPOW2;
5951 } else {
5952 surface->Flags &= ~SFLAG_NONPOW2;
5954 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5955 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5958 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5960 IWineD3DSwapChainImpl *swapchain;
5961 HRESULT hr;
5962 BOOL DisplayModeChanged = FALSE;
5963 WINED3DDISPLAYMODE mode;
5964 TRACE("(%p)\n", This);
5966 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5967 if(FAILED(hr)) {
5968 ERR("Failed to get the first implicit swapchain\n");
5969 return hr;
5972 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5973 * on an existing gl context, so there's no real need for recreation.
5975 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5977 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5979 TRACE("New params:\n");
5980 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5981 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5982 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5983 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5984 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5985 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5986 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5987 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5988 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5989 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5990 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5991 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5992 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5994 /* No special treatment of these parameters. Just store them */
5995 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5996 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5997 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5998 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6000 /* What to do about these? */
6001 if(pPresentationParameters->BackBufferCount != 0 &&
6002 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6003 ERR("Cannot change the back buffer count yet\n");
6005 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6006 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6007 ERR("Cannot change the back buffer format yet\n");
6009 if(pPresentationParameters->hDeviceWindow != NULL &&
6010 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6011 ERR("Cannot change the device window yet\n");
6013 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6014 ERR("What do do about a changed auto depth stencil parameter?\n");
6017 if(pPresentationParameters->Windowed) {
6018 mode.Width = swapchain->orig_width;
6019 mode.Height = swapchain->orig_height;
6020 mode.RefreshRate = 0;
6021 mode.Format = swapchain->presentParms.BackBufferFormat;
6022 } else {
6023 mode.Width = pPresentationParameters->BackBufferWidth;
6024 mode.Height = pPresentationParameters->BackBufferHeight;
6025 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6026 mode.Format = swapchain->presentParms.BackBufferFormat;
6028 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6029 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6030 pPresentationParameters->BackBufferWidth,
6031 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6034 /* Should Width == 800 && Height == 0 set 800x600? */
6035 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6036 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6037 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6039 WINED3DVIEWPORT vp;
6040 int i;
6042 vp.X = 0;
6043 vp.Y = 0;
6044 vp.Width = pPresentationParameters->BackBufferWidth;
6045 vp.Height = pPresentationParameters->BackBufferHeight;
6046 vp.MinZ = 0;
6047 vp.MaxZ = 1;
6049 if(!pPresentationParameters->Windowed) {
6050 DisplayModeChanged = TRUE;
6052 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6053 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6055 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6056 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6057 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6060 /* Now set the new viewport */
6061 IWineD3DDevice_SetViewport(iface, &vp);
6064 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6065 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6066 DisplayModeChanged) {
6068 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6069 if(!pPresentationParameters->Windowed) {
6070 IWineD3DDevice_SetFullscreen(iface, TRUE);
6073 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6075 /* Switching out of fullscreen mode? First set the original res, then change the window */
6076 if(pPresentationParameters->Windowed) {
6077 IWineD3DDevice_SetFullscreen(iface, FALSE);
6079 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6082 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6083 return WINED3D_OK;
6086 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6088 /** FIXME: always true at the moment **/
6089 if(!bEnableDialogs) {
6090 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6092 return WINED3D_OK;
6096 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6098 TRACE("(%p) : pParameters %p\n", This, pParameters);
6100 *pParameters = This->createParms;
6101 return WINED3D_OK;
6104 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6105 IWineD3DSwapChain *swapchain;
6106 HRESULT hrc = WINED3D_OK;
6108 TRACE("Relaying to swapchain\n");
6110 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6111 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6112 IWineD3DSwapChain_Release(swapchain);
6114 return;
6117 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6118 IWineD3DSwapChain *swapchain;
6119 HRESULT hrc = WINED3D_OK;
6121 TRACE("Relaying to swapchain\n");
6123 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6124 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6125 IWineD3DSwapChain_Release(swapchain);
6127 return;
6131 /** ********************************************************
6132 * Notification functions
6133 ** ********************************************************/
6134 /** This function must be called in the release of a resource when ref == 0,
6135 * the contents of resource must still be correct,
6136 * any handels to other resource held by the caller must be closed
6137 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6138 *****************************************************/
6139 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6141 ResourceList* resourceList;
6143 TRACE("(%p) : resource %p\n", This, resource);
6144 /* add a new texture to the frot of the linked list */
6145 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6146 resourceList->resource = resource;
6148 /* Get the old head */
6149 resourceList->next = This->resources;
6151 This->resources = resourceList;
6152 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6154 return;
6157 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6159 ResourceList* resourceList = NULL;
6160 ResourceList* previousResourceList = NULL;
6162 TRACE("(%p) : resource %p\n", This, resource);
6164 resourceList = This->resources;
6166 while (resourceList != NULL) {
6167 if(resourceList->resource == resource) break;
6168 previousResourceList = resourceList;
6169 resourceList = resourceList->next;
6172 if (resourceList == NULL) {
6173 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6174 return;
6175 } else {
6176 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6178 /* make sure we don't leave a hole in the list */
6179 if (previousResourceList != NULL) {
6180 previousResourceList->next = resourceList->next;
6181 } else {
6182 This->resources = resourceList->next;
6185 return;
6189 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6191 int counter;
6193 TRACE("(%p) : resource %p\n", This, resource);
6194 switch(IWineD3DResource_GetType(resource)){
6195 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6196 case WINED3DRTYPE_SURFACE: {
6197 unsigned int i;
6199 /* Cleanup any FBO attachments */
6200 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6201 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6202 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6203 set_render_target_fbo(iface, i, NULL);
6204 This->fbo_color_attachments[i] = NULL;
6207 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6208 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6209 set_depth_stencil_fbo(iface, NULL);
6210 This->fbo_depth_attachment = NULL;
6213 break;
6216 case WINED3DRTYPE_TEXTURE:
6217 case WINED3DRTYPE_CUBETEXTURE:
6218 case WINED3DRTYPE_VOLUMETEXTURE:
6219 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6220 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6221 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6222 This->stateBlock->textures[counter] = NULL;
6224 if (This->updateStateBlock != This->stateBlock ){
6225 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6226 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6227 This->updateStateBlock->textures[counter] = NULL;
6231 break;
6232 case WINED3DRTYPE_VOLUME:
6233 /* TODO: nothing really? */
6234 break;
6235 case WINED3DRTYPE_VERTEXBUFFER:
6236 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6238 int streamNumber;
6239 TRACE("Cleaning up stream pointers\n");
6241 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6242 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6243 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6245 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6246 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6247 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6248 This->updateStateBlock->streamSource[streamNumber] = 0;
6249 /* Set changed flag? */
6252 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) */
6253 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6254 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6255 This->stateBlock->streamSource[streamNumber] = 0;
6258 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6259 else { /* This shouldn't happen */
6260 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6262 #endif
6266 break;
6267 case WINED3DRTYPE_INDEXBUFFER:
6268 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6269 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6270 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6271 This->updateStateBlock->pIndexData = NULL;
6274 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6275 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6276 This->stateBlock->pIndexData = NULL;
6280 break;
6281 default:
6282 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6283 break;
6287 /* Remove the resoruce from the resourceStore */
6288 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6290 TRACE("Resource released\n");
6294 /**********************************************************
6295 * IWineD3DDevice VTbl follows
6296 **********************************************************/
6298 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6300 /*** IUnknown methods ***/
6301 IWineD3DDeviceImpl_QueryInterface,
6302 IWineD3DDeviceImpl_AddRef,
6303 IWineD3DDeviceImpl_Release,
6304 /*** IWineD3DDevice methods ***/
6305 IWineD3DDeviceImpl_GetParent,
6306 /*** Creation methods**/
6307 IWineD3DDeviceImpl_CreateVertexBuffer,
6308 IWineD3DDeviceImpl_CreateIndexBuffer,
6309 IWineD3DDeviceImpl_CreateStateBlock,
6310 IWineD3DDeviceImpl_CreateSurface,
6311 IWineD3DDeviceImpl_CreateTexture,
6312 IWineD3DDeviceImpl_CreateVolumeTexture,
6313 IWineD3DDeviceImpl_CreateVolume,
6314 IWineD3DDeviceImpl_CreateCubeTexture,
6315 IWineD3DDeviceImpl_CreateQuery,
6316 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6317 IWineD3DDeviceImpl_CreateVertexDeclaration,
6318 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6319 IWineD3DDeviceImpl_CreateVertexShader,
6320 IWineD3DDeviceImpl_CreatePixelShader,
6321 IWineD3DDeviceImpl_CreatePalette,
6322 /*** Odd functions **/
6323 IWineD3DDeviceImpl_Init3D,
6324 IWineD3DDeviceImpl_Uninit3D,
6325 IWineD3DDeviceImpl_SetFullscreen,
6326 IWineD3DDeviceImpl_SetMultithreaded,
6327 IWineD3DDeviceImpl_EvictManagedResources,
6328 IWineD3DDeviceImpl_GetAvailableTextureMem,
6329 IWineD3DDeviceImpl_GetBackBuffer,
6330 IWineD3DDeviceImpl_GetCreationParameters,
6331 IWineD3DDeviceImpl_GetDeviceCaps,
6332 IWineD3DDeviceImpl_GetDirect3D,
6333 IWineD3DDeviceImpl_GetDisplayMode,
6334 IWineD3DDeviceImpl_SetDisplayMode,
6335 IWineD3DDeviceImpl_GetHWND,
6336 IWineD3DDeviceImpl_SetHWND,
6337 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6338 IWineD3DDeviceImpl_GetRasterStatus,
6339 IWineD3DDeviceImpl_GetSwapChain,
6340 IWineD3DDeviceImpl_Reset,
6341 IWineD3DDeviceImpl_SetDialogBoxMode,
6342 IWineD3DDeviceImpl_SetCursorProperties,
6343 IWineD3DDeviceImpl_SetCursorPosition,
6344 IWineD3DDeviceImpl_ShowCursor,
6345 IWineD3DDeviceImpl_TestCooperativeLevel,
6346 /*** Getters and setters **/
6347 IWineD3DDeviceImpl_SetClipPlane,
6348 IWineD3DDeviceImpl_GetClipPlane,
6349 IWineD3DDeviceImpl_SetClipStatus,
6350 IWineD3DDeviceImpl_GetClipStatus,
6351 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6352 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6353 IWineD3DDeviceImpl_SetDepthStencilSurface,
6354 IWineD3DDeviceImpl_GetDepthStencilSurface,
6355 IWineD3DDeviceImpl_SetFVF,
6356 IWineD3DDeviceImpl_GetFVF,
6357 IWineD3DDeviceImpl_SetGammaRamp,
6358 IWineD3DDeviceImpl_GetGammaRamp,
6359 IWineD3DDeviceImpl_SetIndices,
6360 IWineD3DDeviceImpl_GetIndices,
6361 IWineD3DDeviceImpl_SetBasevertexIndex,
6362 IWineD3DDeviceImpl_SetLight,
6363 IWineD3DDeviceImpl_GetLight,
6364 IWineD3DDeviceImpl_SetLightEnable,
6365 IWineD3DDeviceImpl_GetLightEnable,
6366 IWineD3DDeviceImpl_SetMaterial,
6367 IWineD3DDeviceImpl_GetMaterial,
6368 IWineD3DDeviceImpl_SetNPatchMode,
6369 IWineD3DDeviceImpl_GetNPatchMode,
6370 IWineD3DDeviceImpl_SetPaletteEntries,
6371 IWineD3DDeviceImpl_GetPaletteEntries,
6372 IWineD3DDeviceImpl_SetPixelShader,
6373 IWineD3DDeviceImpl_GetPixelShader,
6374 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6375 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6376 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6377 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6378 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6379 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6380 IWineD3DDeviceImpl_SetRenderState,
6381 IWineD3DDeviceImpl_GetRenderState,
6382 IWineD3DDeviceImpl_SetRenderTarget,
6383 IWineD3DDeviceImpl_GetRenderTarget,
6384 IWineD3DDeviceImpl_SetFrontBackBuffers,
6385 IWineD3DDeviceImpl_SetSamplerState,
6386 IWineD3DDeviceImpl_GetSamplerState,
6387 IWineD3DDeviceImpl_SetScissorRect,
6388 IWineD3DDeviceImpl_GetScissorRect,
6389 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6390 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6391 IWineD3DDeviceImpl_SetStreamSource,
6392 IWineD3DDeviceImpl_GetStreamSource,
6393 IWineD3DDeviceImpl_SetStreamSourceFreq,
6394 IWineD3DDeviceImpl_GetStreamSourceFreq,
6395 IWineD3DDeviceImpl_SetTexture,
6396 IWineD3DDeviceImpl_GetTexture,
6397 IWineD3DDeviceImpl_SetTextureStageState,
6398 IWineD3DDeviceImpl_GetTextureStageState,
6399 IWineD3DDeviceImpl_SetTransform,
6400 IWineD3DDeviceImpl_GetTransform,
6401 IWineD3DDeviceImpl_SetVertexDeclaration,
6402 IWineD3DDeviceImpl_GetVertexDeclaration,
6403 IWineD3DDeviceImpl_SetVertexShader,
6404 IWineD3DDeviceImpl_GetVertexShader,
6405 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6406 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6407 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6408 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6409 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6410 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6411 IWineD3DDeviceImpl_SetViewport,
6412 IWineD3DDeviceImpl_GetViewport,
6413 IWineD3DDeviceImpl_MultiplyTransform,
6414 IWineD3DDeviceImpl_ValidateDevice,
6415 IWineD3DDeviceImpl_ProcessVertices,
6416 /*** State block ***/
6417 IWineD3DDeviceImpl_BeginStateBlock,
6418 IWineD3DDeviceImpl_EndStateBlock,
6419 /*** Scene management ***/
6420 IWineD3DDeviceImpl_BeginScene,
6421 IWineD3DDeviceImpl_EndScene,
6422 IWineD3DDeviceImpl_Present,
6423 IWineD3DDeviceImpl_Clear,
6424 /*** Drawing ***/
6425 IWineD3DDeviceImpl_DrawPrimitive,
6426 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6427 IWineD3DDeviceImpl_DrawPrimitiveUP,
6428 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6429 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6430 IWineD3DDeviceImpl_DrawRectPatch,
6431 IWineD3DDeviceImpl_DrawTriPatch,
6432 IWineD3DDeviceImpl_DeletePatch,
6433 IWineD3DDeviceImpl_ColorFill,
6434 IWineD3DDeviceImpl_UpdateTexture,
6435 IWineD3DDeviceImpl_UpdateSurface,
6436 IWineD3DDeviceImpl_GetFrontBufferData,
6437 /*** object tracking ***/
6438 IWineD3DDeviceImpl_ResourceReleased
6442 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6443 WINED3DRS_ALPHABLENDENABLE ,
6444 WINED3DRS_ALPHAFUNC ,
6445 WINED3DRS_ALPHAREF ,
6446 WINED3DRS_ALPHATESTENABLE ,
6447 WINED3DRS_BLENDOP ,
6448 WINED3DRS_COLORWRITEENABLE ,
6449 WINED3DRS_DESTBLEND ,
6450 WINED3DRS_DITHERENABLE ,
6451 WINED3DRS_FILLMODE ,
6452 WINED3DRS_FOGDENSITY ,
6453 WINED3DRS_FOGEND ,
6454 WINED3DRS_FOGSTART ,
6455 WINED3DRS_LASTPIXEL ,
6456 WINED3DRS_SHADEMODE ,
6457 WINED3DRS_SRCBLEND ,
6458 WINED3DRS_STENCILENABLE ,
6459 WINED3DRS_STENCILFAIL ,
6460 WINED3DRS_STENCILFUNC ,
6461 WINED3DRS_STENCILMASK ,
6462 WINED3DRS_STENCILPASS ,
6463 WINED3DRS_STENCILREF ,
6464 WINED3DRS_STENCILWRITEMASK ,
6465 WINED3DRS_STENCILZFAIL ,
6466 WINED3DRS_TEXTUREFACTOR ,
6467 WINED3DRS_WRAP0 ,
6468 WINED3DRS_WRAP1 ,
6469 WINED3DRS_WRAP2 ,
6470 WINED3DRS_WRAP3 ,
6471 WINED3DRS_WRAP4 ,
6472 WINED3DRS_WRAP5 ,
6473 WINED3DRS_WRAP6 ,
6474 WINED3DRS_WRAP7 ,
6475 WINED3DRS_ZENABLE ,
6476 WINED3DRS_ZFUNC ,
6477 WINED3DRS_ZWRITEENABLE
6480 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6481 WINED3DTSS_ADDRESSW ,
6482 WINED3DTSS_ALPHAARG0 ,
6483 WINED3DTSS_ALPHAARG1 ,
6484 WINED3DTSS_ALPHAARG2 ,
6485 WINED3DTSS_ALPHAOP ,
6486 WINED3DTSS_BUMPENVLOFFSET ,
6487 WINED3DTSS_BUMPENVLSCALE ,
6488 WINED3DTSS_BUMPENVMAT00 ,
6489 WINED3DTSS_BUMPENVMAT01 ,
6490 WINED3DTSS_BUMPENVMAT10 ,
6491 WINED3DTSS_BUMPENVMAT11 ,
6492 WINED3DTSS_COLORARG0 ,
6493 WINED3DTSS_COLORARG1 ,
6494 WINED3DTSS_COLORARG2 ,
6495 WINED3DTSS_COLOROP ,
6496 WINED3DTSS_RESULTARG ,
6497 WINED3DTSS_TEXCOORDINDEX ,
6498 WINED3DTSS_TEXTURETRANSFORMFLAGS
6501 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6502 WINED3DSAMP_ADDRESSU ,
6503 WINED3DSAMP_ADDRESSV ,
6504 WINED3DSAMP_ADDRESSW ,
6505 WINED3DSAMP_BORDERCOLOR ,
6506 WINED3DSAMP_MAGFILTER ,
6507 WINED3DSAMP_MINFILTER ,
6508 WINED3DSAMP_MIPFILTER ,
6509 WINED3DSAMP_MIPMAPLODBIAS ,
6510 WINED3DSAMP_MAXMIPLEVEL ,
6511 WINED3DSAMP_MAXANISOTROPY ,
6512 WINED3DSAMP_SRGBTEXTURE ,
6513 WINED3DSAMP_ELEMENTINDEX
6516 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6517 WINED3DRS_AMBIENT ,
6518 WINED3DRS_AMBIENTMATERIALSOURCE ,
6519 WINED3DRS_CLIPPING ,
6520 WINED3DRS_CLIPPLANEENABLE ,
6521 WINED3DRS_COLORVERTEX ,
6522 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6523 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6524 WINED3DRS_FOGDENSITY ,
6525 WINED3DRS_FOGEND ,
6526 WINED3DRS_FOGSTART ,
6527 WINED3DRS_FOGTABLEMODE ,
6528 WINED3DRS_FOGVERTEXMODE ,
6529 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6530 WINED3DRS_LIGHTING ,
6531 WINED3DRS_LOCALVIEWER ,
6532 WINED3DRS_MULTISAMPLEANTIALIAS ,
6533 WINED3DRS_MULTISAMPLEMASK ,
6534 WINED3DRS_NORMALIZENORMALS ,
6535 WINED3DRS_PATCHEDGESTYLE ,
6536 WINED3DRS_POINTSCALE_A ,
6537 WINED3DRS_POINTSCALE_B ,
6538 WINED3DRS_POINTSCALE_C ,
6539 WINED3DRS_POINTSCALEENABLE ,
6540 WINED3DRS_POINTSIZE ,
6541 WINED3DRS_POINTSIZE_MAX ,
6542 WINED3DRS_POINTSIZE_MIN ,
6543 WINED3DRS_POINTSPRITEENABLE ,
6544 WINED3DRS_RANGEFOGENABLE ,
6545 WINED3DRS_SPECULARMATERIALSOURCE ,
6546 WINED3DRS_TWEENFACTOR ,
6547 WINED3DRS_VERTEXBLEND
6550 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6551 WINED3DTSS_TEXCOORDINDEX ,
6552 WINED3DTSS_TEXTURETRANSFORMFLAGS
6555 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6556 WINED3DSAMP_DMAPOFFSET
6559 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6560 DWORD rep = StateTable[state].representative;
6561 DWORD idx;
6562 BYTE shift;
6563 UINT i;
6564 WineD3DContext *context;
6566 if(!rep) return;
6567 for(i = 0; i < This->numContexts; i++) {
6568 context = This->contexts[i];
6569 if(isStateDirty(context, rep)) continue;
6571 context->dirtyArray[context->numDirtyEntries++] = rep;
6572 idx = rep >> 5;
6573 shift = rep & 0x1f;
6574 context->isStateDirty[idx] |= (1 << shift);