push 0c258732cb75565633c2f709ca58b227c9f8ae60
[wine/hacks.git] / dlls / wined3d / device.c
blobccb8583479bd47f17715cbe1db42d19d4d504141
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-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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 This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
141 _basetexture.is_srgb = FALSE; \
142 _basetexture.srgb_mode_change_count = 0; \
145 /**********************************************************
146 * Global variable / Constants follow
147 **********************************************************/
148 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
150 /**********************************************************
151 * IUnknown parts follows
152 **********************************************************/
154 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
158 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
159 if (IsEqualGUID(riid, &IID_IUnknown)
160 || IsEqualGUID(riid, &IID_IWineD3DBase)
161 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
162 IUnknown_AddRef(iface);
163 *ppobj = This;
164 return S_OK;
166 *ppobj = NULL;
167 return E_NOINTERFACE;
170 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 ULONG refCount = InterlockedIncrement(&This->ref);
174 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
175 return refCount;
178 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
180 ULONG refCount = InterlockedDecrement(&This->ref);
182 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
184 if (!refCount) {
185 if (This->fbo) {
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
188 if (This->src_fbo) {
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
191 if (This->dst_fbo) {
192 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
195 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
197 /* TODO: Clean up all the surfaces and textures! */
198 /* NOTE: You must release the parent if the object was created via a callback
199 ** ***************************/
201 if (This->resources != NULL ) {
202 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
203 dumpResources(This->resources);
206 if(This->contexts) ERR("Context array not freed!\n");
207 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
208 This->haveHardwareCursor = FALSE;
210 IWineD3D_Release(This->wineD3D);
211 This->wineD3D = NULL;
212 HeapFree(GetProcessHeap(), 0, This);
213 TRACE("Freed device %p\n", This);
214 This = NULL;
216 return refCount;
219 /**********************************************************
220 * IWineD3DDevice implementation follows
221 **********************************************************/
222 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
224 *pParent = This->parent;
225 IUnknown_AddRef(This->parent);
226 return WINED3D_OK;
229 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
230 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
231 GLenum error, glUsage;
232 DWORD vboUsage = object->resource.usage;
233 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
234 WARN("Creating a vbo failed once, not trying again\n");
235 return;
238 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
240 ENTER_GL();
241 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
242 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
244 /* Make sure that the gl error is cleared. Do not use checkGLcall
245 * here because checkGLcall just prints a fixme and continues. However,
246 * if an error during VBO creation occurs we can fall back to non-vbo operation
247 * with full functionality(but performance loss)
249 while(glGetError() != GL_NO_ERROR);
251 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
252 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
253 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
254 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
255 * to check if the rhw and color values are in the correct format.
258 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
259 error = glGetError();
260 if(object->vbo == 0 || error != GL_NO_ERROR) {
261 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
262 goto error;
265 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
266 error = glGetError();
267 if(error != GL_NO_ERROR) {
268 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
269 goto error;
272 /* Don't use static, because dx apps tend to update the buffer
273 * quite often even if they specify 0 usage. Because we always keep the local copy
274 * we never read from the vbo and can create a write only opengl buffer.
276 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
277 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
278 case WINED3DUSAGE_DYNAMIC:
279 TRACE("Gl usage = GL_STREAM_DRAW\n");
280 glUsage = GL_STREAM_DRAW_ARB;
281 break;
282 case WINED3DUSAGE_WRITEONLY:
283 default:
284 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
285 glUsage = GL_DYNAMIC_DRAW_ARB;
286 break;
289 /* Reserve memory for the buffer. The amount of data won't change
290 * so we are safe with calling glBufferData once with a NULL ptr and
291 * calling glBufferSubData on updates
293 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
294 error = glGetError();
295 if(error != GL_NO_ERROR) {
296 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
297 goto error;
300 LEAVE_GL();
302 return;
303 error:
304 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
305 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
306 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
307 object->vbo = 0;
308 object->Flags |= VBFLAG_VBOCREATEFAIL;
309 LEAVE_GL();
310 return;
313 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
314 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
315 IUnknown *parent) {
316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
317 IWineD3DVertexBufferImpl *object;
318 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
319 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
320 BOOL conv;
322 if(Size == 0) {
323 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
324 *ppVertexBuffer = NULL;
325 return WINED3DERR_INVALIDCALL;
328 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
330 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
331 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
333 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
334 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
336 object->fvf = FVF;
338 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
339 * drawStridedFast (half-life 2).
341 * Basically converting the vertices in the buffer is quite expensive, and observations
342 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
343 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
345 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
346 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
347 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
348 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
349 * dx7 apps.
350 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
351 * more. In this call we can convert dx7 buffers too.
353 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
354 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
355 (dxVersion > 7 || !conv) ) {
356 CreateVBO(object);
358 return WINED3D_OK;
361 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
362 GLenum error, glUsage;
363 TRACE("Creating VBO for Index Buffer %p\n", object);
365 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
366 * restored on the next draw
368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
370 ENTER_GL();
371 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
372 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
374 while(glGetError());
376 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
377 error = glGetError();
378 if(error != GL_NO_ERROR || object->vbo == 0) {
379 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
380 goto out;
383 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
384 error = glGetError();
385 if(error != GL_NO_ERROR) {
386 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
387 goto out;
390 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
391 * copy no readback will be needed
393 glUsage = GL_STATIC_DRAW_ARB;
394 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
395 error = glGetError();
396 if(error != GL_NO_ERROR) {
397 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
398 goto out;
400 LEAVE_GL();
401 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
402 return;
404 out:
405 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
406 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
407 LEAVE_GL();
408 object->vbo = 0;
411 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
412 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
413 HANDLE *sharedHandle, IUnknown *parent) {
414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
415 IWineD3DIndexBufferImpl *object;
416 TRACE("(%p) Creating index buffer\n", This);
418 /* Allocate the storage for the device */
419 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
421 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
422 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
425 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
426 CreateIndexBufferVBO(This, object);
429 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
430 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
431 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
433 return WINED3D_OK;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DStateBlockImpl *object;
440 int i, j;
441 HRESULT temp_result;
443 D3DCREATEOBJECTINSTANCE(object, StateBlock)
444 object->blockType = Type;
446 for(i = 0; i < LIGHTMAP_SIZE; i++) {
447 list_init(&object->lightMap[i]);
450 /* Special case - Used during initialization to produce a placeholder stateblock
451 so other functions called can update a state block */
452 if (Type == WINED3DSBT_INIT) {
453 /* Don't bother increasing the reference count otherwise a device will never
454 be freed due to circular dependencies */
455 return WINED3D_OK;
458 temp_result = allocate_shader_constants(object);
459 if (WINED3D_OK != temp_result)
460 return temp_result;
462 /* Otherwise, might as well set the whole state block to the appropriate values */
463 if (This->stateBlock != NULL)
464 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
465 else
466 memset(object->streamFreq, 1, sizeof(object->streamFreq));
468 /* Reset the ref and type after kludging it */
469 object->wineD3DDevice = This;
470 object->ref = 1;
471 object->blockType = Type;
473 TRACE("Updating changed flags appropriate for type %d\n", Type);
475 if (Type == WINED3DSBT_ALL) {
477 TRACE("ALL => Pretend everything has changed\n");
478 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
480 /* Lights are not part of the changed / set structure */
481 for(j = 0; j < LIGHTMAP_SIZE; j++) {
482 struct list *e;
483 LIST_FOR_EACH(e, &object->lightMap[j]) {
484 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
485 light->changed = TRUE;
486 light->enabledChanged = TRUE;
489 } else if (Type == WINED3DSBT_PIXELSTATE) {
491 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
492 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
494 object->changed.pixelShader = TRUE;
496 /* Pixel Shader Constants */
497 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
498 object->changed.pixelShaderConstantsF[i] = TRUE;
499 for (i = 0; i < MAX_CONST_B; ++i)
500 object->changed.pixelShaderConstantsB[i] = TRUE;
501 for (i = 0; i < MAX_CONST_I; ++i)
502 object->changed.pixelShaderConstantsI[i] = TRUE;
504 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
505 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
507 for (j = 0; j < MAX_TEXTURES; j++) {
508 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
509 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
512 for (j = 0 ; j < 16; j++) {
513 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
515 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
519 } else if (Type == WINED3DSBT_VERTEXSTATE) {
521 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
522 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
524 object->changed.vertexShader = TRUE;
526 /* Vertex Shader Constants */
527 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
528 object->changed.vertexShaderConstantsF[i] = TRUE;
529 for (i = 0; i < MAX_CONST_B; ++i)
530 object->changed.vertexShaderConstantsB[i] = TRUE;
531 for (i = 0; i < MAX_CONST_I; ++i)
532 object->changed.vertexShaderConstantsI[i] = TRUE;
534 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
535 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 for (j = 0; j < MAX_TEXTURES; j++) {
538 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
539 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
542 for (j = 0 ; j < 16; j++){
543 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
544 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
548 for(j = 0; j < LIGHTMAP_SIZE; j++) {
549 struct list *e;
550 LIST_FOR_EACH(e, &object->lightMap[j]) {
551 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
552 light->changed = TRUE;
553 light->enabledChanged = TRUE;
556 } else {
557 FIXME("Unrecognized state block type %d\n", Type);
560 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
561 return WINED3D_OK;
564 /* ************************************
565 MSDN:
566 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
568 Discard
569 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
571 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.
573 ******************************** */
575 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) {
576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
577 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
578 unsigned int Size = 1;
579 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
580 TRACE("(%p) Create surface\n",This);
582 /** FIXME: Check ranges on the inputs are valid
583 * MSDN
584 * MultisampleQuality
585 * [in] Quality level. The valid range is between zero and one less than the level
586 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
587 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
588 * values of paired render targets, depth stencil surfaces, and the MultiSample type
589 * must all match.
590 *******************************/
594 * TODO: Discard MSDN
595 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
597 * If this flag is set, the contents of the depth stencil buffer will be
598 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
599 * with a different depth surface.
601 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
602 ***************************/
604 if(MultisampleQuality < 0) {
605 FIXME("Invalid multisample level %d\n", MultisampleQuality);
606 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
609 if(MultisampleQuality > 0) {
610 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
611 MultisampleQuality=0;
614 /** FIXME: Check that the format is supported
615 * by the device.
616 *******************************/
618 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
619 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
620 * space!
621 *********************************/
622 if (WINED3DFMT_UNKNOWN == Format) {
623 Size = 0;
624 } else if (Format == WINED3DFMT_DXT1) {
625 /* DXT1 is half byte per pixel */
626 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
628 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
629 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
630 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
631 } else {
632 /* The pitch is a multiple of 4 bytes */
633 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
634 Size *= Height;
637 /** Create and initialise the surface resource **/
638 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
639 /* "Standalone" surface */
640 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
642 object->currentDesc.Width = Width;
643 object->currentDesc.Height = Height;
644 object->currentDesc.MultiSampleType = MultiSample;
645 object->currentDesc.MultiSampleQuality = MultisampleQuality;
646 object->glDescription.level = Level;
648 /* Flags */
649 object->Flags = 0;
650 object->Flags |= Discard ? SFLAG_DISCARD : 0;
651 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
652 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
655 if (WINED3DFMT_UNKNOWN != Format) {
656 object->bytesPerPixel = tableEntry->bpp;
657 } else {
658 object->bytesPerPixel = 0;
661 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
663 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
665 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
666 * this function is too deep to need to care about things like this.
667 * Levels need to be checked too, and possibly Type since they all affect what can be done.
668 * ****************************************/
669 switch(Pool) {
670 case WINED3DPOOL_SCRATCH:
671 if(!Lockable)
672 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
673 "which are mutually exclusive, setting lockable to TRUE\n");
674 Lockable = TRUE;
675 break;
676 case WINED3DPOOL_SYSTEMMEM:
677 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
678 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
679 case WINED3DPOOL_MANAGED:
680 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
681 "Usage of DYNAMIC which are mutually exclusive, not doing "
682 "anything just telling you.\n");
683 break;
684 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
685 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
686 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
687 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
688 break;
689 default:
690 FIXME("(%p) Unknown pool %d\n", This, Pool);
691 break;
694 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
695 FIXME("Trying to create a render target that isn't in the default pool\n");
698 /* mark the texture as dirty so that it gets loaded first time around*/
699 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
700 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
701 This, Width, Height, Format, debug_d3dformat(Format),
702 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
704 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
705 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
706 This->ddraw_primary = (IWineD3DSurface *) object;
708 /* Look at the implementation and set the correct Vtable */
709 switch(Impl) {
710 case SURFACE_OPENGL:
711 /* Check if a 3D adapter is available when creating gl surfaces */
712 if(!This->adapter) {
713 ERR("OpenGL surfaces are not available without opengl\n");
714 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
715 HeapFree(GetProcessHeap(), 0, object);
716 return WINED3DERR_NOTAVAILABLE;
718 break;
720 case SURFACE_GDI:
721 object->lpVtbl = &IWineGDISurface_Vtbl;
722 break;
724 default:
725 /* To be sure to catch this */
726 ERR("Unknown requested surface implementation %d!\n", Impl);
727 IWineD3DSurface_Release((IWineD3DSurface *) object);
728 return WINED3DERR_INVALIDCALL;
731 list_init(&object->renderbuffers);
733 /* Call the private setup routine */
734 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
738 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
739 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
740 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
741 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
744 IWineD3DTextureImpl *object;
745 unsigned int i;
746 UINT tmpW;
747 UINT tmpH;
748 HRESULT hr;
749 unsigned int pow2Width;
750 unsigned int pow2Height;
753 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
754 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
755 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
757 /* TODO: It should only be possible to create textures for formats
758 that are reported as supported */
759 if (WINED3DFMT_UNKNOWN >= Format) {
760 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
761 return WINED3DERR_INVALIDCALL;
764 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
765 D3DINITIALIZEBASETEXTURE(object->baseTexture);
766 object->width = Width;
767 object->height = Height;
769 /** Non-power2 support **/
770 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
771 pow2Width = Width;
772 pow2Height = Height;
773 } else {
774 /* Find the nearest pow2 match */
775 pow2Width = pow2Height = 1;
776 while (pow2Width < Width) pow2Width <<= 1;
777 while (pow2Height < Height) pow2Height <<= 1;
780 /** FIXME: add support for real non-power-two if it's provided by the video card **/
781 /* Precalculated scaling for 'faked' non power of two texture coords */
782 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
783 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
784 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
786 /* Calculate levels for mip mapping */
787 if (Levels == 0) {
788 TRACE("calculating levels %d\n", object->baseTexture.levels);
789 object->baseTexture.levels++;
790 tmpW = Width;
791 tmpH = Height;
792 while (tmpW > 1 || tmpH > 1) {
793 tmpW = max(1, tmpW >> 1);
794 tmpH = max(1, tmpH >> 1);
795 object->baseTexture.levels++;
797 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
800 /* Generate all the surfaces */
801 tmpW = Width;
802 tmpH = Height;
803 for (i = 0; i < object->baseTexture.levels; i++)
805 /* use the callback to create the texture surface */
806 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
807 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
808 FIXME("Failed to create surface %p\n", object);
809 /* clean up */
810 object->surfaces[i] = NULL;
811 IWineD3DTexture_Release((IWineD3DTexture *)object);
813 *ppTexture = NULL;
814 return hr;
817 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
818 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
819 /* calculate the next mipmap level */
820 tmpW = max(1, tmpW >> 1);
821 tmpH = max(1, tmpH >> 1);
824 TRACE("(%p) : Created texture %p\n", This, object);
825 return WINED3D_OK;
828 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
829 UINT Width, UINT Height, UINT Depth,
830 UINT Levels, DWORD Usage,
831 WINED3DFORMAT Format, WINED3DPOOL Pool,
832 IWineD3DVolumeTexture **ppVolumeTexture,
833 HANDLE *pSharedHandle, IUnknown *parent,
834 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
837 IWineD3DVolumeTextureImpl *object;
838 unsigned int i;
839 UINT tmpW;
840 UINT tmpH;
841 UINT tmpD;
843 /* TODO: It should only be possible to create textures for formats
844 that are reported as supported */
845 if (WINED3DFMT_UNKNOWN >= Format) {
846 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
847 return WINED3DERR_INVALIDCALL;
850 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
851 D3DINITIALIZEBASETEXTURE(object->baseTexture);
853 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
854 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
856 object->width = Width;
857 object->height = Height;
858 object->depth = Depth;
860 /* Calculate levels for mip mapping */
861 if (Levels == 0) {
862 object->baseTexture.levels++;
863 tmpW = Width;
864 tmpH = Height;
865 tmpD = Depth;
866 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
867 tmpW = max(1, tmpW >> 1);
868 tmpH = max(1, tmpH >> 1);
869 tmpD = max(1, tmpD >> 1);
870 object->baseTexture.levels++;
872 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
875 /* Generate all the surfaces */
876 tmpW = Width;
877 tmpH = Height;
878 tmpD = Depth;
880 for (i = 0; i < object->baseTexture.levels; i++)
882 HRESULT hr;
883 /* Create the volume */
884 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
885 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
887 if(FAILED(hr)) {
888 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
889 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
890 *ppVolumeTexture = NULL;
891 return hr;
894 /* Set its container to this object */
895 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
897 /* calcualte the next mipmap level */
898 tmpW = max(1, tmpW >> 1);
899 tmpH = max(1, tmpH >> 1);
900 tmpD = max(1, tmpD >> 1);
903 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
904 TRACE("(%p) : Created volume texture %p\n", This, object);
905 return WINED3D_OK;
908 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
909 UINT Width, UINT Height, UINT Depth,
910 DWORD Usage,
911 WINED3DFORMAT Format, WINED3DPOOL Pool,
912 IWineD3DVolume** ppVolume,
913 HANDLE* pSharedHandle, IUnknown *parent) {
915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
916 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
917 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
919 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
921 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object->currentDesc.Width = Width;
925 object->currentDesc.Height = Height;
926 object->currentDesc.Depth = Depth;
927 object->bytesPerPixel = formatDesc->bpp;
929 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
930 object->lockable = TRUE;
931 object->locked = FALSE;
932 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
933 object->dirty = TRUE;
935 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
938 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
939 UINT Levels, DWORD Usage,
940 WINED3DFORMAT Format, WINED3DPOOL Pool,
941 IWineD3DCubeTexture **ppCubeTexture,
942 HANDLE *pSharedHandle, IUnknown *parent,
943 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
946 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
947 unsigned int i, j;
948 UINT tmpW;
949 HRESULT hr;
950 unsigned int pow2EdgeLength = EdgeLength;
952 /* TODO: It should only be possible to create textures for formats
953 that are reported as supported */
954 if (WINED3DFMT_UNKNOWN >= Format) {
955 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
956 return WINED3DERR_INVALIDCALL;
959 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
960 WARN("(%p) : Tried to create not supported cube texture\n", This);
961 return WINED3DERR_INVALIDCALL;
964 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
965 D3DINITIALIZEBASETEXTURE(object->baseTexture);
967 TRACE("(%p) Create Cube Texture\n", This);
969 /** Non-power2 support **/
971 /* Find the nearest pow2 match */
972 pow2EdgeLength = 1;
973 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
975 object->edgeLength = EdgeLength;
976 /* TODO: support for native non-power 2 */
977 /* Precalculated scaling for 'faked' non power of two texture coords */
978 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
980 /* Calculate levels for mip mapping */
981 if (Levels == 0) {
982 object->baseTexture.levels++;
983 tmpW = EdgeLength;
984 while (tmpW > 1) {
985 tmpW = max(1, tmpW >> 1);
986 object->baseTexture.levels++;
988 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
991 /* Generate all the surfaces */
992 tmpW = EdgeLength;
993 for (i = 0; i < object->baseTexture.levels; i++) {
995 /* Create the 6 faces */
996 for (j = 0; j < 6; j++) {
998 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
999 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1001 if(hr!= WINED3D_OK) {
1002 /* clean up */
1003 int k;
1004 int l;
1005 for (l = 0; l < j; l++) {
1006 IWineD3DSurface_Release(object->surfaces[j][i]);
1008 for (k = 0; k < i; k++) {
1009 for (l = 0; l < 6; l++) {
1010 IWineD3DSurface_Release(object->surfaces[l][j]);
1014 FIXME("(%p) Failed to create surface\n",object);
1015 HeapFree(GetProcessHeap(),0,object);
1016 *ppCubeTexture = NULL;
1017 return hr;
1019 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1020 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1022 tmpW = max(1, tmpW >> 1);
1025 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1026 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1027 return WINED3D_OK;
1030 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1032 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1033 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1035 /* Just a check to see if we support this type of query */
1036 switch(Type) {
1037 case WINED3DQUERYTYPE_OCCLUSION:
1038 TRACE("(%p) occlusion query\n", This);
1039 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1040 hr = WINED3D_OK;
1041 else
1042 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1043 break;
1045 case WINED3DQUERYTYPE_EVENT:
1046 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1047 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1048 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1050 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1052 hr = WINED3D_OK;
1053 break;
1055 case WINED3DQUERYTYPE_VCACHE:
1056 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1057 case WINED3DQUERYTYPE_VERTEXSTATS:
1058 case WINED3DQUERYTYPE_TIMESTAMP:
1059 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1060 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1061 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1062 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1063 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1064 case WINED3DQUERYTYPE_PIXELTIMINGS:
1065 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1066 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1067 default:
1068 FIXME("(%p) Unhandled query type %d\n", This, Type);
1070 if(NULL == ppQuery || hr != WINED3D_OK) {
1071 return hr;
1074 D3DCREATEOBJECTINSTANCE(object, Query)
1075 object->type = Type;
1076 /* allocated the 'extended' data based on the type of query requested */
1077 switch(Type){
1078 case WINED3DQUERYTYPE_OCCLUSION:
1079 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1080 TRACE("(%p) Allocating data for an occlusion query\n", This);
1081 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1082 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1083 break;
1085 case WINED3DQUERYTYPE_EVENT:
1086 /* TODO: GL_APPLE_fence */
1087 if(GL_SUPPORT(APPLE_FENCE)) {
1088 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1089 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1090 checkGLcall("glGenFencesAPPLE");
1091 } else if(GL_SUPPORT(NV_FENCE)) {
1092 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1093 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1094 checkGLcall("glGenFencesNV");
1096 break;
1098 case WINED3DQUERYTYPE_VCACHE:
1099 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1100 case WINED3DQUERYTYPE_VERTEXSTATS:
1101 case WINED3DQUERYTYPE_TIMESTAMP:
1102 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1103 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1104 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1105 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1106 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1107 case WINED3DQUERYTYPE_PIXELTIMINGS:
1108 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1109 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1110 default:
1111 object->extendedData = 0;
1112 FIXME("(%p) Unhandled query type %d\n",This , Type);
1114 TRACE("(%p) : Created Query %p\n", This, object);
1115 return WINED3D_OK;
1118 /*****************************************************************************
1119 * IWineD3DDeviceImpl_SetupFullscreenWindow
1121 * Helper function that modifies a HWND's Style and ExStyle for proper
1122 * fullscreen use.
1124 * Params:
1125 * iface: Pointer to the IWineD3DDevice interface
1126 * window: Window to setup
1128 *****************************************************************************/
1129 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1132 LONG style, exStyle;
1133 /* Don't do anything if an original style is stored.
1134 * That shouldn't happen
1136 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1137 if (This->style || This->exStyle) {
1138 ERR("(%p): Want to change the window parameters of HWND %p, but "
1139 "another style is stored for restoration afterwards\n", This, window);
1142 /* Get the parameters and save them */
1143 style = GetWindowLongW(window, GWL_STYLE);
1144 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1145 This->style = style;
1146 This->exStyle = exStyle;
1148 /* Filter out window decorations */
1149 style &= ~WS_CAPTION;
1150 style &= ~WS_THICKFRAME;
1151 exStyle &= ~WS_EX_WINDOWEDGE;
1152 exStyle &= ~WS_EX_CLIENTEDGE;
1154 /* Make sure the window is managed, otherwise we won't get keyboard input */
1155 style |= WS_POPUP | WS_SYSMENU;
1157 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1158 This->style, This->exStyle, style, exStyle);
1160 SetWindowLongW(window, GWL_STYLE, style);
1161 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1163 /* Inform the window about the update. */
1164 SetWindowPos(window, HWND_TOP, 0, 0,
1165 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1166 ShowWindow(window, SW_NORMAL);
1169 /*****************************************************************************
1170 * IWineD3DDeviceImpl_RestoreWindow
1172 * Helper function that restores a windows' properties when taking it out
1173 * of fullscreen mode
1175 * Params:
1176 * iface: Pointer to the IWineD3DDevice interface
1177 * window: Window to setup
1179 *****************************************************************************/
1180 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1183 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1184 * switch, do nothing
1186 if (!This->style && !This->exStyle) return;
1188 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1189 This, window, This->style, This->exStyle);
1191 SetWindowLongW(window, GWL_STYLE, This->style);
1192 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1194 /* Delete the old values */
1195 This->style = 0;
1196 This->exStyle = 0;
1198 /* Inform the window about the update */
1199 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1200 0, 0, 0, 0, /* Pos, Size, ignored */
1201 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1204 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1205 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1206 IUnknown* parent,
1207 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1208 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1211 HDC hDc;
1212 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1213 HRESULT hr = WINED3D_OK;
1214 IUnknown *bufferParent;
1215 Display *display;
1217 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1219 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1220 * does a device hold a reference to a swap chain giving them a lifetime of the device
1221 * or does the swap chain notify the device of its destruction.
1222 *******************************/
1224 /* Check the params */
1225 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1226 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1227 return WINED3DERR_INVALIDCALL;
1228 } else if (pPresentationParameters->BackBufferCount > 1) {
1229 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");
1232 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1234 /*********************
1235 * Lookup the window Handle and the relating X window handle
1236 ********************/
1238 /* Setup hwnd we are using, plus which display this equates to */
1239 object->win_handle = pPresentationParameters->hDeviceWindow;
1240 if (!object->win_handle) {
1241 object->win_handle = This->createParms.hFocusWindow;
1244 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1245 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1246 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1247 return WINED3DERR_NOTAVAILABLE;
1249 hDc = GetDC(object->win_handle);
1250 display = get_display(hDc);
1251 ReleaseDC(object->win_handle, hDc);
1252 TRACE("Using a display of %p %p\n", display, hDc);
1254 if (NULL == display || NULL == hDc) {
1255 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1256 return WINED3DERR_NOTAVAILABLE;
1259 if (object->win == 0) {
1260 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1261 return WINED3DERR_NOTAVAILABLE;
1264 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1265 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1266 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1268 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1269 * then the corresponding dimension of the client area of the hDeviceWindow
1270 * (or the focus window, if hDeviceWindow is NULL) is taken.
1271 **********************/
1273 if (pPresentationParameters->Windowed &&
1274 ((pPresentationParameters->BackBufferWidth == 0) ||
1275 (pPresentationParameters->BackBufferHeight == 0))) {
1277 RECT Rect;
1278 GetClientRect(object->win_handle, &Rect);
1280 if (pPresentationParameters->BackBufferWidth == 0) {
1281 pPresentationParameters->BackBufferWidth = Rect.right;
1282 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1284 if (pPresentationParameters->BackBufferHeight == 0) {
1285 pPresentationParameters->BackBufferHeight = Rect.bottom;
1286 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1290 /* Put the correct figures in the presentation parameters */
1291 TRACE("Copying across presentation parameters\n");
1292 object->presentParms = *pPresentationParameters;
1294 TRACE("calling rendertarget CB\n");
1295 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1296 parent,
1297 object->presentParms.BackBufferWidth,
1298 object->presentParms.BackBufferHeight,
1299 object->presentParms.BackBufferFormat,
1300 object->presentParms.MultiSampleType,
1301 object->presentParms.MultiSampleQuality,
1302 TRUE /* Lockable */,
1303 &object->frontBuffer,
1304 NULL /* pShared (always null)*/);
1305 if (object->frontBuffer != NULL) {
1306 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1307 } else {
1308 ERR("Failed to create the front buffer\n");
1309 goto error;
1313 * Create an opengl context for the display visual
1314 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1315 * use different properties after that point in time. FIXME: How to handle when requested format
1316 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1317 * it chooses is identical to the one already being used!
1318 **********************************/
1319 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1321 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1322 if(!object->context)
1323 return E_OUTOFMEMORY;
1324 object->num_contexts = 1;
1326 ENTER_GL();
1327 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1328 LEAVE_GL();
1330 if (!object->context[0]) {
1331 ERR("Failed to create a new context\n");
1332 hr = WINED3DERR_NOTAVAILABLE;
1333 goto error;
1334 } else {
1335 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1336 object->win_handle, object->context[0]->glCtx, object->win);
1339 /*********************
1340 * Windowed / Fullscreen
1341 *******************/
1344 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1345 * so we should really check to see if there is a fullscreen swapchain already
1346 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1347 **************************************/
1349 if (!pPresentationParameters->Windowed) {
1351 DEVMODEW devmode;
1352 HDC hdc;
1353 int bpp = 0;
1354 RECT clip_rc;
1356 /* Get info on the current display setup */
1357 hdc = GetDC(0);
1358 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1359 ReleaseDC(0, hdc);
1361 /* Change the display settings */
1362 memset(&devmode, 0, sizeof(DEVMODEW));
1363 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1364 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1365 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1366 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1367 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1368 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1370 /* For GetDisplayMode */
1371 This->ddraw_width = devmode.dmPelsWidth;
1372 This->ddraw_height = devmode.dmPelsHeight;
1373 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1375 IWineD3DDevice_SetFullscreen(iface, TRUE);
1377 /* And finally clip mouse to our screen */
1378 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1379 ClipCursor(&clip_rc);
1382 /*********************
1383 * Create the back, front and stencil buffers
1384 *******************/
1385 if(object->presentParms.BackBufferCount > 0) {
1386 int i;
1388 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1389 if(!object->backBuffer) {
1390 ERR("Out of memory\n");
1391 hr = E_OUTOFMEMORY;
1392 goto error;
1395 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1396 TRACE("calling rendertarget CB\n");
1397 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1398 parent,
1399 object->presentParms.BackBufferWidth,
1400 object->presentParms.BackBufferHeight,
1401 object->presentParms.BackBufferFormat,
1402 object->presentParms.MultiSampleType,
1403 object->presentParms.MultiSampleQuality,
1404 TRUE /* Lockable */,
1405 &object->backBuffer[i],
1406 NULL /* pShared (always null)*/);
1407 if(hr == WINED3D_OK && object->backBuffer[i]) {
1408 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1409 } else {
1410 ERR("Cannot create new back buffer\n");
1411 goto error;
1413 ENTER_GL();
1414 glDrawBuffer(GL_BACK);
1415 checkGLcall("glDrawBuffer(GL_BACK)");
1416 LEAVE_GL();
1418 } else {
1419 object->backBuffer = NULL;
1421 /* Single buffering - draw to front buffer */
1422 ENTER_GL();
1423 glDrawBuffer(GL_FRONT);
1424 checkGLcall("glDrawBuffer(GL_FRONT)");
1425 LEAVE_GL();
1428 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1429 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1430 TRACE("Creating depth stencil buffer\n");
1431 if (This->depthStencilBuffer == NULL ) {
1432 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1433 parent,
1434 object->presentParms.BackBufferWidth,
1435 object->presentParms.BackBufferHeight,
1436 object->presentParms.AutoDepthStencilFormat,
1437 object->presentParms.MultiSampleType,
1438 object->presentParms.MultiSampleQuality,
1439 FALSE /* FIXME: Discard */,
1440 &This->depthStencilBuffer,
1441 NULL /* pShared (always null)*/ );
1442 if (This->depthStencilBuffer != NULL)
1443 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1446 /** TODO: A check on width, height and multisample types
1447 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1448 ****************************/
1449 object->wantsDepthStencilBuffer = TRUE;
1450 } else {
1451 object->wantsDepthStencilBuffer = FALSE;
1454 TRACE("Created swapchain %p\n", object);
1455 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1456 return WINED3D_OK;
1458 error:
1459 if (object->backBuffer) {
1460 int i;
1461 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1462 if(object->backBuffer[i]) {
1463 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1464 IUnknown_Release(bufferParent); /* once for the get parent */
1465 if (IUnknown_Release(bufferParent) > 0) {
1466 FIXME("(%p) Something's still holding the back buffer\n",This);
1470 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1471 object->backBuffer = NULL;
1473 if(object->context[0])
1474 DestroyContext(This, object->context[0]);
1475 if(object->frontBuffer) {
1476 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1477 IUnknown_Release(bufferParent); /* once for the get parent */
1478 if (IUnknown_Release(bufferParent) > 0) {
1479 FIXME("(%p) Something's still holding the front buffer\n",This);
1482 HeapFree(GetProcessHeap(), 0, object);
1483 return hr;
1486 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1487 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1489 TRACE("(%p)\n", This);
1491 return This->NumberOfSwapChains;
1494 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1496 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1498 if(iSwapChain < This->NumberOfSwapChains) {
1499 *pSwapChain = This->swapchains[iSwapChain];
1500 IWineD3DSwapChain_AddRef(*pSwapChain);
1501 TRACE("(%p) returning %p\n", This, *pSwapChain);
1502 return WINED3D_OK;
1503 } else {
1504 TRACE("Swapchain out of range\n");
1505 *pSwapChain = NULL;
1506 return WINED3DERR_INVALIDCALL;
1510 /*****
1511 * Vertex Declaration
1512 *****/
1513 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1514 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1516 IWineD3DVertexDeclarationImpl *object = NULL;
1517 HRESULT hr = WINED3D_OK;
1519 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1520 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1522 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1524 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1526 return hr;
1529 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1531 unsigned int idx, idx2;
1532 unsigned int offset;
1533 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1534 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1535 BOOL has_blend_idx = has_blend &&
1536 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1537 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1538 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1539 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1540 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1541 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1542 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1544 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1545 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1547 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1548 WINED3DVERTEXELEMENT *elements = NULL;
1550 unsigned int size;
1551 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1552 if (has_blend_idx) num_blends--;
1554 /* Compute declaration size */
1555 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1556 has_psize + has_diffuse + has_specular + num_textures + 1;
1558 /* convert the declaration */
1559 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1560 if (!elements)
1561 return 0;
1563 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1564 idx = 0;
1565 if (has_pos) {
1566 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1567 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1568 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1570 else {
1571 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1572 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1574 elements[idx].UsageIndex = 0;
1575 idx++;
1577 if (has_blend && (num_blends > 0)) {
1578 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1579 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1580 else
1581 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1582 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1583 elements[idx].UsageIndex = 0;
1584 idx++;
1586 if (has_blend_idx) {
1587 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1588 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1589 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1590 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1591 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1592 else
1593 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1594 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1595 elements[idx].UsageIndex = 0;
1596 idx++;
1598 if (has_normal) {
1599 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1600 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1601 elements[idx].UsageIndex = 0;
1602 idx++;
1604 if (has_psize) {
1605 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1606 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1607 elements[idx].UsageIndex = 0;
1608 idx++;
1610 if (has_diffuse) {
1611 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1612 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1613 elements[idx].UsageIndex = 0;
1614 idx++;
1616 if (has_specular) {
1617 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1618 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1619 elements[idx].UsageIndex = 1;
1620 idx++;
1622 for (idx2 = 0; idx2 < num_textures; idx2++) {
1623 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1624 switch (numcoords) {
1625 case WINED3DFVF_TEXTUREFORMAT1:
1626 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1627 break;
1628 case WINED3DFVF_TEXTUREFORMAT2:
1629 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1630 break;
1631 case WINED3DFVF_TEXTUREFORMAT3:
1632 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1633 break;
1634 case WINED3DFVF_TEXTUREFORMAT4:
1635 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1636 break;
1638 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1639 elements[idx].UsageIndex = idx2;
1640 idx++;
1643 /* Now compute offsets, and initialize the rest of the fields */
1644 for (idx = 0, offset = 0; idx < size-1; idx++) {
1645 elements[idx].Stream = 0;
1646 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1647 elements[idx].Offset = offset;
1648 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1651 *ppVertexElements = elements;
1652 return size;
1655 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1656 WINED3DVERTEXELEMENT* elements = NULL;
1657 size_t size;
1658 DWORD hr;
1660 size = ConvertFvfToDeclaration(Fvf, &elements);
1661 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1663 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1664 HeapFree(GetProcessHeap(), 0, elements);
1665 if (hr != S_OK) return hr;
1667 return WINED3D_OK;
1670 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1671 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1673 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1674 HRESULT hr = WINED3D_OK;
1675 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1676 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1678 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1680 if (vertex_declaration) {
1681 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1684 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1686 if (WINED3D_OK != hr) {
1687 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1688 IWineD3DVertexShader_Release(*ppVertexShader);
1689 return WINED3DERR_INVALIDCALL;
1692 return WINED3D_OK;
1695 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1697 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1698 HRESULT hr = WINED3D_OK;
1700 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1701 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1702 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1703 if (WINED3D_OK == hr) {
1704 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1705 } else {
1706 WARN("(%p) : Failed to create pixel shader\n", This);
1709 return hr;
1712 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1714 IWineD3DPaletteImpl *object;
1715 HRESULT hr;
1716 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1718 /* Create the new object */
1719 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1720 if(!object) {
1721 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1722 return E_OUTOFMEMORY;
1725 object->lpVtbl = &IWineD3DPalette_Vtbl;
1726 object->ref = 1;
1727 object->Flags = Flags;
1728 object->parent = Parent;
1729 object->wineD3DDevice = This;
1730 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1732 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1734 if(!object->hpal) {
1735 HeapFree( GetProcessHeap(), 0, object);
1736 return E_OUTOFMEMORY;
1739 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1740 if(FAILED(hr)) {
1741 IWineD3DPalette_Release((IWineD3DPalette *) object);
1742 return hr;
1745 *Palette = (IWineD3DPalette *) object;
1747 return WINED3D_OK;
1750 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1752 IWineD3DSwapChainImpl *swapchain;
1753 HRESULT hr;
1754 DWORD state;
1756 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1757 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1759 /* TODO: Test if OpenGL is compiled in and loaded */
1761 TRACE("(%p) : Creating stateblock\n", This);
1762 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1763 hr = IWineD3DDevice_CreateStateBlock(iface,
1764 WINED3DSBT_INIT,
1765 (IWineD3DStateBlock **)&This->stateBlock,
1766 NULL);
1767 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1768 WARN("Failed to create stateblock\n");
1769 return hr;
1771 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1772 This->updateStateBlock = This->stateBlock;
1773 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1775 hr = allocate_shader_constants(This->updateStateBlock);
1776 if (WINED3D_OK != hr)
1777 return hr;
1779 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1780 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1781 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1783 /* Initialize the texture unit mapping to a 1:1 mapping */
1784 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1785 if (state < GL_LIMITS(fragment_samplers)) {
1786 This->texUnitMap[state] = state;
1787 This->rev_tex_unit_map[state] = state;
1788 } else {
1789 This->texUnitMap[state] = -1;
1790 This->rev_tex_unit_map[state] = -1;
1794 /* Setup the implicit swapchain */
1795 TRACE("Creating implicit swapchain\n");
1796 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1797 if (FAILED(hr) || !swapchain) {
1798 WARN("Failed to create implicit swapchain\n");
1799 return hr;
1802 This->NumberOfSwapChains = 1;
1803 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1804 if(!This->swapchains) {
1805 ERR("Out of memory!\n");
1806 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1807 return E_OUTOFMEMORY;
1809 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1811 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1813 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1814 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1815 This->render_targets[0] = swapchain->backBuffer[0];
1816 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1818 else {
1819 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1820 This->render_targets[0] = swapchain->frontBuffer;
1821 This->lastActiveRenderTarget = swapchain->frontBuffer;
1823 IWineD3DSurface_AddRef(This->render_targets[0]);
1824 This->activeContext = swapchain->context[0];
1825 This->lastThread = GetCurrentThreadId();
1827 /* Depth Stencil support */
1828 This->stencilBufferTarget = This->depthStencilBuffer;
1829 if (NULL != This->stencilBufferTarget) {
1830 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1833 /* Set up some starting GL setup */
1834 ENTER_GL();
1836 /* Setup all the devices defaults */
1837 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1838 #if 0
1839 IWineD3DImpl_CheckGraphicsMemory();
1840 #endif
1842 { /* Set a default viewport */
1843 WINED3DVIEWPORT vp;
1844 vp.X = 0;
1845 vp.Y = 0;
1846 vp.Width = pPresentationParameters->BackBufferWidth;
1847 vp.Height = pPresentationParameters->BackBufferHeight;
1848 vp.MinZ = 0.0f;
1849 vp.MaxZ = 1.0f;
1850 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1853 /* Initialize the current view state */
1854 This->view_ident = 1;
1855 This->contexts[0]->last_was_rhw = 0;
1856 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1857 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1859 switch(wined3d_settings.offscreen_rendering_mode) {
1860 case ORM_FBO:
1861 case ORM_PBUFFER:
1862 This->offscreenBuffer = GL_BACK;
1863 break;
1865 case ORM_BACKBUFFER:
1867 if(GL_LIMITS(aux_buffers) > 0) {
1868 TRACE("Using auxilliary buffer for offscreen rendering\n");
1869 This->offscreenBuffer = GL_AUX0;
1870 } else {
1871 TRACE("Using back buffer for offscreen rendering\n");
1872 This->offscreenBuffer = GL_BACK;
1877 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1878 LEAVE_GL();
1880 /* Clear the screen */
1881 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1882 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1883 0x00, 1.0, 0);
1885 This->d3d_initialized = TRUE;
1886 return WINED3D_OK;
1889 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1891 int sampler;
1892 uint i;
1893 TRACE("(%p)\n", This);
1895 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1897 ENTER_GL();
1898 /* I don't think that the interface guarants that the device is destroyed from the same thread
1899 * it was created. Thus make sure a context is active for the glDelete* calls
1901 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1902 LEAVE_GL();
1904 TRACE("Deleting high order patches\n");
1905 for(i = 0; i < PATCHMAP_SIZE; i++) {
1906 struct list *e1, *e2;
1907 struct WineD3DRectPatch *patch;
1908 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1909 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1910 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1914 /* Delete the pbuffer context if there is any */
1915 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1917 /* Delete the mouse cursor texture */
1918 if(This->cursorTexture) {
1919 ENTER_GL();
1920 glDeleteTextures(1, &This->cursorTexture);
1921 LEAVE_GL();
1922 This->cursorTexture = 0;
1925 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1926 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1928 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1929 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1932 /* Release the buffers (with sanity checks)*/
1933 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1934 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1935 if(This->depthStencilBuffer != This->stencilBufferTarget)
1936 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1938 This->stencilBufferTarget = NULL;
1940 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1941 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1942 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1944 TRACE("Setting rendertarget to NULL\n");
1945 This->render_targets[0] = NULL;
1947 if (This->depthStencilBuffer) {
1948 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1949 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1951 This->depthStencilBuffer = NULL;
1954 for(i=0; i < This->NumberOfSwapChains; i++) {
1955 TRACE("Releasing the implicit swapchain %d\n", i);
1956 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1957 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1961 HeapFree(GetProcessHeap(), 0, This->swapchains);
1962 This->swapchains = NULL;
1963 This->NumberOfSwapChains = 0;
1965 /* Release the update stateblock */
1966 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1967 if(This->updateStateBlock != This->stateBlock)
1968 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1970 This->updateStateBlock = NULL;
1972 { /* because were not doing proper internal refcounts releasing the primary state block
1973 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1974 to set this->stateBlock = NULL; first */
1975 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1976 This->stateBlock = NULL;
1978 /* Release the stateblock */
1979 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1980 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1984 HeapFree(GetProcessHeap(), 0, This->render_targets);
1985 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
1986 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1987 This->render_targets = NULL;
1988 This->fbo_color_attachments = NULL;
1989 This->draw_buffers = NULL;
1992 This->d3d_initialized = FALSE;
1993 return WINED3D_OK;
1996 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1998 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2000 /* Setup the window for fullscreen mode */
2001 if(fullscreen && !This->ddraw_fullscreen) {
2002 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2003 } else if(!fullscreen && This->ddraw_fullscreen) {
2004 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2007 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2008 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2009 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2010 * separately.
2012 This->ddraw_fullscreen = fullscreen;
2015 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2016 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2017 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2019 * There is no way to deactivate thread safety once it is enabled
2021 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2024 /*For now just store the flag(needed in case of ddraw) */
2025 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2027 return;
2030 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2031 DEVMODEW devmode;
2032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2033 LONG ret;
2034 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2035 RECT clip_rc;
2037 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2039 /* Resize the screen even without a window:
2040 * The app could have unset it with SetCooperativeLevel, but not called
2041 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2042 * but we don't have any hwnd
2045 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2046 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2047 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2048 devmode.dmPelsWidth = pMode->Width;
2049 devmode.dmPelsHeight = pMode->Height;
2051 devmode.dmDisplayFrequency = pMode->RefreshRate;
2052 if (pMode->RefreshRate != 0) {
2053 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2056 /* Only change the mode if necessary */
2057 if( (This->ddraw_width == pMode->Width) &&
2058 (This->ddraw_height == pMode->Height) &&
2059 (This->ddraw_format == pMode->Format) &&
2060 (pMode->RefreshRate == 0) ) {
2061 return WINED3D_OK;
2064 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2065 if (ret != DISP_CHANGE_SUCCESSFUL) {
2066 if(devmode.dmDisplayFrequency != 0) {
2067 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2068 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2069 devmode.dmDisplayFrequency = 0;
2070 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2072 if(ret != DISP_CHANGE_SUCCESSFUL) {
2073 return WINED3DERR_NOTAVAILABLE;
2077 /* Store the new values */
2078 This->ddraw_width = pMode->Width;
2079 This->ddraw_height = pMode->Height;
2080 This->ddraw_format = pMode->Format;
2082 /* Only do this with a window of course */
2083 if(This->ddraw_window)
2084 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2086 /* And finally clip mouse to our screen */
2087 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2088 ClipCursor(&clip_rc);
2090 return WINED3D_OK;
2093 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2095 *ppD3D= This->wineD3D;
2096 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2097 IWineD3D_AddRef(*ppD3D);
2098 return WINED3D_OK;
2101 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2102 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2103 * into the video ram as possible and seeing how many fit
2104 * you can also get the correct initial value from nvidia and ATI's driver via X
2105 * texture memory is video memory + AGP memory
2106 *******************/
2107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2108 static BOOL showfixmes = TRUE;
2109 if (showfixmes) {
2110 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2111 (wined3d_settings.emulated_textureram/(1024*1024)),
2112 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2113 showfixmes = FALSE;
2115 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2116 (wined3d_settings.emulated_textureram/(1024*1024)),
2117 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2118 /* return simulated texture memory left */
2119 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2124 /*****
2125 * Get / Set FVF
2126 *****/
2127 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2130 /* Update the current state block */
2131 This->updateStateBlock->changed.fvf = TRUE;
2132 This->updateStateBlock->set.fvf = TRUE;
2134 if(This->updateStateBlock->fvf == fvf) {
2135 TRACE("Application is setting the old fvf over, nothing to do\n");
2136 return WINED3D_OK;
2139 This->updateStateBlock->fvf = fvf;
2140 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2142 return WINED3D_OK;
2146 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2148 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2149 *pfvf = This->stateBlock->fvf;
2150 return WINED3D_OK;
2153 /*****
2154 * Get / Set Stream Source
2155 *****/
2156 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2158 IWineD3DVertexBuffer *oldSrc;
2160 if (StreamNumber >= MAX_STREAMS) {
2161 WARN("Stream out of range %d\n", StreamNumber);
2162 return WINED3DERR_INVALIDCALL;
2165 oldSrc = This->stateBlock->streamSource[StreamNumber];
2166 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2168 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2169 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2171 if(oldSrc == pStreamData &&
2172 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2173 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2174 TRACE("Application is setting the old values over, nothing to do\n");
2175 return WINED3D_OK;
2178 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2179 if (pStreamData) {
2180 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2181 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2184 /* Handle recording of state blocks */
2185 if (This->isRecordingState) {
2186 TRACE("Recording... not performing anything\n");
2187 return WINED3D_OK;
2190 /* Need to do a getParent and pass the reffs up */
2191 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2192 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2193 so for now, just count internally */
2194 if (pStreamData != NULL) {
2195 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2196 InterlockedIncrement(&vbImpl->bindCount);
2198 if (oldSrc != NULL) {
2199 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2204 return WINED3D_OK;
2207 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2210 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2211 This->stateBlock->streamSource[StreamNumber],
2212 This->stateBlock->streamOffset[StreamNumber],
2213 This->stateBlock->streamStride[StreamNumber]);
2215 if (StreamNumber >= MAX_STREAMS) {
2216 WARN("Stream out of range %d\n", StreamNumber);
2217 return WINED3DERR_INVALIDCALL;
2219 *pStream = This->stateBlock->streamSource[StreamNumber];
2220 *pStride = This->stateBlock->streamStride[StreamNumber];
2221 if (pOffset) {
2222 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2225 if (*pStream != NULL) {
2226 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2228 return WINED3D_OK;
2231 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2233 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2234 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2236 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2237 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2239 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2240 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2241 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2243 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2244 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2248 return WINED3D_OK;
2251 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2254 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2255 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2257 TRACE("(%p) : returning %d\n", This, *Divider);
2259 return WINED3D_OK;
2262 /*****
2263 * Get / Set & Multiply Transform
2264 *****/
2265 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2268 /* Most of this routine, comments included copied from ddraw tree initially: */
2269 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2271 /* Handle recording of state blocks */
2272 if (This->isRecordingState) {
2273 TRACE("Recording... not performing anything\n");
2274 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2275 This->updateStateBlock->set.transform[d3dts] = TRUE;
2276 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2277 return WINED3D_OK;
2281 * If the new matrix is the same as the current one,
2282 * we cut off any further processing. this seems to be a reasonable
2283 * optimization because as was noticed, some apps (warcraft3 for example)
2284 * tend towards setting the same matrix repeatedly for some reason.
2286 * From here on we assume that the new matrix is different, wherever it matters.
2288 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2289 TRACE("The app is setting the same matrix over again\n");
2290 return WINED3D_OK;
2291 } else {
2292 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2296 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2297 where ViewMat = Camera space, WorldMat = world space.
2299 In OpenGL, camera and world space is combined into GL_MODELVIEW
2300 matrix. The Projection matrix stay projection matrix.
2303 /* Capture the times we can just ignore the change for now */
2304 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2305 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2306 /* Handled by the state manager */
2309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2310 return WINED3D_OK;
2313 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2315 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2316 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2317 return WINED3D_OK;
2320 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2321 WINED3DMATRIX *mat = NULL;
2322 WINED3DMATRIX temp;
2324 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2325 * below means it will be recorded in a state block change, but it
2326 * works regardless where it is recorded.
2327 * If this is found to be wrong, change to StateBlock.
2329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2330 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2332 if (State < HIGHEST_TRANSFORMSTATE)
2334 mat = &This->updateStateBlock->transforms[State];
2335 } else {
2336 FIXME("Unhandled transform state!!\n");
2339 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2341 /* Apply change via set transform - will reapply to eg. lights this way */
2342 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2345 /*****
2346 * Get / Set Light
2347 *****/
2348 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2349 you can reference any indexes you want as long as that number max are enabled at any
2350 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2351 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2352 but when recording, just build a chain pretty much of commands to be replayed. */
2354 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2355 float rho;
2356 PLIGHTINFOEL *object = NULL;
2357 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2358 struct list *e;
2360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2361 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2363 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2364 * the gl driver.
2366 if(!pLight) {
2367 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2368 return WINED3DERR_INVALIDCALL;
2371 switch(pLight->Type) {
2372 case WINED3DLIGHT_POINT:
2373 case WINED3DLIGHT_SPOT:
2374 case WINED3DLIGHT_PARALLELPOINT:
2375 case WINED3DLIGHT_GLSPOT:
2376 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2377 * most wanted
2379 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2380 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2381 return WINED3DERR_INVALIDCALL;
2383 break;
2385 case WINED3DLIGHT_DIRECTIONAL:
2386 /* Ignores attenuation */
2387 break;
2389 default:
2390 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2391 return WINED3DERR_INVALIDCALL;
2394 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2395 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2396 if(object->OriginalIndex == Index) break;
2397 object = NULL;
2400 if(!object) {
2401 TRACE("Adding new light\n");
2402 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2403 if(!object) {
2404 ERR("Out of memory error when allocating a light\n");
2405 return E_OUTOFMEMORY;
2407 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2408 object->glIndex = -1;
2409 object->OriginalIndex = Index;
2410 object->changed = TRUE;
2413 /* Initialize the object */
2414 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,
2415 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2416 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2417 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2418 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2419 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2420 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2422 /* Save away the information */
2423 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2425 switch (pLight->Type) {
2426 case WINED3DLIGHT_POINT:
2427 /* Position */
2428 object->lightPosn[0] = pLight->Position.x;
2429 object->lightPosn[1] = pLight->Position.y;
2430 object->lightPosn[2] = pLight->Position.z;
2431 object->lightPosn[3] = 1.0f;
2432 object->cutoff = 180.0f;
2433 /* FIXME: Range */
2434 break;
2436 case WINED3DLIGHT_DIRECTIONAL:
2437 /* Direction */
2438 object->lightPosn[0] = -pLight->Direction.x;
2439 object->lightPosn[1] = -pLight->Direction.y;
2440 object->lightPosn[2] = -pLight->Direction.z;
2441 object->lightPosn[3] = 0.0;
2442 object->exponent = 0.0f;
2443 object->cutoff = 180.0f;
2444 break;
2446 case WINED3DLIGHT_SPOT:
2447 /* Position */
2448 object->lightPosn[0] = pLight->Position.x;
2449 object->lightPosn[1] = pLight->Position.y;
2450 object->lightPosn[2] = pLight->Position.z;
2451 object->lightPosn[3] = 1.0;
2453 /* Direction */
2454 object->lightDirn[0] = pLight->Direction.x;
2455 object->lightDirn[1] = pLight->Direction.y;
2456 object->lightDirn[2] = pLight->Direction.z;
2457 object->lightDirn[3] = 1.0;
2460 * opengl-ish and d3d-ish spot lights use too different models for the
2461 * light "intensity" as a function of the angle towards the main light direction,
2462 * so we only can approximate very roughly.
2463 * however spot lights are rather rarely used in games (if ever used at all).
2464 * furthermore if still used, probably nobody pays attention to such details.
2466 if (pLight->Falloff == 0) {
2467 rho = 6.28f;
2468 } else {
2469 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2471 if (rho < 0.0001) rho = 0.0001f;
2472 object->exponent = -0.3/log(cos(rho/2));
2473 if (object->exponent > 128.0) {
2474 object->exponent = 128.0;
2476 object->cutoff = pLight->Phi*90/M_PI;
2478 /* FIXME: Range */
2479 break;
2481 default:
2482 FIXME("Unrecognized light type %d\n", pLight->Type);
2485 /* Update the live definitions if the light is currently assigned a glIndex */
2486 if (object->glIndex != -1 && !This->isRecordingState) {
2487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2489 return WINED3D_OK;
2492 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2493 PLIGHTINFOEL *lightInfo = NULL;
2494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2495 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2496 struct list *e;
2497 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2499 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2500 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2501 if(lightInfo->OriginalIndex == Index) break;
2502 lightInfo = NULL;
2505 if (lightInfo == NULL) {
2506 TRACE("Light information requested but light not defined\n");
2507 return WINED3DERR_INVALIDCALL;
2510 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2511 return WINED3D_OK;
2514 /*****
2515 * Get / Set Light Enable
2516 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2517 *****/
2518 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2519 PLIGHTINFOEL *lightInfo = NULL;
2520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2521 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2522 struct list *e;
2523 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2525 /* Tests show true = 128...not clear why */
2526 Enable = Enable? 128: 0;
2528 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2529 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2530 if(lightInfo->OriginalIndex == Index) break;
2531 lightInfo = NULL;
2533 TRACE("Found light: %p\n", lightInfo);
2535 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2536 if (lightInfo == NULL) {
2538 TRACE("Light enabled requested but light not defined, so defining one!\n");
2539 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2541 /* Search for it again! Should be fairly quick as near head of list */
2542 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2543 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2544 if(lightInfo->OriginalIndex == Index) break;
2545 lightInfo = NULL;
2547 if (lightInfo == NULL) {
2548 FIXME("Adding default lights has failed dismally\n");
2549 return WINED3DERR_INVALIDCALL;
2553 lightInfo->enabledChanged = TRUE;
2554 if(!Enable) {
2555 if(lightInfo->glIndex != -1) {
2556 if(!This->isRecordingState) {
2557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2560 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2561 lightInfo->glIndex = -1;
2562 } else {
2563 TRACE("Light already disabled, nothing to do\n");
2565 } else {
2566 if (lightInfo->glIndex != -1) {
2567 /* nop */
2568 TRACE("Nothing to do as light was enabled\n");
2569 } else {
2570 int i;
2571 /* Find a free gl light */
2572 for(i = 0; i < This->maxConcurrentLights; i++) {
2573 if(This->stateBlock->activeLights[i] == NULL) {
2574 This->stateBlock->activeLights[i] = lightInfo;
2575 lightInfo->glIndex = i;
2576 break;
2579 if(lightInfo->glIndex == -1) {
2580 ERR("Too many concurrently active lights\n");
2581 return WINED3DERR_INVALIDCALL;
2584 /* i == lightInfo->glIndex */
2585 if(!This->isRecordingState) {
2586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2591 return WINED3D_OK;
2594 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2596 PLIGHTINFOEL *lightInfo = NULL;
2597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2598 struct list *e;
2599 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2600 TRACE("(%p) : for idx(%d)\n", This, Index);
2602 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2603 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2604 if(lightInfo->OriginalIndex == Index) break;
2605 lightInfo = NULL;
2608 if (lightInfo == NULL) {
2609 TRACE("Light enabled state requested but light not defined\n");
2610 return WINED3DERR_INVALIDCALL;
2612 /* true is 128 according to SetLightEnable */
2613 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2614 return WINED3D_OK;
2617 /*****
2618 * Get / Set Clip Planes
2619 *****/
2620 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2622 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2624 /* Validate Index */
2625 if (Index >= GL_LIMITS(clipplanes)) {
2626 TRACE("Application has requested clipplane this device doesn't support\n");
2627 return WINED3DERR_INVALIDCALL;
2630 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2631 This->updateStateBlock->set.clipplane[Index] = TRUE;
2633 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2634 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2635 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2636 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2637 TRACE("Application is setting old values over, nothing to do\n");
2638 return WINED3D_OK;
2641 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2642 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2643 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2644 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2646 /* Handle recording of state blocks */
2647 if (This->isRecordingState) {
2648 TRACE("Recording... not performing anything\n");
2649 return WINED3D_OK;
2652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2654 return WINED3D_OK;
2657 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 TRACE("(%p) : for idx %d\n", This, Index);
2661 /* Validate Index */
2662 if (Index >= GL_LIMITS(clipplanes)) {
2663 TRACE("Application has requested clipplane this device doesn't support\n");
2664 return WINED3DERR_INVALIDCALL;
2667 pPlane[0] = This->stateBlock->clipplane[Index][0];
2668 pPlane[1] = This->stateBlock->clipplane[Index][1];
2669 pPlane[2] = This->stateBlock->clipplane[Index][2];
2670 pPlane[3] = This->stateBlock->clipplane[Index][3];
2671 return WINED3D_OK;
2674 /*****
2675 * Get / Set Clip Plane Status
2676 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2677 *****/
2678 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2680 FIXME("(%p) : stub\n", This);
2681 if (NULL == pClipStatus) {
2682 return WINED3DERR_INVALIDCALL;
2684 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2685 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2686 return WINED3D_OK;
2689 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 FIXME("(%p) : stub\n", This);
2692 if (NULL == pClipStatus) {
2693 return WINED3DERR_INVALIDCALL;
2695 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2696 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2697 return WINED3D_OK;
2700 /*****
2701 * Get / Set Material
2702 *****/
2703 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2706 This->updateStateBlock->changed.material = TRUE;
2707 This->updateStateBlock->set.material = TRUE;
2708 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2710 /* Handle recording of state blocks */
2711 if (This->isRecordingState) {
2712 TRACE("Recording... not performing anything\n");
2713 return WINED3D_OK;
2716 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2717 return WINED3D_OK;
2720 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2722 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2723 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2724 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2725 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2726 pMaterial->Ambient.b, pMaterial->Ambient.a);
2727 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2728 pMaterial->Specular.b, pMaterial->Specular.a);
2729 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2730 pMaterial->Emissive.b, pMaterial->Emissive.a);
2731 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2733 return WINED3D_OK;
2736 /*****
2737 * Get / Set Indices
2738 *****/
2739 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2741 IWineD3DIndexBuffer *oldIdxs;
2743 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2744 oldIdxs = This->updateStateBlock->pIndexData;
2746 This->updateStateBlock->changed.indices = TRUE;
2747 This->updateStateBlock->set.indices = TRUE;
2748 This->updateStateBlock->pIndexData = pIndexData;
2750 /* Handle recording of state blocks */
2751 if (This->isRecordingState) {
2752 TRACE("Recording... not performing anything\n");
2753 return WINED3D_OK;
2756 if(oldIdxs != pIndexData) {
2757 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2759 return WINED3D_OK;
2762 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 *ppIndexData = This->stateBlock->pIndexData;
2767 /* up ref count on ppindexdata */
2768 if (*ppIndexData) {
2769 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2770 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2771 }else{
2772 TRACE("(%p) No index data set\n", This);
2774 TRACE("Returning %p\n", *ppIndexData);
2776 return WINED3D_OK;
2779 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2780 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2782 TRACE("(%p)->(%d)\n", This, BaseIndex);
2784 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2785 TRACE("Application is setting the old value over, nothing to do\n");
2786 return WINED3D_OK;
2789 This->updateStateBlock->baseVertexIndex = BaseIndex;
2791 if (This->isRecordingState) {
2792 TRACE("Recording... not performing anything\n");
2793 return WINED3D_OK;
2795 /* The base vertex index affects the stream sources */
2796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2797 return WINED3D_OK;
2800 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802 TRACE("(%p) : base_index %p\n", This, base_index);
2804 *base_index = This->stateBlock->baseVertexIndex;
2806 TRACE("Returning %u\n", *base_index);
2808 return WINED3D_OK;
2811 /*****
2812 * Get / Set Viewports
2813 *****/
2814 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 TRACE("(%p)\n", This);
2818 This->updateStateBlock->changed.viewport = TRUE;
2819 This->updateStateBlock->set.viewport = TRUE;
2820 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2822 /* Handle recording of state blocks */
2823 if (This->isRecordingState) {
2824 TRACE("Recording... not performing anything\n");
2825 return WINED3D_OK;
2828 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2829 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2832 return WINED3D_OK;
2836 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2838 TRACE("(%p)\n", This);
2839 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2840 return WINED3D_OK;
2843 /*****
2844 * Get / Set Render States
2845 * TODO: Verify against dx9 definitions
2846 *****/
2847 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850 DWORD oldValue = This->stateBlock->renderState[State];
2852 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2854 This->updateStateBlock->changed.renderState[State] = TRUE;
2855 This->updateStateBlock->set.renderState[State] = TRUE;
2856 This->updateStateBlock->renderState[State] = Value;
2858 /* Handle recording of state blocks */
2859 if (This->isRecordingState) {
2860 TRACE("Recording... not performing anything\n");
2861 return WINED3D_OK;
2864 /* Compared here and not before the assignment to allow proper stateblock recording */
2865 if(Value == oldValue) {
2866 TRACE("Application is setting the old value over, nothing to do\n");
2867 } else {
2868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2871 return WINED3D_OK;
2874 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2876 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2877 *pValue = This->stateBlock->renderState[State];
2878 return WINED3D_OK;
2881 /*****
2882 * Get / Set Sampler States
2883 * TODO: Verify against dx9 definitions
2884 *****/
2886 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 DWORD oldValue;
2890 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2891 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2893 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2894 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2898 * SetSampler is designed to allow for more than the standard up to 8 textures
2899 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2900 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2902 * http://developer.nvidia.com/object/General_FAQ.html#t6
2904 * There are two new settings for GForce
2905 * the sampler one:
2906 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2907 * and the texture one:
2908 * GL_MAX_TEXTURE_COORDS_ARB.
2909 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2910 ******************/
2912 oldValue = This->stateBlock->samplerState[Sampler][Type];
2913 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2914 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2915 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2917 /* Handle recording of state blocks */
2918 if (This->isRecordingState) {
2919 TRACE("Recording... not performing anything\n");
2920 return WINED3D_OK;
2923 if(oldValue == Value) {
2924 TRACE("Application is setting the old value over, nothing to do\n");
2925 return WINED3D_OK;
2928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2930 return WINED3D_OK;
2933 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2936 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2937 This, Sampler, debug_d3dsamplerstate(Type), Type);
2939 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2940 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2943 *Value = This->stateBlock->samplerState[Sampler][Type];
2944 TRACE("(%p) : Returning %#x\n", This, *Value);
2946 return WINED3D_OK;
2949 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 This->updateStateBlock->set.scissorRect = TRUE;
2953 This->updateStateBlock->changed.scissorRect = TRUE;
2954 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2955 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2956 return WINED3D_OK;
2958 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2960 if(This->isRecordingState) {
2961 TRACE("Recording... not performing anything\n");
2962 return WINED3D_OK;
2965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2967 return WINED3D_OK;
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2974 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2980 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2982 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2984 This->updateStateBlock->vertexDecl = pDecl;
2985 This->updateStateBlock->changed.vertexDecl = TRUE;
2986 This->updateStateBlock->set.vertexDecl = TRUE;
2988 if (This->isRecordingState) {
2989 TRACE("Recording... not performing anything\n");
2990 return WINED3D_OK;
2991 } else if(pDecl == oldDecl) {
2992 /* Checked after the assignment to allow proper stateblock recording */
2993 TRACE("Application is setting the old declaration over, nothing to do\n");
2994 return WINED3D_OK;
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3006 *ppDecl = This->stateBlock->vertexDecl;
3007 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3008 return WINED3D_OK;
3011 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3015 This->updateStateBlock->vertexShader = pShader;
3016 This->updateStateBlock->changed.vertexShader = TRUE;
3017 This->updateStateBlock->set.vertexShader = TRUE;
3019 if (This->isRecordingState) {
3020 TRACE("Recording... not performing anything\n");
3021 return WINED3D_OK;
3022 } else if(oldShader == pShader) {
3023 /* Checked here to allow proper stateblock recording */
3024 TRACE("App is setting the old shader over, nothing to do\n");
3025 return WINED3D_OK;
3028 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 if (NULL == ppShader) {
3039 return WINED3DERR_INVALIDCALL;
3041 *ppShader = This->stateBlock->vertexShader;
3042 if( NULL != *ppShader)
3043 IWineD3DVertexShader_AddRef(*ppShader);
3045 TRACE("(%p) : returning %p\n", This, *ppShader);
3046 return WINED3D_OK;
3049 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3050 IWineD3DDevice *iface,
3051 UINT start,
3052 CONST BOOL *srcData,
3053 UINT count) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 int i, cnt = min(count, MAX_CONST_B - start);
3058 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3059 iface, srcData, start, count);
3061 if (srcData == NULL || cnt < 0)
3062 return WINED3DERR_INVALIDCALL;
3064 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3065 for (i = 0; i < cnt; i++)
3066 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3068 for (i = start; i < cnt + start; ++i) {
3069 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3070 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3075 return WINED3D_OK;
3078 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3079 IWineD3DDevice *iface,
3080 UINT start,
3081 BOOL *dstData,
3082 UINT count) {
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 int cnt = min(count, MAX_CONST_B - start);
3087 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3088 iface, dstData, start, count);
3090 if (dstData == NULL || cnt < 0)
3091 return WINED3DERR_INVALIDCALL;
3093 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3094 return WINED3D_OK;
3097 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3098 IWineD3DDevice *iface,
3099 UINT start,
3100 CONST int *srcData,
3101 UINT count) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 int i, cnt = min(count, MAX_CONST_I - start);
3106 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3107 iface, srcData, start, count);
3109 if (srcData == NULL || cnt < 0)
3110 return WINED3DERR_INVALIDCALL;
3112 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3113 for (i = 0; i < cnt; i++)
3114 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3115 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3117 for (i = start; i < cnt + start; ++i) {
3118 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3119 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3124 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3128 IWineD3DDevice *iface,
3129 UINT start,
3130 int *dstData,
3131 UINT count) {
3133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3134 int cnt = min(count, MAX_CONST_I - start);
3136 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3137 iface, dstData, start, count);
3139 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3140 return WINED3DERR_INVALIDCALL;
3142 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3143 return WINED3D_OK;
3146 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3147 IWineD3DDevice *iface,
3148 UINT start,
3149 CONST float *srcData,
3150 UINT count) {
3152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 int i;
3155 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3156 iface, srcData, start, count);
3158 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3159 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3160 return WINED3DERR_INVALIDCALL;
3162 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3163 if(TRACE_ON(d3d)) {
3164 for (i = 0; i < count; i++)
3165 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3166 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3169 for (i = start; i < count + start; ++i) {
3170 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3171 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3172 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3173 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3174 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3176 ptr->idx[ptr->count++] = i;
3177 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3179 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3184 return WINED3D_OK;
3187 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3188 IWineD3DDevice *iface,
3189 UINT start,
3190 float *dstData,
3191 UINT count) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3196 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3197 iface, dstData, start, count);
3199 if (dstData == NULL || cnt < 0)
3200 return WINED3DERR_INVALIDCALL;
3202 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3203 return WINED3D_OK;
3206 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3207 DWORD i;
3208 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3213 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3214 int i = This->rev_tex_unit_map[unit];
3215 int j = This->texUnitMap[stage];
3217 This->texUnitMap[stage] = unit;
3218 if (i != -1 && i != stage) {
3219 This->texUnitMap[i] = -1;
3222 This->rev_tex_unit_map[unit] = stage;
3223 if (j != -1 && j != unit) {
3224 This->rev_tex_unit_map[j] = -1;
3228 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3229 int i;
3231 for (i = 0; i < MAX_TEXTURES; ++i) {
3232 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3233 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3234 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3235 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3236 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3237 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3238 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3239 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3241 if (color_op == WINED3DTOP_DISABLE) {
3242 /* Not used, and disable higher stages */
3243 while (i < MAX_TEXTURES) {
3244 This->fixed_function_usage_map[i] = FALSE;
3245 ++i;
3247 break;
3250 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3251 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3252 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3253 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3254 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3255 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3256 This->fixed_function_usage_map[i] = TRUE;
3257 } else {
3258 This->fixed_function_usage_map[i] = FALSE;
3261 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3262 This->fixed_function_usage_map[i+1] = TRUE;
3267 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3268 int i, tex;
3270 device_update_fixed_function_usage_map(This);
3272 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3273 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3274 if (!This->fixed_function_usage_map[i]) continue;
3276 if (This->texUnitMap[i] != i) {
3277 device_map_stage(This, i, i);
3278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3279 markTextureStagesDirty(This, i);
3282 return;
3285 /* Now work out the mapping */
3286 tex = 0;
3287 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3288 if (!This->fixed_function_usage_map[i]) continue;
3290 if (This->texUnitMap[i] != tex) {
3291 device_map_stage(This, i, tex);
3292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3293 markTextureStagesDirty(This, i);
3296 ++tex;
3300 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3301 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3302 int i;
3304 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3305 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3306 device_map_stage(This, i, i);
3307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3308 if (i < MAX_TEXTURES) {
3309 markTextureStagesDirty(This, i);
3315 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3316 int current_mapping = This->rev_tex_unit_map[unit];
3318 if (current_mapping == -1) {
3319 /* Not currently used */
3320 return TRUE;
3323 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3324 /* Used by a fragment sampler */
3326 if (!pshader_sampler_tokens) {
3327 /* No pixel shader, check fixed function */
3328 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3331 /* Pixel shader, check the shader's sampler map */
3332 return !pshader_sampler_tokens[current_mapping];
3335 /* Used by a vertex sampler */
3336 return !vshader_sampler_tokens[current_mapping];
3339 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3340 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3341 DWORD *pshader_sampler_tokens = NULL;
3342 int start = GL_LIMITS(combined_samplers) - 1;
3343 int i;
3345 if (ps) {
3346 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3348 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3349 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3350 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3353 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3354 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3355 if (vshader_sampler_tokens[i]) {
3356 if (This->texUnitMap[vsampler_idx] != -1) {
3357 /* Already mapped somewhere */
3358 continue;
3361 while (start >= 0) {
3362 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3363 device_map_stage(This, vsampler_idx, start);
3364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3366 --start;
3367 break;
3370 --start;
3376 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3377 BOOL vs = use_vs(This);
3378 BOOL ps = use_ps(This);
3380 * Rules are:
3381 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3382 * that would be really messy and require shader recompilation
3383 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3384 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3386 if (ps) {
3387 device_map_psamplers(This);
3388 } else {
3389 device_map_fixed_function_samplers(This);
3392 if (vs) {
3393 device_map_vsamplers(This, ps);
3397 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3399 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3400 This->updateStateBlock->pixelShader = pShader;
3401 This->updateStateBlock->changed.pixelShader = TRUE;
3402 This->updateStateBlock->set.pixelShader = TRUE;
3404 /* Handle recording of state blocks */
3405 if (This->isRecordingState) {
3406 TRACE("Recording... not performing anything\n");
3409 if (This->isRecordingState) {
3410 TRACE("Recording... not performing anything\n");
3411 return WINED3D_OK;
3414 if(pShader == oldShader) {
3415 TRACE("App is setting the old pixel shader over, nothing to do\n");
3416 return WINED3D_OK;
3419 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3422 return WINED3D_OK;
3425 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3428 if (NULL == ppShader) {
3429 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3430 return WINED3DERR_INVALIDCALL;
3433 *ppShader = This->stateBlock->pixelShader;
3434 if (NULL != *ppShader) {
3435 IWineD3DPixelShader_AddRef(*ppShader);
3437 TRACE("(%p) : returning %p\n", This, *ppShader);
3438 return WINED3D_OK;
3441 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3442 IWineD3DDevice *iface,
3443 UINT start,
3444 CONST BOOL *srcData,
3445 UINT count) {
3447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3448 int i, cnt = min(count, MAX_CONST_B - start);
3450 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3451 iface, srcData, start, count);
3453 if (srcData == NULL || cnt < 0)
3454 return WINED3DERR_INVALIDCALL;
3456 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3457 for (i = 0; i < cnt; i++)
3458 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3460 for (i = start; i < cnt + start; ++i) {
3461 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3462 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3467 return WINED3D_OK;
3470 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3471 IWineD3DDevice *iface,
3472 UINT start,
3473 BOOL *dstData,
3474 UINT count) {
3476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3477 int cnt = min(count, MAX_CONST_B - start);
3479 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3480 iface, dstData, start, count);
3482 if (dstData == NULL || cnt < 0)
3483 return WINED3DERR_INVALIDCALL;
3485 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3486 return WINED3D_OK;
3489 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3490 IWineD3DDevice *iface,
3491 UINT start,
3492 CONST int *srcData,
3493 UINT count) {
3495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3496 int i, cnt = min(count, MAX_CONST_I - start);
3498 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3499 iface, srcData, start, count);
3501 if (srcData == NULL || cnt < 0)
3502 return WINED3DERR_INVALIDCALL;
3504 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3505 for (i = 0; i < cnt; i++)
3506 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3507 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3509 for (i = start; i < cnt + start; ++i) {
3510 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3511 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3514 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3516 return WINED3D_OK;
3519 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3520 IWineD3DDevice *iface,
3521 UINT start,
3522 int *dstData,
3523 UINT count) {
3525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3526 int cnt = min(count, MAX_CONST_I - start);
3528 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3529 iface, dstData, start, count);
3531 if (dstData == NULL || cnt < 0)
3532 return WINED3DERR_INVALIDCALL;
3534 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3535 return WINED3D_OK;
3538 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3539 IWineD3DDevice *iface,
3540 UINT start,
3541 CONST float *srcData,
3542 UINT count) {
3544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3545 int i;
3547 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3548 iface, srcData, start, count);
3550 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3551 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3552 return WINED3DERR_INVALIDCALL;
3554 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3555 if(TRACE_ON(d3d)) {
3556 for (i = 0; i < count; i++)
3557 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3558 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3561 for (i = start; i < count + start; ++i) {
3562 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3563 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3564 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3565 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3566 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3568 ptr->idx[ptr->count++] = i;
3569 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3571 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3576 return WINED3D_OK;
3579 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3580 IWineD3DDevice *iface,
3581 UINT start,
3582 float *dstData,
3583 UINT count) {
3585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3586 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3588 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3589 iface, dstData, start, count);
3591 if (dstData == NULL || cnt < 0)
3592 return WINED3DERR_INVALIDCALL;
3594 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3595 return WINED3D_OK;
3598 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3599 static HRESULT
3600 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3601 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3602 unsigned int i;
3603 DWORD DestFVF = dest->fvf;
3604 WINED3DVIEWPORT vp;
3605 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3606 BOOL doClip;
3607 int numTextures;
3609 if (lpStrideData->u.s.normal.lpData) {
3610 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3613 if (lpStrideData->u.s.position.lpData == NULL) {
3614 ERR("Source has no position mask\n");
3615 return WINED3DERR_INVALIDCALL;
3618 /* We might access VBOs from this code, so hold the lock */
3619 ENTER_GL();
3621 if (dest->resource.allocatedMemory == NULL) {
3622 /* This may happen if we do direct locking into a vbo. Unlikely,
3623 * but theoretically possible(ddraw processvertices test)
3625 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3626 if(!dest->resource.allocatedMemory) {
3627 LEAVE_GL();
3628 ERR("Out of memory\n");
3629 return E_OUTOFMEMORY;
3631 if(dest->vbo) {
3632 void *src;
3633 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3634 checkGLcall("glBindBufferARB");
3635 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3636 if(src) {
3637 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3639 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3640 checkGLcall("glUnmapBufferARB");
3644 /* Get a pointer into the destination vbo(create one if none exists) and
3645 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3647 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3648 CreateVBO(dest);
3651 if(dest->vbo) {
3652 unsigned char extrabytes = 0;
3653 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3654 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3655 * this may write 4 extra bytes beyond the area that should be written
3657 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3658 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3659 if(!dest_conv_addr) {
3660 ERR("Out of memory\n");
3661 /* Continue without storing converted vertices */
3663 dest_conv = dest_conv_addr;
3666 /* Should I clip?
3667 * a) WINED3DRS_CLIPPING is enabled
3668 * b) WINED3DVOP_CLIP is passed
3670 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3671 static BOOL warned = FALSE;
3673 * The clipping code is not quite correct. Some things need
3674 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3675 * so disable clipping for now.
3676 * (The graphics in Half-Life are broken, and my processvertices
3677 * test crashes with IDirect3DDevice3)
3678 doClip = TRUE;
3680 doClip = FALSE;
3681 if(!warned) {
3682 warned = TRUE;
3683 FIXME("Clipping is broken and disabled for now\n");
3685 } else doClip = FALSE;
3686 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3688 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3689 WINED3DTS_VIEW,
3690 &view_mat);
3691 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3692 WINED3DTS_PROJECTION,
3693 &proj_mat);
3694 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3695 WINED3DTS_WORLDMATRIX(0),
3696 &world_mat);
3698 TRACE("View mat:\n");
3699 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);
3700 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);
3701 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);
3702 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);
3704 TRACE("Proj mat:\n");
3705 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);
3706 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);
3707 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);
3708 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);
3710 TRACE("World mat:\n");
3711 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);
3712 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);
3713 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);
3714 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);
3716 /* Get the viewport */
3717 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3718 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3719 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3721 multiply_matrix(&mat,&view_mat,&world_mat);
3722 multiply_matrix(&mat,&proj_mat,&mat);
3724 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3726 for (i = 0; i < dwCount; i+= 1) {
3727 unsigned int tex_index;
3729 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3730 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3731 /* The position first */
3732 float *p =
3733 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3734 float x, y, z, rhw;
3735 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3737 /* Multiplication with world, view and projection matrix */
3738 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);
3739 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);
3740 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);
3741 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);
3743 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3745 /* WARNING: The following things are taken from d3d7 and were not yet checked
3746 * against d3d8 or d3d9!
3749 /* Clipping conditions: From
3750 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3752 * A vertex is clipped if it does not match the following requirements
3753 * -rhw < x <= rhw
3754 * -rhw < y <= rhw
3755 * 0 < z <= rhw
3756 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3758 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3759 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3763 if( !doClip ||
3764 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3765 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3766 ( rhw > eps ) ) ) {
3768 /* "Normal" viewport transformation (not clipped)
3769 * 1) The values are divided by rhw
3770 * 2) The y axis is negative, so multiply it with -1
3771 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3772 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3773 * 4) Multiply x with Width/2 and add Width/2
3774 * 5) The same for the height
3775 * 6) Add the viewpoint X and Y to the 2D coordinates and
3776 * The minimum Z value to z
3777 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3779 * Well, basically it's simply a linear transformation into viewport
3780 * coordinates
3783 x /= rhw;
3784 y /= rhw;
3785 z /= rhw;
3787 y *= -1;
3789 x *= vp.Width / 2;
3790 y *= vp.Height / 2;
3791 z *= vp.MaxZ - vp.MinZ;
3793 x += vp.Width / 2 + vp.X;
3794 y += vp.Height / 2 + vp.Y;
3795 z += vp.MinZ;
3797 rhw = 1 / rhw;
3798 } else {
3799 /* That vertex got clipped
3800 * Contrary to OpenGL it is not dropped completely, it just
3801 * undergoes a different calculation.
3803 TRACE("Vertex got clipped\n");
3804 x += rhw;
3805 y += rhw;
3807 x /= 2;
3808 y /= 2;
3810 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3811 * outside of the main vertex buffer memory. That needs some more
3812 * investigation...
3816 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3819 ( (float *) dest_ptr)[0] = x;
3820 ( (float *) dest_ptr)[1] = y;
3821 ( (float *) dest_ptr)[2] = z;
3822 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3824 dest_ptr += 3 * sizeof(float);
3826 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3827 dest_ptr += sizeof(float);
3830 if(dest_conv) {
3831 float w = 1 / rhw;
3832 ( (float *) dest_conv)[0] = x * w;
3833 ( (float *) dest_conv)[1] = y * w;
3834 ( (float *) dest_conv)[2] = z * w;
3835 ( (float *) dest_conv)[3] = w;
3837 dest_conv += 3 * sizeof(float);
3839 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3840 dest_conv += sizeof(float);
3844 if (DestFVF & WINED3DFVF_PSIZE) {
3845 dest_ptr += sizeof(DWORD);
3846 if(dest_conv) dest_conv += sizeof(DWORD);
3848 if (DestFVF & WINED3DFVF_NORMAL) {
3849 float *normal =
3850 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3851 /* AFAIK this should go into the lighting information */
3852 FIXME("Didn't expect the destination to have a normal\n");
3853 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3854 if(dest_conv) {
3855 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3859 if (DestFVF & WINED3DFVF_DIFFUSE) {
3860 DWORD *color_d =
3861 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3862 if(!color_d) {
3863 static BOOL warned = FALSE;
3865 if(!warned) {
3866 ERR("No diffuse color in source, but destination has one\n");
3867 warned = TRUE;
3870 *( (DWORD *) dest_ptr) = 0xffffffff;
3871 dest_ptr += sizeof(DWORD);
3873 if(dest_conv) {
3874 *( (DWORD *) dest_conv) = 0xffffffff;
3875 dest_conv += sizeof(DWORD);
3878 else {
3879 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3880 if(dest_conv) {
3881 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3882 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3883 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3884 dest_conv += sizeof(DWORD);
3889 if (DestFVF & WINED3DFVF_SPECULAR) {
3890 /* What's the color value in the feedback buffer? */
3891 DWORD *color_s =
3892 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3893 if(!color_s) {
3894 static BOOL warned = FALSE;
3896 if(!warned) {
3897 ERR("No specular color in source, but destination has one\n");
3898 warned = TRUE;
3901 *( (DWORD *) dest_ptr) = 0xFF000000;
3902 dest_ptr += sizeof(DWORD);
3904 if(dest_conv) {
3905 *( (DWORD *) dest_conv) = 0xFF000000;
3906 dest_conv += sizeof(DWORD);
3909 else {
3910 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3911 if(dest_conv) {
3912 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3913 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3914 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3915 dest_conv += sizeof(DWORD);
3920 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3921 float *tex_coord =
3922 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3923 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3924 if(!tex_coord) {
3925 ERR("No source texture, but destination requests one\n");
3926 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3927 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3929 else {
3930 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3931 if(dest_conv) {
3932 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3938 if(dest_conv) {
3939 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3940 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3941 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3942 dwCount * get_flexible_vertex_size(DestFVF),
3943 dest_conv_addr));
3944 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3945 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3948 LEAVE_GL();
3950 return WINED3D_OK;
3952 #undef copy_and_next
3954 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3956 WineDirect3DVertexStridedData strided;
3957 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3958 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3960 if(pVertexDecl) {
3961 ERR("Output vertex declaration not implemented yet\n");
3964 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3965 * and this call is quite performance critical, so don't call needlessly
3967 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3968 ENTER_GL();
3969 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3970 LEAVE_GL();
3973 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3974 * control the streamIsUP flag, thus restore it afterwards.
3976 This->stateBlock->streamIsUP = FALSE;
3977 memset(&strided, 0, sizeof(strided));
3978 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3979 This->stateBlock->streamIsUP = streamWasUP;
3981 if(vbo || SrcStartIndex) {
3982 unsigned int i;
3983 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3984 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3986 * Also get the start index in, but only loop over all elements if there's something to add at all.
3988 #define FIXSRC(type) \
3989 if(strided.u.s.type.VBO) { \
3990 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3991 strided.u.s.type.VBO = 0; \
3992 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3993 ENTER_GL(); \
3994 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3995 vb->vbo = 0; \
3996 LEAVE_GL(); \
3998 if(strided.u.s.type.lpData) { \
3999 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4001 FIXSRC(position);
4002 FIXSRC(blendWeights);
4003 FIXSRC(blendMatrixIndices);
4004 FIXSRC(normal);
4005 FIXSRC(pSize);
4006 FIXSRC(diffuse);
4007 FIXSRC(specular);
4008 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4009 FIXSRC(texCoords[i]);
4011 FIXSRC(position2);
4012 FIXSRC(normal2);
4013 FIXSRC(tangent);
4014 FIXSRC(binormal);
4015 FIXSRC(tessFactor);
4016 FIXSRC(fog);
4017 FIXSRC(depth);
4018 FIXSRC(sample);
4019 #undef FIXSRC
4022 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4025 /*****
4026 * Get / Set Texture Stage States
4027 * TODO: Verify against dx9 definitions
4028 *****/
4029 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4031 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4033 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4035 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4037 if (Stage >= MAX_TEXTURES) {
4038 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4039 return WINED3D_OK;
4042 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4043 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4044 This->updateStateBlock->textureState[Stage][Type] = Value;
4046 if (This->isRecordingState) {
4047 TRACE("Recording... not performing anything\n");
4048 return WINED3D_OK;
4051 /* Checked after the assignments to allow proper stateblock recording */
4052 if(oldValue == Value) {
4053 TRACE("App is setting the old value over, nothing to do\n");
4054 return WINED3D_OK;
4057 if(Stage > This->stateBlock->lowest_disabled_stage &&
4058 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4059 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4060 * Changes in other states are important on disabled stages too
4062 return WINED3D_OK;
4065 if(Type == WINED3DTSS_COLOROP) {
4066 int i;
4068 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4069 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4070 * they have to be disabled
4072 * The current stage is dirtified below.
4074 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4075 TRACE("Additionally dirtifying stage %d\n", i);
4076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4078 This->stateBlock->lowest_disabled_stage = Stage;
4079 TRACE("New lowest disabled: %d\n", Stage);
4080 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4081 /* Previously disabled stage enabled. Stages above it may need enabling
4082 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4083 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4085 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4088 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4089 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4090 break;
4092 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4095 This->stateBlock->lowest_disabled_stage = i;
4096 TRACE("New lowest disabled: %d\n", i);
4098 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4099 /* TODO: Built a stage -> texture unit mapping for register combiners */
4103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4105 return WINED3D_OK;
4108 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4110 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4111 *pValue = This->updateStateBlock->textureState[Stage][Type];
4112 return WINED3D_OK;
4115 /*****
4116 * Get / Set Texture
4117 *****/
4118 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 IWineD3DBaseTexture *oldTexture;
4122 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4124 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4125 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4128 oldTexture = This->updateStateBlock->textures[Stage];
4130 if(pTexture != NULL) {
4131 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4133 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4134 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4135 return WINED3DERR_INVALIDCALL;
4137 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4140 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4141 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4143 This->updateStateBlock->set.textures[Stage] = TRUE;
4144 This->updateStateBlock->changed.textures[Stage] = TRUE;
4145 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4146 This->updateStateBlock->textures[Stage] = pTexture;
4148 /* Handle recording of state blocks */
4149 if (This->isRecordingState) {
4150 TRACE("Recording... not performing anything\n");
4151 return WINED3D_OK;
4154 if(oldTexture == pTexture) {
4155 TRACE("App is setting the same texture again, nothing to do\n");
4156 return WINED3D_OK;
4159 /** NOTE: MSDN says that setTexture increases the reference count,
4160 * and the the application must set the texture back to null (or have a leaky application),
4161 * This means we should pass the refcount up to the parent
4162 *******************************/
4163 if (NULL != This->updateStateBlock->textures[Stage]) {
4164 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4165 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4167 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4168 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4169 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4170 * so the COLOROP and ALPHAOP have to be dirtified.
4172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4175 if(bindCount == 1) {
4176 new->baseTexture.sampler = Stage;
4178 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4182 if (NULL != oldTexture) {
4183 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4184 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4186 IWineD3DBaseTexture_Release(oldTexture);
4187 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4192 if(bindCount && old->baseTexture.sampler == Stage) {
4193 int i;
4194 /* Have to do a search for the other sampler(s) where the texture is bound to
4195 * Shouldn't happen as long as apps bind a texture only to one stage
4197 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4198 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4199 if(This->updateStateBlock->textures[i] == oldTexture) {
4200 old->baseTexture.sampler = i;
4201 break;
4207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4209 return WINED3D_OK;
4212 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4215 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4217 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4218 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4221 *ppTexture=This->stateBlock->textures[Stage];
4222 if (*ppTexture)
4223 IWineD3DBaseTexture_AddRef(*ppTexture);
4225 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4227 return WINED3D_OK;
4230 /*****
4231 * Get Back Buffer
4232 *****/
4233 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4234 IWineD3DSurface **ppBackBuffer) {
4235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4236 IWineD3DSwapChain *swapChain;
4237 HRESULT hr;
4239 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4241 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4242 if (hr == WINED3D_OK) {
4243 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4244 IWineD3DSwapChain_Release(swapChain);
4245 } else {
4246 *ppBackBuffer = NULL;
4248 return hr;
4251 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4253 WARN("(%p) : stub, calling idirect3d for now\n", This);
4254 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4257 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4259 IWineD3DSwapChain *swapChain;
4260 HRESULT hr;
4262 if(iSwapChain > 0) {
4263 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4264 if (hr == WINED3D_OK) {
4265 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4266 IWineD3DSwapChain_Release(swapChain);
4267 } else {
4268 FIXME("(%p) Error getting display mode\n", This);
4270 } else {
4271 /* Don't read the real display mode,
4272 but return the stored mode instead. X11 can't change the color
4273 depth, and some apps are pretty angry if they SetDisplayMode from
4274 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4276 Also don't relay to the swapchain because with ddraw it's possible
4277 that there isn't a swapchain at all */
4278 pMode->Width = This->ddraw_width;
4279 pMode->Height = This->ddraw_height;
4280 pMode->Format = This->ddraw_format;
4281 pMode->RefreshRate = 0;
4282 hr = WINED3D_OK;
4285 return hr;
4288 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4290 TRACE("(%p)->(%p)\n", This, hWnd);
4292 if(This->ddraw_fullscreen) {
4293 if(This->ddraw_window && This->ddraw_window != hWnd) {
4294 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4296 if(hWnd && This->ddraw_window != hWnd) {
4297 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4301 This->ddraw_window = hWnd;
4302 return WINED3D_OK;
4305 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4307 TRACE("(%p)->(%p)\n", This, hWnd);
4309 *hWnd = This->ddraw_window;
4310 return WINED3D_OK;
4313 /*****
4314 * Stateblock related functions
4315 *****/
4317 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 IWineD3DStateBlockImpl *object;
4320 HRESULT temp_result;
4321 int i;
4323 TRACE("(%p)\n", This);
4325 if (This->isRecordingState) {
4326 return WINED3DERR_INVALIDCALL;
4329 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4330 if (NULL == object ) {
4331 FIXME("(%p)Error allocating memory for stateblock\n", This);
4332 return E_OUTOFMEMORY;
4334 TRACE("(%p) created object %p\n", This, object);
4335 object->wineD3DDevice= This;
4336 /** FIXME: object->parent = parent; **/
4337 object->parent = NULL;
4338 object->blockType = WINED3DSBT_ALL;
4339 object->ref = 1;
4340 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4342 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4343 list_init(&object->lightMap[i]);
4346 temp_result = allocate_shader_constants(object);
4347 if (WINED3D_OK != temp_result)
4348 return temp_result;
4350 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4351 This->updateStateBlock = object;
4352 This->isRecordingState = TRUE;
4354 TRACE("(%p) recording stateblock %p\n",This , object);
4355 return WINED3D_OK;
4358 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4361 if (!This->isRecordingState) {
4362 FIXME("(%p) not recording! returning error\n", This);
4363 *ppStateBlock = NULL;
4364 return WINED3DERR_INVALIDCALL;
4367 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4368 This->isRecordingState = FALSE;
4369 This->updateStateBlock = This->stateBlock;
4370 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4371 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4372 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4373 return WINED3D_OK;
4376 /*****
4377 * Scene related functions
4378 *****/
4379 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4380 /* At the moment we have no need for any functionality at the beginning
4381 of a scene */
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 TRACE("(%p)\n", This);
4385 if(This->inScene) {
4386 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4387 return WINED3DERR_INVALIDCALL;
4389 This->inScene = TRUE;
4390 return WINED3D_OK;
4393 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4395 TRACE("(%p)\n", This);
4397 if(!This->inScene) {
4398 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4399 return WINED3DERR_INVALIDCALL;
4402 ENTER_GL();
4403 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4404 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4406 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4407 glFlush();
4408 checkGLcall("glFlush");
4409 LEAVE_GL();
4411 This->inScene = FALSE;
4412 return WINED3D_OK;
4415 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4416 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4417 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4419 IWineD3DSwapChain *swapChain = NULL;
4420 int i;
4421 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4423 TRACE("(%p) Presenting the frame\n", This);
4425 for(i = 0 ; i < swapchains ; i ++) {
4427 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4428 TRACE("presentinng chain %d, %p\n", i, swapChain);
4429 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4430 IWineD3DSwapChain_Release(swapChain);
4433 return WINED3D_OK;
4436 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4437 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4439 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4441 GLbitfield glMask = 0;
4442 unsigned int i;
4443 CONST WINED3DRECT* curRect;
4445 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4446 Count, pRects, Flags, Color, Z, Stencil);
4448 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4449 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4450 /* TODO: What about depth stencil buffers without stencil bits? */
4451 return WINED3DERR_INVALIDCALL;
4454 ENTER_GL();
4455 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4456 * and not the last active one.
4459 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4460 apply_fbo_state(iface);
4463 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4465 if (Count > 0 && pRects) {
4466 curRect = pRects;
4467 } else {
4468 curRect = NULL;
4471 /* Only set the values up once, as they are not changing */
4472 if (Flags & WINED3DCLEAR_STENCIL) {
4473 glClearStencil(Stencil);
4474 checkGLcall("glClearStencil");
4475 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4476 glStencilMask(0xFFFFFFFF);
4479 if (Flags & WINED3DCLEAR_ZBUFFER) {
4480 glDepthMask(GL_TRUE);
4481 glClearDepth(Z);
4482 checkGLcall("glClearDepth");
4483 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4487 if (Flags & WINED3DCLEAR_TARGET) {
4488 TRACE("Clearing screen with glClear to color %x\n", Color);
4489 glClearColor(D3DCOLOR_R(Color),
4490 D3DCOLOR_G(Color),
4491 D3DCOLOR_B(Color),
4492 D3DCOLOR_A(Color));
4493 checkGLcall("glClearColor");
4495 /* Clear ALL colors! */
4496 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4497 glMask = glMask | GL_COLOR_BUFFER_BIT;
4500 if (!curRect) {
4501 /* In drawable flag is set below */
4503 if (This->render_offscreen) {
4504 glScissor(This->stateBlock->viewport.X,
4505 This->stateBlock->viewport.Y,
4506 This->stateBlock->viewport.Width,
4507 This->stateBlock->viewport.Height);
4508 } else {
4509 glScissor(This->stateBlock->viewport.X,
4510 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4511 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4512 This->stateBlock->viewport.Width,
4513 This->stateBlock->viewport.Height);
4515 checkGLcall("glScissor");
4516 glClear(glMask);
4517 checkGLcall("glClear");
4518 } else {
4519 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4520 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4522 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4523 curRect[0].x2 < target->currentDesc.Width ||
4524 curRect[0].y2 < target->currentDesc.Height) {
4525 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4526 blt_to_drawable(This, target);
4530 /* Now process each rect in turn */
4531 for (i = 0; i < Count; i++) {
4532 /* Note gl uses lower left, width/height */
4533 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4534 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4535 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4536 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4538 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4539 * The rectangle is not cleared, no error is returned, but further rectanlges are
4540 * still cleared if they are valid
4542 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4543 TRACE("Rectangle with negative dimensions, ignoring\n");
4544 continue;
4547 if(This->render_offscreen) {
4548 glScissor(curRect[i].x1, curRect[i].y1,
4549 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4550 } else {
4551 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4552 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4554 checkGLcall("glScissor");
4556 glClear(glMask);
4557 checkGLcall("glClear");
4561 /* Restore the old values (why..?) */
4562 if (Flags & WINED3DCLEAR_STENCIL) {
4563 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4565 if (Flags & WINED3DCLEAR_TARGET) {
4566 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4567 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4568 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4569 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4570 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4573 LEAVE_GL();
4575 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4576 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4578 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4579 target->Flags |= SFLAG_INTEXTURE;
4580 target->Flags &= ~SFLAG_INSYSMEM;
4581 } else {
4582 target->Flags |= SFLAG_INDRAWABLE;
4583 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4585 return WINED3D_OK;
4588 /*****
4589 * Drawing functions
4590 *****/
4591 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4592 UINT PrimitiveCount) {
4594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4596 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4597 debug_d3dprimitivetype(PrimitiveType),
4598 StartVertex, PrimitiveCount);
4600 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4601 if(This->stateBlock->streamIsUP) {
4602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4603 This->stateBlock->streamIsUP = FALSE;
4606 if(This->stateBlock->loadBaseVertexIndex != 0) {
4607 This->stateBlock->loadBaseVertexIndex = 0;
4608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4610 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4611 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4612 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4613 return WINED3D_OK;
4616 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4617 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4618 WINED3DPRIMITIVETYPE PrimitiveType,
4619 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4622 UINT idxStride = 2;
4623 IWineD3DIndexBuffer *pIB;
4624 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4625 GLuint vbo;
4627 pIB = This->stateBlock->pIndexData;
4628 if (!pIB) {
4629 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4630 * without an index buffer set. (The first time at least...)
4631 * D3D8 simply dies, but I doubt it can do much harm to return
4632 * D3DERR_INVALIDCALL there as well. */
4633 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4634 return WINED3DERR_INVALIDCALL;
4637 if(This->stateBlock->streamIsUP) {
4638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4639 This->stateBlock->streamIsUP = FALSE;
4641 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4643 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4644 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4645 minIndex, NumVertices, startIndex, primCount);
4647 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4648 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4649 idxStride = 2;
4650 } else {
4651 idxStride = 4;
4654 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4655 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4656 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4659 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4660 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4662 return WINED3D_OK;
4665 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4666 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4667 UINT VertexStreamZeroStride) {
4668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4670 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4671 debug_d3dprimitivetype(PrimitiveType),
4672 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4674 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4675 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4676 This->stateBlock->streamOffset[0] = 0;
4677 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4678 This->stateBlock->streamIsUP = TRUE;
4679 This->stateBlock->loadBaseVertexIndex = 0;
4681 /* TODO: Only mark dirty if drawing from a different UP address */
4682 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4684 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4685 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4687 /* MSDN specifies stream zero settings must be set to NULL */
4688 This->stateBlock->streamStride[0] = 0;
4689 This->stateBlock->streamSource[0] = NULL;
4691 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4692 * the new stream sources or use UP drawing again
4694 return WINED3D_OK;
4697 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4698 UINT MinVertexIndex, UINT NumVertices,
4699 UINT PrimitiveCount, CONST void* pIndexData,
4700 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4701 UINT VertexStreamZeroStride) {
4702 int idxStride;
4703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4705 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4706 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4707 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4708 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4710 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4711 idxStride = 2;
4712 } else {
4713 idxStride = 4;
4716 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4717 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4718 This->stateBlock->streamIsUP = TRUE;
4719 This->stateBlock->streamOffset[0] = 0;
4720 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4722 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4723 This->stateBlock->baseVertexIndex = 0;
4724 This->stateBlock->loadBaseVertexIndex = 0;
4725 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4729 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4731 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4732 This->stateBlock->streamSource[0] = NULL;
4733 This->stateBlock->streamStride[0] = 0;
4734 This->stateBlock->pIndexData = NULL;
4735 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4736 * SetStreamSource to specify a vertex buffer
4739 return WINED3D_OK;
4742 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4745 /* Mark the state dirty until we have nicer tracking
4746 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4747 * that value.
4749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4751 This->stateBlock->baseVertexIndex = 0;
4752 This->up_strided = DrawPrimStrideData;
4753 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4754 This->up_strided = NULL;
4755 return WINED3D_OK;
4757 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4758 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 HRESULT hr = WINED3D_OK;
4761 WINED3DRESOURCETYPE sourceType;
4762 WINED3DRESOURCETYPE destinationType;
4763 int i ,levels;
4765 /* TODO: think about moving the code into IWineD3DBaseTexture */
4767 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4769 /* verify that the source and destination textures aren't NULL */
4770 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4771 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4772 This, pSourceTexture, pDestinationTexture);
4773 hr = WINED3DERR_INVALIDCALL;
4776 if (pSourceTexture == pDestinationTexture) {
4777 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4778 This, pSourceTexture, pDestinationTexture);
4779 hr = WINED3DERR_INVALIDCALL;
4781 /* Verify that the source and destination textures are the same type */
4782 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4783 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4785 if (sourceType != destinationType) {
4786 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4787 This);
4788 hr = WINED3DERR_INVALIDCALL;
4791 /* check that both textures have the identical numbers of levels */
4792 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4793 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4794 hr = WINED3DERR_INVALIDCALL;
4797 if (WINED3D_OK == hr) {
4799 /* Make sure that the destination texture is loaded */
4800 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4802 /* Update every surface level of the texture */
4803 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4805 switch (sourceType) {
4806 case WINED3DRTYPE_TEXTURE:
4808 IWineD3DSurface *srcSurface;
4809 IWineD3DSurface *destSurface;
4811 for (i = 0 ; i < levels ; ++i) {
4812 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4813 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4814 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4815 IWineD3DSurface_Release(srcSurface);
4816 IWineD3DSurface_Release(destSurface);
4817 if (WINED3D_OK != hr) {
4818 WARN("(%p) : Call to update surface failed\n", This);
4819 return hr;
4823 break;
4824 case WINED3DRTYPE_CUBETEXTURE:
4826 IWineD3DSurface *srcSurface;
4827 IWineD3DSurface *destSurface;
4828 WINED3DCUBEMAP_FACES faceType;
4830 for (i = 0 ; i < levels ; ++i) {
4831 /* Update each cube face */
4832 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4833 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4834 if (WINED3D_OK != hr) {
4835 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4836 } else {
4837 TRACE("Got srcSurface %p\n", srcSurface);
4839 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4840 if (WINED3D_OK != hr) {
4841 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4842 } else {
4843 TRACE("Got desrSurface %p\n", destSurface);
4845 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4846 IWineD3DSurface_Release(srcSurface);
4847 IWineD3DSurface_Release(destSurface);
4848 if (WINED3D_OK != hr) {
4849 WARN("(%p) : Call to update surface failed\n", This);
4850 return hr;
4855 break;
4856 #if 0 /* TODO: Add support for volume textures */
4857 case WINED3DRTYPE_VOLUMETEXTURE:
4859 IWineD3DVolume srcVolume = NULL;
4860 IWineD3DSurface destVolume = NULL;
4862 for (i = 0 ; i < levels ; ++i) {
4863 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4864 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4865 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4866 IWineD3DVolume_Release(srcSurface);
4867 IWineD3DVolume_Release(destSurface);
4868 if (WINED3D_OK != hr) {
4869 WARN("(%p) : Call to update volume failed\n", This);
4870 return hr;
4874 break;
4875 #endif
4876 default:
4877 FIXME("(%p) : Unsupported source and destination type\n", This);
4878 hr = WINED3DERR_INVALIDCALL;
4882 return hr;
4885 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4886 IWineD3DSwapChain *swapChain;
4887 HRESULT hr;
4888 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4889 if(hr == WINED3D_OK) {
4890 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4891 IWineD3DSwapChain_Release(swapChain);
4893 return hr;
4896 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4898 /* return a sensible default */
4899 *pNumPasses = 1;
4900 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4901 FIXME("(%p) : stub\n", This);
4902 return WINED3D_OK;
4905 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4907 int j;
4908 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4909 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4910 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4911 return WINED3DERR_INVALIDCALL;
4913 for (j = 0; j < 256; ++j) {
4914 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4915 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4916 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4917 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4919 TRACE("(%p) : returning\n", This);
4920 return WINED3D_OK;
4923 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4925 int j;
4926 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4927 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4928 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4929 return WINED3DERR_INVALIDCALL;
4931 for (j = 0; j < 256; ++j) {
4932 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4933 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4934 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4935 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4937 TRACE("(%p) : returning\n", This);
4938 return WINED3D_OK;
4941 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4943 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4944 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4945 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4946 return WINED3DERR_INVALIDCALL;
4948 /*TODO: stateblocks */
4949 This->currentPalette = PaletteNumber;
4950 TRACE("(%p) : returning\n", This);
4951 return WINED3D_OK;
4954 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4956 if (PaletteNumber == NULL) {
4957 WARN("(%p) : returning Invalid Call\n", This);
4958 return WINED3DERR_INVALIDCALL;
4960 /*TODO: stateblocks */
4961 *PaletteNumber = This->currentPalette;
4962 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4963 return WINED3D_OK;
4966 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4968 static BOOL showFixmes = TRUE;
4969 if (showFixmes) {
4970 FIXME("(%p) : stub\n", This);
4971 showFixmes = FALSE;
4974 This->softwareVertexProcessing = bSoftware;
4975 return WINED3D_OK;
4979 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4981 static BOOL showFixmes = TRUE;
4982 if (showFixmes) {
4983 FIXME("(%p) : stub\n", This);
4984 showFixmes = FALSE;
4986 return This->softwareVertexProcessing;
4990 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4992 IWineD3DSwapChain *swapChain;
4993 HRESULT hr;
4995 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4997 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4998 if(hr == WINED3D_OK){
4999 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5000 IWineD3DSwapChain_Release(swapChain);
5001 }else{
5002 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5004 return hr;
5008 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5010 static BOOL showfixmes = TRUE;
5011 if(nSegments != 0.0f) {
5012 if( showfixmes) {
5013 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5014 showfixmes = FALSE;
5017 return WINED3D_OK;
5020 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5022 static BOOL showfixmes = TRUE;
5023 if( showfixmes) {
5024 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5025 showfixmes = FALSE;
5027 return 0.0f;
5030 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5032 /** TODO: remove casts to IWineD3DSurfaceImpl
5033 * NOTE: move code to surface to accomplish this
5034 ****************************************/
5035 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5036 int srcWidth, srcHeight;
5037 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5038 WINED3DFORMAT destFormat, srcFormat;
5039 UINT destSize;
5040 int srcLeft, destLeft, destTop;
5041 WINED3DPOOL srcPool, destPool;
5042 int offset = 0;
5043 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5044 glDescriptor *glDescription = NULL;
5046 WINED3DSURFACE_DESC winedesc;
5048 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5049 memset(&winedesc, 0, sizeof(winedesc));
5050 winedesc.Width = &srcSurfaceWidth;
5051 winedesc.Height = &srcSurfaceHeight;
5052 winedesc.Pool = &srcPool;
5053 winedesc.Format = &srcFormat;
5055 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5057 winedesc.Width = &destSurfaceWidth;
5058 winedesc.Height = &destSurfaceHeight;
5059 winedesc.Pool = &destPool;
5060 winedesc.Format = &destFormat;
5061 winedesc.Size = &destSize;
5063 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5065 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5066 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5067 return WINED3DERR_INVALIDCALL;
5070 if (destFormat == WINED3DFMT_UNKNOWN) {
5071 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5072 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5074 /* Get the update surface description */
5075 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5078 ENTER_GL();
5080 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5082 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5083 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5084 checkGLcall("glActiveTextureARB");
5087 /* Make sure the surface is loaded and up to date */
5088 IWineD3DSurface_PreLoad(pDestinationSurface);
5090 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5092 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5093 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5094 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5095 srcLeft = pSourceRect ? pSourceRect->left : 0;
5096 destLeft = pDestPoint ? pDestPoint->x : 0;
5097 destTop = pDestPoint ? pDestPoint->y : 0;
5100 /* This function doesn't support compressed textures
5101 the pitch is just bytesPerPixel * width */
5102 if(srcWidth != srcSurfaceWidth || srcLeft ){
5103 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5104 offset += srcLeft * pSrcSurface->bytesPerPixel;
5105 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5107 /* TODO DXT formats */
5109 if(pSourceRect != NULL && pSourceRect->top != 0){
5110 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5112 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5113 ,This
5114 ,glDescription->level
5115 ,destLeft
5116 ,destTop
5117 ,srcWidth
5118 ,srcHeight
5119 ,glDescription->glFormat
5120 ,glDescription->glType
5121 ,IWineD3DSurface_GetData(pSourceSurface)
5124 /* Sanity check */
5125 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5127 /* need to lock the surface to get the data */
5128 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5131 /* TODO: Cube and volume support */
5132 if(rowoffset != 0){
5133 /* not a whole row so we have to do it a line at a time */
5134 int j;
5136 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5137 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5139 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5141 glTexSubImage2D(glDescription->target
5142 ,glDescription->level
5143 ,destLeft
5145 ,srcWidth
5147 ,glDescription->glFormat
5148 ,glDescription->glType
5149 ,data /* could be quicker using */
5151 data += rowoffset;
5154 } else { /* Full width, so just write out the whole texture */
5156 if (WINED3DFMT_DXT1 == destFormat ||
5157 WINED3DFMT_DXT2 == destFormat ||
5158 WINED3DFMT_DXT3 == destFormat ||
5159 WINED3DFMT_DXT4 == destFormat ||
5160 WINED3DFMT_DXT5 == destFormat) {
5161 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5162 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5163 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5164 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5165 } if (destFormat != srcFormat) {
5166 FIXME("Updating mixed format compressed texture is not curretly support\n");
5167 } else {
5168 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5169 glDescription->level,
5170 glDescription->glFormatInternal,
5171 srcWidth,
5172 srcHeight,
5174 destSize,
5175 IWineD3DSurface_GetData(pSourceSurface));
5177 } else {
5178 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5182 } else {
5183 glTexSubImage2D(glDescription->target
5184 ,glDescription->level
5185 ,destLeft
5186 ,destTop
5187 ,srcWidth
5188 ,srcHeight
5189 ,glDescription->glFormat
5190 ,glDescription->glType
5191 ,IWineD3DSurface_GetData(pSourceSurface)
5195 checkGLcall("glTexSubImage2D");
5197 LEAVE_GL();
5199 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5200 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5203 return WINED3D_OK;
5206 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5208 struct WineD3DRectPatch *patch;
5209 unsigned int i;
5210 struct list *e;
5211 BOOL found;
5212 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5214 if(!(Handle || pRectPatchInfo)) {
5215 /* TODO: Write a test for the return value, thus the FIXME */
5216 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5217 return WINED3DERR_INVALIDCALL;
5220 if(Handle) {
5221 i = PATCHMAP_HASHFUNC(Handle);
5222 found = FALSE;
5223 LIST_FOR_EACH(e, &This->patches[i]) {
5224 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5225 if(patch->Handle == Handle) {
5226 found = TRUE;
5227 break;
5231 if(!found) {
5232 TRACE("Patch does not exist. Creating a new one\n");
5233 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5234 patch->Handle = Handle;
5235 list_add_head(&This->patches[i], &patch->entry);
5236 } else {
5237 TRACE("Found existing patch %p\n", patch);
5239 } else {
5240 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5241 * attributes we have to tesselate, read back, and draw. This needs a patch
5242 * management structure instance. Create one.
5244 * A possible improvement is to check if a vertex shader is used, and if not directly
5245 * draw the patch.
5247 FIXME("Drawing an uncached patch. This is slow\n");
5248 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5251 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5252 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5253 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5254 HRESULT hr;
5255 TRACE("Tesselation density or patch info changed, retesselating\n");
5257 if(pRectPatchInfo) {
5258 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5260 patch->numSegs[0] = pNumSegs[0];
5261 patch->numSegs[1] = pNumSegs[1];
5262 patch->numSegs[2] = pNumSegs[2];
5263 patch->numSegs[3] = pNumSegs[3];
5265 hr = tesselate_rectpatch(This, patch);
5266 if(FAILED(hr)) {
5267 WARN("Patch tesselation failed\n");
5269 /* Do not release the handle to store the params of the patch */
5270 if(!Handle) {
5271 HeapFree(GetProcessHeap(), 0, patch);
5273 return hr;
5277 This->currentPatch = patch;
5278 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5279 This->currentPatch = NULL;
5281 /* Destroy uncached patches */
5282 if(!Handle) {
5283 HeapFree(GetProcessHeap(), 0, patch->mem);
5284 HeapFree(GetProcessHeap(), 0, patch);
5286 return WINED3D_OK;
5289 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5290 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5292 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5293 FIXME("(%p) : Stub\n", This);
5294 return WINED3D_OK;
5297 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5299 int i;
5300 struct WineD3DRectPatch *patch;
5301 struct list *e;
5302 TRACE("(%p) Handle(%d)\n", This, Handle);
5304 i = PATCHMAP_HASHFUNC(Handle);
5305 LIST_FOR_EACH(e, &This->patches[i]) {
5306 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5307 if(patch->Handle == Handle) {
5308 TRACE("Deleting patch %p\n", patch);
5309 list_remove(&patch->entry);
5310 HeapFree(GetProcessHeap(), 0, patch->mem);
5311 HeapFree(GetProcessHeap(), 0, patch);
5312 return WINED3D_OK;
5316 /* TODO: Write a test for the return value */
5317 FIXME("Attempt to destroy nonexistant patch\n");
5318 return WINED3DERR_INVALIDCALL;
5321 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5322 HRESULT hr;
5323 IWineD3DSwapChain *swapchain;
5325 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5326 if (SUCCEEDED(hr)) {
5327 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5328 return swapchain;
5331 return NULL;
5334 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5337 if (!*fbo) {
5338 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5339 checkGLcall("glGenFramebuffersEXT()");
5341 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5342 checkGLcall("glBindFramebuffer()");
5345 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5346 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5347 IWineD3DBaseTextureImpl *texture_impl;
5348 GLenum texttarget, target;
5349 GLint old_binding;
5351 texttarget = surface_impl->glDescription.target;
5352 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5353 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5355 IWineD3DSurface_PreLoad(surface);
5357 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5358 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5359 glBindTexture(target, old_binding);
5361 /* Update base texture states array */
5362 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5363 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5364 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5365 if (texture_impl->baseTexture.bindCount) {
5366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5369 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5372 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5374 checkGLcall("attach_surface_fbo");
5377 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5379 IWineD3DSwapChain *swapchain;
5381 swapchain = get_swapchain(surface);
5382 if (swapchain) {
5383 GLenum buffer;
5385 TRACE("Surface %p is onscreen\n", surface);
5387 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5388 buffer = surface_get_gl_buffer(surface, swapchain);
5389 glDrawBuffer(buffer);
5390 checkGLcall("glDrawBuffer()");
5391 } else {
5392 TRACE("Surface %p is offscreen\n", surface);
5393 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5394 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5397 if (rect) {
5398 glEnable(GL_SCISSOR_TEST);
5399 if(!swapchain) {
5400 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5401 } else {
5402 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5403 rect->x2 - rect->x1, rect->y2 - rect->y1);
5405 checkGLcall("glScissor");
5406 } else {
5407 glDisable(GL_SCISSOR_TEST);
5409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5411 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5414 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5415 glClear(GL_COLOR_BUFFER_BIT);
5416 checkGLcall("glClear");
5418 if (This->render_offscreen) {
5419 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5420 } else {
5421 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5422 checkGLcall("glBindFramebuffer()");
5425 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5426 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5427 glDrawBuffer(GL_BACK);
5428 checkGLcall("glDrawBuffer()");
5432 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5434 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5435 WINEDDBLTFX BltFx;
5436 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5438 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5439 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5440 return WINED3DERR_INVALIDCALL;
5443 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5444 color_fill_fbo(iface, pSurface, pRect, color);
5445 return WINED3D_OK;
5446 } else {
5447 /* Just forward this to the DirectDraw blitting engine */
5448 memset(&BltFx, 0, sizeof(BltFx));
5449 BltFx.dwSize = sizeof(BltFx);
5450 BltFx.u5.dwFillColor = color;
5451 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5455 /* rendertarget and deptth stencil functions */
5456 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5459 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5460 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5461 return WINED3DERR_INVALIDCALL;
5464 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5465 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5466 /* Note inc ref on returned surface */
5467 if(*ppRenderTarget != NULL)
5468 IWineD3DSurface_AddRef(*ppRenderTarget);
5469 return WINED3D_OK;
5472 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5475 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5476 IWineD3DSwapChainImpl *Swapchain;
5477 HRESULT hr;
5479 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5481 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5482 if(hr != WINED3D_OK) {
5483 ERR("Can't get the swapchain\n");
5484 return hr;
5487 /* Make sure to release the swapchain */
5488 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5490 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5491 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5492 return WINED3DERR_INVALIDCALL;
5494 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5495 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5496 return WINED3DERR_INVALIDCALL;
5499 if(Swapchain->frontBuffer != Front) {
5500 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5502 if(Swapchain->frontBuffer)
5503 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5504 Swapchain->frontBuffer = Front;
5506 if(Swapchain->frontBuffer) {
5507 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5511 if(Back && !Swapchain->backBuffer) {
5512 /* We need memory for the back buffer array - only one back buffer this way */
5513 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5514 if(!Swapchain->backBuffer) {
5515 ERR("Out of memory\n");
5516 return E_OUTOFMEMORY;
5520 if(Swapchain->backBuffer[0] != Back) {
5521 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5523 /* What to do about the context here in the case of multithreading? Not sure.
5524 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5526 ENTER_GL();
5527 if(!Swapchain->backBuffer[0]) {
5528 /* GL was told to draw to the front buffer at creation,
5529 * undo that
5531 glDrawBuffer(GL_BACK);
5532 checkGLcall("glDrawBuffer(GL_BACK)");
5533 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5534 Swapchain->presentParms.BackBufferCount = 1;
5535 } else if (!Back) {
5536 /* That makes problems - disable for now */
5537 /* glDrawBuffer(GL_FRONT); */
5538 checkGLcall("glDrawBuffer(GL_FRONT)");
5539 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5540 Swapchain->presentParms.BackBufferCount = 0;
5542 LEAVE_GL();
5544 if(Swapchain->backBuffer[0])
5545 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5546 Swapchain->backBuffer[0] = Back;
5548 if(Swapchain->backBuffer[0]) {
5549 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5550 } else {
5551 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5556 return WINED3D_OK;
5559 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5561 *ppZStencilSurface = This->depthStencilBuffer;
5562 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5564 if(*ppZStencilSurface != NULL) {
5565 /* Note inc ref on returned surface */
5566 IWineD3DSurface_AddRef(*ppZStencilSurface);
5568 return WINED3D_OK;
5571 /* TODO: Handle stencil attachments */
5572 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5574 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5576 TRACE("Set depth stencil to %p\n", depth_stencil);
5578 if (depth_stencil_impl) {
5579 if (depth_stencil_impl->current_renderbuffer) {
5580 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5581 checkGLcall("glFramebufferRenderbufferEXT()");
5582 } else {
5583 IWineD3DBaseTextureImpl *texture_impl;
5584 GLenum texttarget, target;
5585 GLint old_binding = 0;
5587 texttarget = depth_stencil_impl->glDescription.target;
5588 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5589 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5591 IWineD3DSurface_PreLoad(depth_stencil);
5593 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5594 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5595 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5596 glBindTexture(target, old_binding);
5598 /* Update base texture states array */
5599 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5600 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5601 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5602 if (texture_impl->baseTexture.bindCount) {
5603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5606 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5609 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5610 checkGLcall("glFramebufferTexture2DEXT()");
5612 } else {
5613 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5614 checkGLcall("glFramebufferTexture2DEXT()");
5618 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5620 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5622 TRACE("Set render target %u to %p\n", idx, render_target);
5624 if (rtimpl) {
5625 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5626 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5627 } else {
5628 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5629 checkGLcall("glFramebufferTexture2DEXT()");
5631 This->draw_buffers[idx] = GL_NONE;
5635 static void check_fbo_status(IWineD3DDevice *iface) {
5636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5637 GLenum status;
5639 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5640 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5641 TRACE("FBO complete\n");
5642 } else {
5643 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5645 /* Dump the FBO attachments */
5646 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5647 IWineD3DSurfaceImpl *attachment;
5648 int i;
5650 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5651 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5652 if (attachment) {
5653 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5654 attachment->pow2Width, attachment->pow2Height);
5657 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5658 if (attachment) {
5659 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5660 attachment->pow2Width, attachment->pow2Height);
5666 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5668 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5669 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5671 if (!ds_impl) return FALSE;
5673 if (ds_impl->current_renderbuffer) {
5674 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5675 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5678 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5679 rt_impl->pow2Height != ds_impl->pow2Height);
5682 void apply_fbo_state(IWineD3DDevice *iface) {
5683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5684 unsigned int i;
5686 if (This->render_offscreen) {
5687 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5689 /* Apply render targets */
5690 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5691 IWineD3DSurface *render_target = This->render_targets[i];
5692 if (This->fbo_color_attachments[i] != render_target) {
5693 set_render_target_fbo(iface, i, render_target);
5694 This->fbo_color_attachments[i] = render_target;
5698 /* Apply depth targets */
5699 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5700 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5701 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5703 if (This->stencilBufferTarget) {
5704 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5706 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5707 This->fbo_depth_attachment = This->stencilBufferTarget;
5710 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5711 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5712 checkGLcall("glDrawBuffers()");
5713 } else {
5714 glDrawBuffer(This->draw_buffers[0]);
5715 checkGLcall("glDrawBuffer()");
5717 } else {
5718 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5721 check_fbo_status(iface);
5724 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5725 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5727 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5728 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5729 GLenum gl_filter;
5731 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5732 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5733 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5734 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5736 switch (filter) {
5737 case WINED3DTEXF_LINEAR:
5738 gl_filter = GL_LINEAR;
5739 break;
5741 default:
5742 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5743 case WINED3DTEXF_NONE:
5744 case WINED3DTEXF_POINT:
5745 gl_filter = GL_NEAREST;
5746 break;
5749 /* Attach src surface to src fbo */
5750 src_swapchain = get_swapchain(src_surface);
5751 ENTER_GL();
5752 if (src_swapchain) {
5753 GLenum buffer;
5755 TRACE("Source surface %p is onscreen\n", src_surface);
5756 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5758 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5759 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5760 glReadBuffer(buffer);
5761 checkGLcall("glReadBuffer()");
5763 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5764 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5765 } else {
5766 TRACE("Source surface %p is offscreen\n", src_surface);
5767 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5768 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5769 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5770 checkGLcall("glReadBuffer()");
5773 /* Attach dst surface to dst fbo */
5774 dst_swapchain = get_swapchain(dst_surface);
5775 if (dst_swapchain) {
5776 GLenum buffer;
5778 TRACE("Destination surface %p is onscreen\n", dst_surface);
5779 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5781 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5782 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5783 glDrawBuffer(buffer);
5784 checkGLcall("glDrawBuffer()");
5786 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5787 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5788 } else {
5789 TRACE("Destination surface %p is offscreen\n", dst_surface);
5791 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5792 if(!src_swapchain) {
5793 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5796 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5797 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5798 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5799 checkGLcall("glDrawBuffer()");
5801 glDisable(GL_SCISSOR_TEST);
5802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5804 if (flip) {
5805 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5806 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5807 checkGLcall("glBlitFramebuffer()");
5808 } else {
5809 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5810 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5811 checkGLcall("glBlitFramebuffer()");
5814 if (This->render_offscreen) {
5815 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5816 } else {
5817 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5818 checkGLcall("glBindFramebuffer()");
5821 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5822 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5823 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5824 glDrawBuffer(GL_BACK);
5825 checkGLcall("glDrawBuffer()");
5827 LEAVE_GL();
5830 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5831 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5832 WINED3DVIEWPORT viewport;
5834 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5836 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5837 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5838 return WINED3DERR_INVALIDCALL;
5841 /* MSDN says that null disables the render target
5842 but a device must always be associated with a render target
5843 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5845 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5846 for more details
5848 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5849 FIXME("Trying to set render target 0 to NULL\n");
5850 return WINED3DERR_INVALIDCALL;
5852 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5853 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);
5854 return WINED3DERR_INVALIDCALL;
5857 /* If we are trying to set what we already have, don't bother */
5858 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5859 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5860 return WINED3D_OK;
5862 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5863 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5864 This->render_targets[RenderTargetIndex] = pRenderTarget;
5866 /* Render target 0 is special */
5867 if(RenderTargetIndex == 0) {
5868 /* Finally, reset the viewport as the MSDN states. */
5869 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5870 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5871 viewport.X = 0;
5872 viewport.Y = 0;
5873 viewport.MaxZ = 1.0f;
5874 viewport.MinZ = 0.0f;
5875 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5876 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5877 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5881 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5882 * ctx properly.
5883 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5884 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5886 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5888 return WINED3D_OK;
5891 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5893 HRESULT hr = WINED3D_OK;
5894 IWineD3DSurface *tmp;
5896 TRACE("(%p) Swapping z-buffer\n",This);
5898 if (pNewZStencil == This->stencilBufferTarget) {
5899 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5900 } else {
5901 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5902 * depending on the renter target implementation being used.
5903 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5904 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5905 * stencil buffer and incure an extra memory overhead
5906 ******************************************************/
5908 tmp = This->stencilBufferTarget;
5909 This->stencilBufferTarget = pNewZStencil;
5910 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5911 /* should we be calling the parent or the wined3d surface? */
5912 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5913 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5914 hr = WINED3D_OK;
5916 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5917 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5924 return hr;
5927 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5928 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5930 /* TODO: the use of Impl is deprecated. */
5931 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5932 WINED3DLOCKED_RECT lockedRect;
5934 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5936 /* some basic validation checks */
5937 if(This->cursorTexture) {
5938 ENTER_GL();
5939 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5940 glDeleteTextures(1, &This->cursorTexture);
5941 LEAVE_GL();
5942 This->cursorTexture = 0;
5945 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5946 This->haveHardwareCursor = TRUE;
5947 else
5948 This->haveHardwareCursor = FALSE;
5950 if(pCursorBitmap) {
5951 WINED3DLOCKED_RECT rect;
5953 /* MSDN: Cursor must be A8R8G8B8 */
5954 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5955 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5956 return WINED3DERR_INVALIDCALL;
5959 /* MSDN: Cursor must be smaller than the display mode */
5960 if(pSur->currentDesc.Width > This->ddraw_width ||
5961 pSur->currentDesc.Height > This->ddraw_height) {
5962 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);
5963 return WINED3DERR_INVALIDCALL;
5966 if (!This->haveHardwareCursor) {
5967 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5969 /* Do not store the surface's pointer because the application may
5970 * release it after setting the cursor image. Windows doesn't
5971 * addref the set surface, so we can't do this either without
5972 * creating circular refcount dependencies. Copy out the gl texture
5973 * instead.
5975 This->cursorWidth = pSur->currentDesc.Width;
5976 This->cursorHeight = pSur->currentDesc.Height;
5977 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5979 const GlPixelFormatDesc *glDesc;
5980 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
5981 char *mem, *bits = (char *)rect.pBits;
5982 GLint intfmt = glDesc->glInternal;
5983 GLint format = glDesc->glFormat;
5984 GLint type = glDesc->glType;
5985 INT height = This->cursorHeight;
5986 INT width = This->cursorWidth;
5987 INT bpp = tableEntry->bpp;
5988 INT i;
5990 /* Reformat the texture memory (pitch and width can be
5991 * different) */
5992 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5993 for(i = 0; i < height; i++)
5994 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5995 IWineD3DSurface_UnlockRect(pCursorBitmap);
5996 ENTER_GL();
5998 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5999 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6000 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6003 /* Make sure that a proper texture unit is selected */
6004 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6005 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6006 checkGLcall("glActiveTextureARB");
6008 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6009 /* Create a new cursor texture */
6010 glGenTextures(1, &This->cursorTexture);
6011 checkGLcall("glGenTextures");
6012 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6013 checkGLcall("glBindTexture");
6014 /* Copy the bitmap memory into the cursor texture */
6015 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6016 HeapFree(GetProcessHeap(), 0, mem);
6017 checkGLcall("glTexImage2D");
6019 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6020 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6021 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6024 LEAVE_GL();
6026 else
6028 FIXME("A cursor texture was not returned.\n");
6029 This->cursorTexture = 0;
6032 else
6034 /* Draw a hardware cursor */
6035 ICONINFO cursorInfo;
6036 HCURSOR cursor;
6037 /* Create and clear maskBits because it is not needed for
6038 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6039 * chunks. */
6040 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6041 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6042 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6043 WINED3DLOCK_NO_DIRTY_UPDATE |
6044 WINED3DLOCK_READONLY
6046 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6047 pSur->currentDesc.Height);
6049 cursorInfo.fIcon = FALSE;
6050 cursorInfo.xHotspot = XHotSpot;
6051 cursorInfo.yHotspot = YHotSpot;
6052 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6053 pSur->currentDesc.Height, 1,
6054 1, &maskBits);
6055 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6056 pSur->currentDesc.Height, 1,
6057 32, lockedRect.pBits);
6058 IWineD3DSurface_UnlockRect(pCursorBitmap);
6059 /* Create our cursor and clean up. */
6060 cursor = CreateIconIndirect(&cursorInfo);
6061 SetCursor(cursor);
6062 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6063 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6064 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6065 This->hardwareCursor = cursor;
6066 HeapFree(GetProcessHeap(), 0, maskBits);
6070 This->xHotSpot = XHotSpot;
6071 This->yHotSpot = YHotSpot;
6072 return WINED3D_OK;
6075 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6077 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6079 This->xScreenSpace = XScreenSpace;
6080 This->yScreenSpace = YScreenSpace;
6082 return;
6086 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6088 BOOL oldVisible = This->bCursorVisible;
6089 POINT pt;
6091 TRACE("(%p) : visible(%d)\n", This, bShow);
6094 * When ShowCursor is first called it should make the cursor appear at the OS's last
6095 * known cursor position. Because of this, some applications just repetitively call
6096 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6098 GetCursorPos(&pt);
6099 This->xScreenSpace = pt.x;
6100 This->yScreenSpace = pt.y;
6102 if (This->haveHardwareCursor) {
6103 This->bCursorVisible = bShow;
6104 if (bShow)
6105 SetCursor(This->hardwareCursor);
6106 else
6107 SetCursor(NULL);
6109 else
6111 if (This->cursorTexture)
6112 This->bCursorVisible = bShow;
6115 return oldVisible;
6118 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6120 TRACE("(%p) : state (%u)\n", This, This->state);
6121 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6122 switch (This->state) {
6123 case WINED3D_OK:
6124 return WINED3D_OK;
6125 case WINED3DERR_DEVICELOST:
6127 ResourceList *resourceList = This->resources;
6128 while (NULL != resourceList) {
6129 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6130 return WINED3DERR_DEVICENOTRESET;
6131 resourceList = resourceList->next;
6133 return WINED3DERR_DEVICELOST;
6135 case WINED3DERR_DRIVERINTERNALERROR:
6136 return WINED3DERR_DRIVERINTERNALERROR;
6139 /* Unknown state */
6140 return WINED3DERR_DRIVERINTERNALERROR;
6144 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6146 /** FIXME: Resource tracking needs to be done,
6147 * The closes we can do to this is set the priorities of all managed textures low
6148 * and then reset them.
6149 ***********************************************************/
6150 FIXME("(%p) : stub\n", This);
6151 return WINED3D_OK;
6154 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6155 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6157 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6158 if(surface->Flags & SFLAG_DIBSECTION) {
6159 /* Release the DC */
6160 SelectObject(surface->hDC, surface->dib.holdbitmap);
6161 DeleteDC(surface->hDC);
6162 /* Release the DIB section */
6163 DeleteObject(surface->dib.DIBsection);
6164 surface->dib.bitmap_data = NULL;
6165 surface->resource.allocatedMemory = NULL;
6166 surface->Flags &= ~SFLAG_DIBSECTION;
6168 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6169 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6170 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6171 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6172 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6173 } else {
6174 surface->pow2Width = surface->pow2Height = 1;
6175 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6176 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6178 if(surface->glDescription.textureName) {
6179 ENTER_GL();
6180 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6181 glDeleteTextures(1, &surface->glDescription.textureName);
6182 LEAVE_GL();
6183 surface->glDescription.textureName = 0;
6184 surface->Flags &= ~SFLAG_CLIENT;
6186 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6187 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6188 surface->Flags |= SFLAG_NONPOW2;
6189 } else {
6190 surface->Flags &= ~SFLAG_NONPOW2;
6192 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6193 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6196 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6198 IWineD3DSwapChainImpl *swapchain;
6199 HRESULT hr;
6200 BOOL DisplayModeChanged = FALSE;
6201 WINED3DDISPLAYMODE mode;
6202 TRACE("(%p)\n", This);
6204 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6205 if(FAILED(hr)) {
6206 ERR("Failed to get the first implicit swapchain\n");
6207 return hr;
6210 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6211 * on an existing gl context, so there's no real need for recreation.
6213 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6215 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6217 TRACE("New params:\n");
6218 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6219 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6220 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6221 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6222 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6223 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6224 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6225 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6226 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6227 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6228 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6229 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6230 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6232 /* No special treatment of these parameters. Just store them */
6233 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6234 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6235 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6236 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6238 /* What to do about these? */
6239 if(pPresentationParameters->BackBufferCount != 0 &&
6240 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6241 ERR("Cannot change the back buffer count yet\n");
6243 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6244 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6245 ERR("Cannot change the back buffer format yet\n");
6247 if(pPresentationParameters->hDeviceWindow != NULL &&
6248 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6249 ERR("Cannot change the device window yet\n");
6251 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6252 ERR("What do do about a changed auto depth stencil parameter?\n");
6255 if(pPresentationParameters->Windowed) {
6256 mode.Width = swapchain->orig_width;
6257 mode.Height = swapchain->orig_height;
6258 mode.RefreshRate = 0;
6259 mode.Format = swapchain->presentParms.BackBufferFormat;
6260 } else {
6261 mode.Width = pPresentationParameters->BackBufferWidth;
6262 mode.Height = pPresentationParameters->BackBufferHeight;
6263 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6264 mode.Format = swapchain->presentParms.BackBufferFormat;
6266 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6267 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6268 pPresentationParameters->BackBufferWidth,
6269 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6272 /* Should Width == 800 && Height == 0 set 800x600? */
6273 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6274 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6275 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6277 WINED3DVIEWPORT vp;
6278 int i;
6280 vp.X = 0;
6281 vp.Y = 0;
6282 vp.Width = pPresentationParameters->BackBufferWidth;
6283 vp.Height = pPresentationParameters->BackBufferHeight;
6284 vp.MinZ = 0;
6285 vp.MaxZ = 1;
6287 if(!pPresentationParameters->Windowed) {
6288 DisplayModeChanged = TRUE;
6290 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6291 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6293 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6294 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6295 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6298 /* Now set the new viewport */
6299 IWineD3DDevice_SetViewport(iface, &vp);
6302 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6303 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6304 DisplayModeChanged) {
6306 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6307 if(!pPresentationParameters->Windowed) {
6308 IWineD3DDevice_SetFullscreen(iface, TRUE);
6311 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6313 /* Switching out of fullscreen mode? First set the original res, then change the window */
6314 if(pPresentationParameters->Windowed) {
6315 IWineD3DDevice_SetFullscreen(iface, FALSE);
6317 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6320 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6321 return WINED3D_OK;
6324 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6326 /** FIXME: always true at the moment **/
6327 if(!bEnableDialogs) {
6328 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6330 return WINED3D_OK;
6334 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6336 TRACE("(%p) : pParameters %p\n", This, pParameters);
6338 *pParameters = This->createParms;
6339 return WINED3D_OK;
6342 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6343 IWineD3DSwapChain *swapchain;
6344 HRESULT hrc = WINED3D_OK;
6346 TRACE("Relaying to swapchain\n");
6348 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6349 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6350 IWineD3DSwapChain_Release(swapchain);
6352 return;
6355 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6356 IWineD3DSwapChain *swapchain;
6357 HRESULT hrc = WINED3D_OK;
6359 TRACE("Relaying to swapchain\n");
6361 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6362 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6363 IWineD3DSwapChain_Release(swapchain);
6365 return;
6369 /** ********************************************************
6370 * Notification functions
6371 ** ********************************************************/
6372 /** This function must be called in the release of a resource when ref == 0,
6373 * the contents of resource must still be correct,
6374 * any handels to other resource held by the caller must be closed
6375 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6376 *****************************************************/
6377 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6379 ResourceList* resourceList;
6381 TRACE("(%p) : resource %p\n", This, resource);
6382 /* add a new texture to the frot of the linked list */
6383 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6384 resourceList->resource = resource;
6386 /* Get the old head */
6387 resourceList->next = This->resources;
6389 This->resources = resourceList;
6390 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6392 return;
6395 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6397 ResourceList* resourceList = NULL;
6398 ResourceList* previousResourceList = NULL;
6400 TRACE("(%p) : resource %p\n", This, resource);
6402 resourceList = This->resources;
6404 while (resourceList != NULL) {
6405 if(resourceList->resource == resource) break;
6406 previousResourceList = resourceList;
6407 resourceList = resourceList->next;
6410 if (resourceList == NULL) {
6411 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6412 return;
6413 } else {
6414 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6416 /* make sure we don't leave a hole in the list */
6417 if (previousResourceList != NULL) {
6418 previousResourceList->next = resourceList->next;
6419 } else {
6420 This->resources = resourceList->next;
6423 return;
6427 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6429 int counter;
6431 TRACE("(%p) : resource %p\n", This, resource);
6432 switch(IWineD3DResource_GetType(resource)){
6433 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6434 case WINED3DRTYPE_SURFACE: {
6435 unsigned int i;
6437 /* Cleanup any FBO attachments if d3d is enabled */
6438 if(This->d3d_initialized) {
6439 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6440 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6441 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6442 set_render_target_fbo(iface, i, NULL);
6443 This->fbo_color_attachments[i] = NULL;
6446 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6447 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6448 set_depth_stencil_fbo(iface, NULL);
6449 This->fbo_depth_attachment = NULL;
6453 break;
6455 case WINED3DRTYPE_TEXTURE:
6456 case WINED3DRTYPE_CUBETEXTURE:
6457 case WINED3DRTYPE_VOLUMETEXTURE:
6458 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6459 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6460 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6461 This->stateBlock->textures[counter] = NULL;
6463 if (This->updateStateBlock != This->stateBlock ){
6464 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6465 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6466 This->updateStateBlock->textures[counter] = NULL;
6470 break;
6471 case WINED3DRTYPE_VOLUME:
6472 /* TODO: nothing really? */
6473 break;
6474 case WINED3DRTYPE_VERTEXBUFFER:
6475 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6477 int streamNumber;
6478 TRACE("Cleaning up stream pointers\n");
6480 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6481 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6482 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6484 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6485 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6486 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6487 This->updateStateBlock->streamSource[streamNumber] = 0;
6488 /* Set changed flag? */
6491 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) */
6492 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6493 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6494 This->stateBlock->streamSource[streamNumber] = 0;
6497 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6498 else { /* This shouldn't happen */
6499 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6501 #endif
6505 break;
6506 case WINED3DRTYPE_INDEXBUFFER:
6507 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6508 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6509 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6510 This->updateStateBlock->pIndexData = NULL;
6513 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6514 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6515 This->stateBlock->pIndexData = NULL;
6519 break;
6520 default:
6521 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6522 break;
6526 /* Remove the resoruce from the resourceStore */
6527 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6529 TRACE("Resource released\n");
6533 /**********************************************************
6534 * IWineD3DDevice VTbl follows
6535 **********************************************************/
6537 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6539 /*** IUnknown methods ***/
6540 IWineD3DDeviceImpl_QueryInterface,
6541 IWineD3DDeviceImpl_AddRef,
6542 IWineD3DDeviceImpl_Release,
6543 /*** IWineD3DDevice methods ***/
6544 IWineD3DDeviceImpl_GetParent,
6545 /*** Creation methods**/
6546 IWineD3DDeviceImpl_CreateVertexBuffer,
6547 IWineD3DDeviceImpl_CreateIndexBuffer,
6548 IWineD3DDeviceImpl_CreateStateBlock,
6549 IWineD3DDeviceImpl_CreateSurface,
6550 IWineD3DDeviceImpl_CreateTexture,
6551 IWineD3DDeviceImpl_CreateVolumeTexture,
6552 IWineD3DDeviceImpl_CreateVolume,
6553 IWineD3DDeviceImpl_CreateCubeTexture,
6554 IWineD3DDeviceImpl_CreateQuery,
6555 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6556 IWineD3DDeviceImpl_CreateVertexDeclaration,
6557 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6558 IWineD3DDeviceImpl_CreateVertexShader,
6559 IWineD3DDeviceImpl_CreatePixelShader,
6560 IWineD3DDeviceImpl_CreatePalette,
6561 /*** Odd functions **/
6562 IWineD3DDeviceImpl_Init3D,
6563 IWineD3DDeviceImpl_Uninit3D,
6564 IWineD3DDeviceImpl_SetFullscreen,
6565 IWineD3DDeviceImpl_SetMultithreaded,
6566 IWineD3DDeviceImpl_EvictManagedResources,
6567 IWineD3DDeviceImpl_GetAvailableTextureMem,
6568 IWineD3DDeviceImpl_GetBackBuffer,
6569 IWineD3DDeviceImpl_GetCreationParameters,
6570 IWineD3DDeviceImpl_GetDeviceCaps,
6571 IWineD3DDeviceImpl_GetDirect3D,
6572 IWineD3DDeviceImpl_GetDisplayMode,
6573 IWineD3DDeviceImpl_SetDisplayMode,
6574 IWineD3DDeviceImpl_GetHWND,
6575 IWineD3DDeviceImpl_SetHWND,
6576 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6577 IWineD3DDeviceImpl_GetRasterStatus,
6578 IWineD3DDeviceImpl_GetSwapChain,
6579 IWineD3DDeviceImpl_Reset,
6580 IWineD3DDeviceImpl_SetDialogBoxMode,
6581 IWineD3DDeviceImpl_SetCursorProperties,
6582 IWineD3DDeviceImpl_SetCursorPosition,
6583 IWineD3DDeviceImpl_ShowCursor,
6584 IWineD3DDeviceImpl_TestCooperativeLevel,
6585 /*** Getters and setters **/
6586 IWineD3DDeviceImpl_SetClipPlane,
6587 IWineD3DDeviceImpl_GetClipPlane,
6588 IWineD3DDeviceImpl_SetClipStatus,
6589 IWineD3DDeviceImpl_GetClipStatus,
6590 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6591 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6592 IWineD3DDeviceImpl_SetDepthStencilSurface,
6593 IWineD3DDeviceImpl_GetDepthStencilSurface,
6594 IWineD3DDeviceImpl_SetFVF,
6595 IWineD3DDeviceImpl_GetFVF,
6596 IWineD3DDeviceImpl_SetGammaRamp,
6597 IWineD3DDeviceImpl_GetGammaRamp,
6598 IWineD3DDeviceImpl_SetIndices,
6599 IWineD3DDeviceImpl_GetIndices,
6600 IWineD3DDeviceImpl_SetBaseVertexIndex,
6601 IWineD3DDeviceImpl_GetBaseVertexIndex,
6602 IWineD3DDeviceImpl_SetLight,
6603 IWineD3DDeviceImpl_GetLight,
6604 IWineD3DDeviceImpl_SetLightEnable,
6605 IWineD3DDeviceImpl_GetLightEnable,
6606 IWineD3DDeviceImpl_SetMaterial,
6607 IWineD3DDeviceImpl_GetMaterial,
6608 IWineD3DDeviceImpl_SetNPatchMode,
6609 IWineD3DDeviceImpl_GetNPatchMode,
6610 IWineD3DDeviceImpl_SetPaletteEntries,
6611 IWineD3DDeviceImpl_GetPaletteEntries,
6612 IWineD3DDeviceImpl_SetPixelShader,
6613 IWineD3DDeviceImpl_GetPixelShader,
6614 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6615 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6616 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6617 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6618 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6619 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6620 IWineD3DDeviceImpl_SetRenderState,
6621 IWineD3DDeviceImpl_GetRenderState,
6622 IWineD3DDeviceImpl_SetRenderTarget,
6623 IWineD3DDeviceImpl_GetRenderTarget,
6624 IWineD3DDeviceImpl_SetFrontBackBuffers,
6625 IWineD3DDeviceImpl_SetSamplerState,
6626 IWineD3DDeviceImpl_GetSamplerState,
6627 IWineD3DDeviceImpl_SetScissorRect,
6628 IWineD3DDeviceImpl_GetScissorRect,
6629 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6630 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6631 IWineD3DDeviceImpl_SetStreamSource,
6632 IWineD3DDeviceImpl_GetStreamSource,
6633 IWineD3DDeviceImpl_SetStreamSourceFreq,
6634 IWineD3DDeviceImpl_GetStreamSourceFreq,
6635 IWineD3DDeviceImpl_SetTexture,
6636 IWineD3DDeviceImpl_GetTexture,
6637 IWineD3DDeviceImpl_SetTextureStageState,
6638 IWineD3DDeviceImpl_GetTextureStageState,
6639 IWineD3DDeviceImpl_SetTransform,
6640 IWineD3DDeviceImpl_GetTransform,
6641 IWineD3DDeviceImpl_SetVertexDeclaration,
6642 IWineD3DDeviceImpl_GetVertexDeclaration,
6643 IWineD3DDeviceImpl_SetVertexShader,
6644 IWineD3DDeviceImpl_GetVertexShader,
6645 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6646 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6647 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6648 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6649 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6650 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6651 IWineD3DDeviceImpl_SetViewport,
6652 IWineD3DDeviceImpl_GetViewport,
6653 IWineD3DDeviceImpl_MultiplyTransform,
6654 IWineD3DDeviceImpl_ValidateDevice,
6655 IWineD3DDeviceImpl_ProcessVertices,
6656 /*** State block ***/
6657 IWineD3DDeviceImpl_BeginStateBlock,
6658 IWineD3DDeviceImpl_EndStateBlock,
6659 /*** Scene management ***/
6660 IWineD3DDeviceImpl_BeginScene,
6661 IWineD3DDeviceImpl_EndScene,
6662 IWineD3DDeviceImpl_Present,
6663 IWineD3DDeviceImpl_Clear,
6664 /*** Drawing ***/
6665 IWineD3DDeviceImpl_DrawPrimitive,
6666 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6667 IWineD3DDeviceImpl_DrawPrimitiveUP,
6668 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6669 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6670 IWineD3DDeviceImpl_DrawRectPatch,
6671 IWineD3DDeviceImpl_DrawTriPatch,
6672 IWineD3DDeviceImpl_DeletePatch,
6673 IWineD3DDeviceImpl_ColorFill,
6674 IWineD3DDeviceImpl_UpdateTexture,
6675 IWineD3DDeviceImpl_UpdateSurface,
6676 IWineD3DDeviceImpl_GetFrontBufferData,
6677 /*** object tracking ***/
6678 IWineD3DDeviceImpl_ResourceReleased
6682 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6683 WINED3DRS_ALPHABLENDENABLE ,
6684 WINED3DRS_ALPHAFUNC ,
6685 WINED3DRS_ALPHAREF ,
6686 WINED3DRS_ALPHATESTENABLE ,
6687 WINED3DRS_BLENDOP ,
6688 WINED3DRS_COLORWRITEENABLE ,
6689 WINED3DRS_DESTBLEND ,
6690 WINED3DRS_DITHERENABLE ,
6691 WINED3DRS_FILLMODE ,
6692 WINED3DRS_FOGDENSITY ,
6693 WINED3DRS_FOGEND ,
6694 WINED3DRS_FOGSTART ,
6695 WINED3DRS_LASTPIXEL ,
6696 WINED3DRS_SHADEMODE ,
6697 WINED3DRS_SRCBLEND ,
6698 WINED3DRS_STENCILENABLE ,
6699 WINED3DRS_STENCILFAIL ,
6700 WINED3DRS_STENCILFUNC ,
6701 WINED3DRS_STENCILMASK ,
6702 WINED3DRS_STENCILPASS ,
6703 WINED3DRS_STENCILREF ,
6704 WINED3DRS_STENCILWRITEMASK ,
6705 WINED3DRS_STENCILZFAIL ,
6706 WINED3DRS_TEXTUREFACTOR ,
6707 WINED3DRS_WRAP0 ,
6708 WINED3DRS_WRAP1 ,
6709 WINED3DRS_WRAP2 ,
6710 WINED3DRS_WRAP3 ,
6711 WINED3DRS_WRAP4 ,
6712 WINED3DRS_WRAP5 ,
6713 WINED3DRS_WRAP6 ,
6714 WINED3DRS_WRAP7 ,
6715 WINED3DRS_ZENABLE ,
6716 WINED3DRS_ZFUNC ,
6717 WINED3DRS_ZWRITEENABLE
6720 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6721 WINED3DTSS_ADDRESSW ,
6722 WINED3DTSS_ALPHAARG0 ,
6723 WINED3DTSS_ALPHAARG1 ,
6724 WINED3DTSS_ALPHAARG2 ,
6725 WINED3DTSS_ALPHAOP ,
6726 WINED3DTSS_BUMPENVLOFFSET ,
6727 WINED3DTSS_BUMPENVLSCALE ,
6728 WINED3DTSS_BUMPENVMAT00 ,
6729 WINED3DTSS_BUMPENVMAT01 ,
6730 WINED3DTSS_BUMPENVMAT10 ,
6731 WINED3DTSS_BUMPENVMAT11 ,
6732 WINED3DTSS_COLORARG0 ,
6733 WINED3DTSS_COLORARG1 ,
6734 WINED3DTSS_COLORARG2 ,
6735 WINED3DTSS_COLOROP ,
6736 WINED3DTSS_RESULTARG ,
6737 WINED3DTSS_TEXCOORDINDEX ,
6738 WINED3DTSS_TEXTURETRANSFORMFLAGS
6741 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6742 WINED3DSAMP_ADDRESSU ,
6743 WINED3DSAMP_ADDRESSV ,
6744 WINED3DSAMP_ADDRESSW ,
6745 WINED3DSAMP_BORDERCOLOR ,
6746 WINED3DSAMP_MAGFILTER ,
6747 WINED3DSAMP_MINFILTER ,
6748 WINED3DSAMP_MIPFILTER ,
6749 WINED3DSAMP_MIPMAPLODBIAS ,
6750 WINED3DSAMP_MAXMIPLEVEL ,
6751 WINED3DSAMP_MAXANISOTROPY ,
6752 WINED3DSAMP_SRGBTEXTURE ,
6753 WINED3DSAMP_ELEMENTINDEX
6756 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6757 WINED3DRS_AMBIENT ,
6758 WINED3DRS_AMBIENTMATERIALSOURCE ,
6759 WINED3DRS_CLIPPING ,
6760 WINED3DRS_CLIPPLANEENABLE ,
6761 WINED3DRS_COLORVERTEX ,
6762 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6763 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6764 WINED3DRS_FOGDENSITY ,
6765 WINED3DRS_FOGEND ,
6766 WINED3DRS_FOGSTART ,
6767 WINED3DRS_FOGTABLEMODE ,
6768 WINED3DRS_FOGVERTEXMODE ,
6769 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6770 WINED3DRS_LIGHTING ,
6771 WINED3DRS_LOCALVIEWER ,
6772 WINED3DRS_MULTISAMPLEANTIALIAS ,
6773 WINED3DRS_MULTISAMPLEMASK ,
6774 WINED3DRS_NORMALIZENORMALS ,
6775 WINED3DRS_PATCHEDGESTYLE ,
6776 WINED3DRS_POINTSCALE_A ,
6777 WINED3DRS_POINTSCALE_B ,
6778 WINED3DRS_POINTSCALE_C ,
6779 WINED3DRS_POINTSCALEENABLE ,
6780 WINED3DRS_POINTSIZE ,
6781 WINED3DRS_POINTSIZE_MAX ,
6782 WINED3DRS_POINTSIZE_MIN ,
6783 WINED3DRS_POINTSPRITEENABLE ,
6784 WINED3DRS_RANGEFOGENABLE ,
6785 WINED3DRS_SPECULARMATERIALSOURCE ,
6786 WINED3DRS_TWEENFACTOR ,
6787 WINED3DRS_VERTEXBLEND
6790 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6791 WINED3DTSS_TEXCOORDINDEX ,
6792 WINED3DTSS_TEXTURETRANSFORMFLAGS
6795 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6796 WINED3DSAMP_DMAPOFFSET
6799 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6800 DWORD rep = StateTable[state].representative;
6801 DWORD idx;
6802 BYTE shift;
6803 UINT i;
6804 WineD3DContext *context;
6806 if(!rep) return;
6807 for(i = 0; i < This->numContexts; i++) {
6808 context = This->contexts[i];
6809 if(isStateDirty(context, rep)) continue;
6811 context->dirtyArray[context->numDirtyEntries++] = rep;
6812 idx = rep >> 5;
6813 shift = rep & 0x1f;
6814 context->isStateDirty[idx] |= (1 << shift);