wined3d: Do not fail if the adapter info can't be initialized.
[wine/multimedia.git] / dlls / wined3d / device.c
blob9f6d63b5ea40ead3cfa07018c72b8b8d9f716b0f
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION 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 PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
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;
647 /* Setup some glformat defaults */
648 object->glDescription.glFormat = tableEntry->glFormat;
649 object->glDescription.glFormatInternal = tableEntry->glInternal;
650 object->glDescription.glType = tableEntry->glType;
652 object->glDescription.textureName = 0;
653 object->glDescription.level = Level;
654 object->glDescription.target = GL_TEXTURE_2D;
656 /* Flags */
657 object->Flags = 0;
658 object->Flags |= Discard ? SFLAG_DISCARD : 0;
659 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
660 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
663 if (WINED3DFMT_UNKNOWN != Format) {
664 object->bytesPerPixel = tableEntry->bpp;
665 } else {
666 object->bytesPerPixel = 0;
669 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
671 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
673 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
674 * this function is too deep to need to care about things like this.
675 * Levels need to be checked too, and possibly Type since they all affect what can be done.
676 * ****************************************/
677 switch(Pool) {
678 case WINED3DPOOL_SCRATCH:
679 if(!Lockable)
680 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
681 "which are mutually exclusive, setting lockable to TRUE\n");
682 Lockable = TRUE;
683 break;
684 case WINED3DPOOL_SYSTEMMEM:
685 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
686 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
687 case WINED3DPOOL_MANAGED:
688 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
689 "Usage of DYNAMIC which are mutually exclusive, not doing "
690 "anything just telling you.\n");
691 break;
692 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
693 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
694 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
695 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
696 break;
697 default:
698 FIXME("(%p) Unknown pool %d\n", This, Pool);
699 break;
702 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
703 FIXME("Trying to create a render target that isn't in the default pool\n");
706 /* mark the texture as dirty so that it gets loaded first time around*/
707 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
708 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
709 This, Width, Height, Format, debug_d3dformat(Format),
710 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
712 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
713 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
714 This->ddraw_primary = (IWineD3DSurface *) object;
716 /* Look at the implementation and set the correct Vtable */
717 switch(Impl) {
718 case SURFACE_OPENGL:
719 /* Check if a 3D adapter is available when creating gl surfaces */
720 if(!This->adapter) {
721 ERR("OpenGL surfaces are not available without opengl\n");
722 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
723 HeapFree(GetProcessHeap(), 0, object);
724 return WINED3DERR_NOTAVAILABLE;
726 break;
728 case SURFACE_GDI:
729 object->lpVtbl = &IWineGDISurface_Vtbl;
730 break;
732 default:
733 /* To be sure to catch this */
734 ERR("Unknown requested surface implementation %d!\n", Impl);
735 IWineD3DSurface_Release((IWineD3DSurface *) object);
736 return WINED3DERR_INVALIDCALL;
739 list_init(&object->renderbuffers);
741 /* Call the private setup routine */
742 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
746 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
747 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
748 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
749 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
752 IWineD3DTextureImpl *object;
753 unsigned int i;
754 UINT tmpW;
755 UINT tmpH;
756 HRESULT hr;
757 unsigned int pow2Width;
758 unsigned int pow2Height;
761 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
762 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
763 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
765 /* TODO: It should only be possible to create textures for formats
766 that are reported as supported */
767 if (WINED3DFMT_UNKNOWN >= Format) {
768 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
769 return WINED3DERR_INVALIDCALL;
772 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
773 D3DINITIALIZEBASETEXTURE(object->baseTexture);
774 object->width = Width;
775 object->height = Height;
777 /** Non-power2 support **/
778 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
779 pow2Width = Width;
780 pow2Height = Height;
781 } else {
782 /* Find the nearest pow2 match */
783 pow2Width = pow2Height = 1;
784 while (pow2Width < Width) pow2Width <<= 1;
785 while (pow2Height < Height) pow2Height <<= 1;
788 /** FIXME: add support for real non-power-two if it's provided by the video card **/
789 /* Precalculated scaling for 'faked' non power of two texture coords */
790 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
791 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
792 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
794 /* Calculate levels for mip mapping */
795 if (Levels == 0) {
796 TRACE("calculating levels %d\n", object->baseTexture.levels);
797 object->baseTexture.levels++;
798 tmpW = Width;
799 tmpH = Height;
800 while (tmpW > 1 || tmpH > 1) {
801 tmpW = max(1, tmpW >> 1);
802 tmpH = max(1, tmpH >> 1);
803 object->baseTexture.levels++;
805 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
808 /* Generate all the surfaces */
809 tmpW = Width;
810 tmpH = Height;
811 for (i = 0; i < object->baseTexture.levels; i++)
813 /* use the callback to create the texture surface */
814 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
815 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
816 FIXME("Failed to create surface %p\n", object);
817 /* clean up */
818 object->surfaces[i] = NULL;
819 IWineD3DTexture_Release((IWineD3DTexture *)object);
821 *ppTexture = NULL;
822 return hr;
825 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
826 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
827 /* calculate the next mipmap level */
828 tmpW = max(1, tmpW >> 1);
829 tmpH = max(1, tmpH >> 1);
832 TRACE("(%p) : Created texture %p\n", This, object);
833 return WINED3D_OK;
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
837 UINT Width, UINT Height, UINT Depth,
838 UINT Levels, DWORD Usage,
839 WINED3DFORMAT Format, WINED3DPOOL Pool,
840 IWineD3DVolumeTexture **ppVolumeTexture,
841 HANDLE *pSharedHandle, IUnknown *parent,
842 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
845 IWineD3DVolumeTextureImpl *object;
846 unsigned int i;
847 UINT tmpW;
848 UINT tmpH;
849 UINT tmpD;
851 /* TODO: It should only be possible to create textures for formats
852 that are reported as supported */
853 if (WINED3DFMT_UNKNOWN >= Format) {
854 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
855 return WINED3DERR_INVALIDCALL;
858 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
859 D3DINITIALIZEBASETEXTURE(object->baseTexture);
861 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
862 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
864 object->width = Width;
865 object->height = Height;
866 object->depth = Depth;
868 /* Calculate levels for mip mapping */
869 if (Levels == 0) {
870 object->baseTexture.levels++;
871 tmpW = Width;
872 tmpH = Height;
873 tmpD = Depth;
874 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
875 tmpW = max(1, tmpW >> 1);
876 tmpH = max(1, tmpH >> 1);
877 tmpD = max(1, tmpD >> 1);
878 object->baseTexture.levels++;
880 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
883 /* Generate all the surfaces */
884 tmpW = Width;
885 tmpH = Height;
886 tmpD = Depth;
888 for (i = 0; i < object->baseTexture.levels; i++)
890 HRESULT hr;
891 /* Create the volume */
892 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
893 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
895 if(FAILED(hr)) {
896 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
897 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
898 *ppVolumeTexture = NULL;
899 return hr;
902 /* Set its container to this object */
903 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
905 /* calcualte the next mipmap level */
906 tmpW = max(1, tmpW >> 1);
907 tmpH = max(1, tmpH >> 1);
908 tmpD = max(1, tmpD >> 1);
911 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
912 TRACE("(%p) : Created volume texture %p\n", This, object);
913 return WINED3D_OK;
916 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
917 UINT Width, UINT Height, UINT Depth,
918 DWORD Usage,
919 WINED3DFORMAT Format, WINED3DPOOL Pool,
920 IWineD3DVolume** ppVolume,
921 HANDLE* pSharedHandle, IUnknown *parent) {
923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
924 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
925 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
927 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
929 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
930 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
932 object->currentDesc.Width = Width;
933 object->currentDesc.Height = Height;
934 object->currentDesc.Depth = Depth;
935 object->bytesPerPixel = formatDesc->bpp;
937 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
938 object->lockable = TRUE;
939 object->locked = FALSE;
940 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
941 object->dirty = TRUE;
943 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
946 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
947 UINT Levels, DWORD Usage,
948 WINED3DFORMAT Format, WINED3DPOOL Pool,
949 IWineD3DCubeTexture **ppCubeTexture,
950 HANDLE *pSharedHandle, IUnknown *parent,
951 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
954 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
955 unsigned int i, j;
956 UINT tmpW;
957 HRESULT hr;
958 unsigned int pow2EdgeLength = EdgeLength;
960 /* TODO: It should only be possible to create textures for formats
961 that are reported as supported */
962 if (WINED3DFMT_UNKNOWN >= Format) {
963 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
964 return WINED3DERR_INVALIDCALL;
967 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
968 WARN("(%p) : Tried to create not supported cube texture\n", This);
969 return WINED3DERR_INVALIDCALL;
972 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
973 D3DINITIALIZEBASETEXTURE(object->baseTexture);
975 TRACE("(%p) Create Cube Texture\n", This);
977 /** Non-power2 support **/
979 /* Find the nearest pow2 match */
980 pow2EdgeLength = 1;
981 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
983 object->edgeLength = EdgeLength;
984 /* TODO: support for native non-power 2 */
985 /* Precalculated scaling for 'faked' non power of two texture coords */
986 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
988 /* Calculate levels for mip mapping */
989 if (Levels == 0) {
990 object->baseTexture.levels++;
991 tmpW = EdgeLength;
992 while (tmpW > 1) {
993 tmpW = max(1, tmpW >> 1);
994 object->baseTexture.levels++;
996 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
999 /* Generate all the surfaces */
1000 tmpW = EdgeLength;
1001 for (i = 0; i < object->baseTexture.levels; i++) {
1003 /* Create the 6 faces */
1004 for (j = 0; j < 6; j++) {
1006 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1007 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1009 if(hr!= WINED3D_OK) {
1010 /* clean up */
1011 int k;
1012 int l;
1013 for (l = 0; l < j; l++) {
1014 IWineD3DSurface_Release(object->surfaces[j][i]);
1016 for (k = 0; k < i; k++) {
1017 for (l = 0; l < 6; l++) {
1018 IWineD3DSurface_Release(object->surfaces[l][j]);
1022 FIXME("(%p) Failed to create surface\n",object);
1023 HeapFree(GetProcessHeap(),0,object);
1024 *ppCubeTexture = NULL;
1025 return hr;
1027 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1028 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1030 tmpW = max(1, tmpW >> 1);
1033 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1034 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1035 return WINED3D_OK;
1038 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1040 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1041 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1043 /* Just a check to see if we support this type of query */
1044 switch(Type) {
1045 case WINED3DQUERYTYPE_OCCLUSION:
1046 TRACE("(%p) occlusion query\n", This);
1047 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1048 hr = WINED3D_OK;
1049 else
1050 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1051 break;
1053 case WINED3DQUERYTYPE_EVENT:
1054 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1055 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1056 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1058 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1060 hr = WINED3D_OK;
1061 break;
1063 case WINED3DQUERYTYPE_VCACHE:
1064 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1065 case WINED3DQUERYTYPE_VERTEXSTATS:
1066 case WINED3DQUERYTYPE_TIMESTAMP:
1067 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1068 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1069 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1070 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1071 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1072 case WINED3DQUERYTYPE_PIXELTIMINGS:
1073 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1074 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1075 default:
1076 FIXME("(%p) Unhandled query type %d\n", This, Type);
1078 if(NULL == ppQuery || hr != WINED3D_OK) {
1079 return hr;
1082 D3DCREATEOBJECTINSTANCE(object, Query)
1083 object->type = Type;
1084 /* allocated the 'extended' data based on the type of query requested */
1085 switch(Type){
1086 case WINED3DQUERYTYPE_OCCLUSION:
1087 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1088 TRACE("(%p) Allocating data for an occlusion query\n", This);
1089 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1090 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1091 break;
1093 case WINED3DQUERYTYPE_EVENT:
1094 /* TODO: GL_APPLE_fence */
1095 if(GL_SUPPORT(APPLE_FENCE)) {
1096 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1097 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1098 checkGLcall("glGenFencesAPPLE");
1099 } else if(GL_SUPPORT(NV_FENCE)) {
1100 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1101 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1102 checkGLcall("glGenFencesNV");
1104 break;
1106 case WINED3DQUERYTYPE_VCACHE:
1107 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1108 case WINED3DQUERYTYPE_VERTEXSTATS:
1109 case WINED3DQUERYTYPE_TIMESTAMP:
1110 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1111 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1112 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1113 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1114 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1115 case WINED3DQUERYTYPE_PIXELTIMINGS:
1116 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1117 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1118 default:
1119 object->extendedData = 0;
1120 FIXME("(%p) Unhandled query type %d\n",This , Type);
1122 TRACE("(%p) : Created Query %p\n", This, object);
1123 return WINED3D_OK;
1126 /*****************************************************************************
1127 * IWineD3DDeviceImpl_SetupFullscreenWindow
1129 * Helper function that modifies a HWND's Style and ExStyle for proper
1130 * fullscreen use.
1132 * Params:
1133 * iface: Pointer to the IWineD3DDevice interface
1134 * window: Window to setup
1136 *****************************************************************************/
1137 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1140 LONG style, exStyle;
1141 /* Don't do anything if an original style is stored.
1142 * That shouldn't happen
1144 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1145 if (This->style || This->exStyle) {
1146 ERR("(%p): Want to change the window parameters of HWND %p, but "
1147 "another style is stored for restoration afterwards\n", This, window);
1150 /* Get the parameters and save them */
1151 style = GetWindowLongW(window, GWL_STYLE);
1152 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1153 This->style = style;
1154 This->exStyle = exStyle;
1156 /* Filter out window decorations */
1157 style &= ~WS_CAPTION;
1158 style &= ~WS_THICKFRAME;
1159 exStyle &= ~WS_EX_WINDOWEDGE;
1160 exStyle &= ~WS_EX_CLIENTEDGE;
1162 /* Make sure the window is managed, otherwise we won't get keyboard input */
1163 style |= WS_POPUP | WS_SYSMENU;
1165 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1166 This->style, This->exStyle, style, exStyle);
1168 SetWindowLongW(window, GWL_STYLE, style);
1169 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1171 /* Inform the window about the update. */
1172 SetWindowPos(window, HWND_TOP, 0, 0,
1173 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1174 ShowWindow(window, SW_NORMAL);
1177 /*****************************************************************************
1178 * IWineD3DDeviceImpl_RestoreWindow
1180 * Helper function that restores a windows' properties when taking it out
1181 * of fullscreen mode
1183 * Params:
1184 * iface: Pointer to the IWineD3DDevice interface
1185 * window: Window to setup
1187 *****************************************************************************/
1188 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1191 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1192 * switch, do nothing
1194 if (!This->style && !This->exStyle) return;
1196 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1197 This, window, This->style, This->exStyle);
1199 SetWindowLongW(window, GWL_STYLE, This->style);
1200 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1202 /* Delete the old values */
1203 This->style = 0;
1204 This->exStyle = 0;
1206 /* Inform the window about the update */
1207 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1208 0, 0, 0, 0, /* Pos, Size, ignored */
1209 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1212 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1213 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1214 IUnknown* parent,
1215 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1216 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1219 HDC hDc;
1220 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1221 HRESULT hr = WINED3D_OK;
1222 IUnknown *bufferParent;
1223 Display *display;
1225 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1227 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1228 * does a device hold a reference to a swap chain giving them a lifetime of the device
1229 * or does the swap chain notify the device of its destruction.
1230 *******************************/
1232 /* Check the params */
1233 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1234 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1235 return WINED3DERR_INVALIDCALL;
1236 } else if (pPresentationParameters->BackBufferCount > 1) {
1237 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");
1240 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1242 /*********************
1243 * Lookup the window Handle and the relating X window handle
1244 ********************/
1246 /* Setup hwnd we are using, plus which display this equates to */
1247 object->win_handle = pPresentationParameters->hDeviceWindow;
1248 if (!object->win_handle) {
1249 object->win_handle = This->createParms.hFocusWindow;
1252 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1253 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1254 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1255 return WINED3DERR_NOTAVAILABLE;
1257 hDc = GetDC(object->win_handle);
1258 display = get_display(hDc);
1259 ReleaseDC(object->win_handle, hDc);
1260 TRACE("Using a display of %p %p\n", display, hDc);
1262 if (NULL == display || NULL == hDc) {
1263 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1264 return WINED3DERR_NOTAVAILABLE;
1267 if (object->win == 0) {
1268 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1269 return WINED3DERR_NOTAVAILABLE;
1272 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1273 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1274 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1276 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1277 * then the corresponding dimension of the client area of the hDeviceWindow
1278 * (or the focus window, if hDeviceWindow is NULL) is taken.
1279 **********************/
1281 if (pPresentationParameters->Windowed &&
1282 ((pPresentationParameters->BackBufferWidth == 0) ||
1283 (pPresentationParameters->BackBufferHeight == 0))) {
1285 RECT Rect;
1286 GetClientRect(object->win_handle, &Rect);
1288 if (pPresentationParameters->BackBufferWidth == 0) {
1289 pPresentationParameters->BackBufferWidth = Rect.right;
1290 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1292 if (pPresentationParameters->BackBufferHeight == 0) {
1293 pPresentationParameters->BackBufferHeight = Rect.bottom;
1294 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1298 /* Put the correct figures in the presentation parameters */
1299 TRACE("Copying across presentation parameters\n");
1300 object->presentParms = *pPresentationParameters;
1302 TRACE("calling rendertarget CB\n");
1303 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1304 parent,
1305 object->presentParms.BackBufferWidth,
1306 object->presentParms.BackBufferHeight,
1307 object->presentParms.BackBufferFormat,
1308 object->presentParms.MultiSampleType,
1309 object->presentParms.MultiSampleQuality,
1310 TRUE /* Lockable */,
1311 &object->frontBuffer,
1312 NULL /* pShared (always null)*/);
1313 if (object->frontBuffer != NULL) {
1314 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1315 } else {
1316 ERR("Failed to create the front buffer\n");
1317 goto error;
1321 * Create an opengl context for the display visual
1322 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1323 * use different properties after that point in time. FIXME: How to handle when requested format
1324 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1325 * it chooses is identical to the one already being used!
1326 **********************************/
1327 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1329 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1330 if(!object->context)
1331 return E_OUTOFMEMORY;
1332 object->num_contexts = 1;
1334 ENTER_GL();
1335 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1336 LEAVE_GL();
1338 if (!object->context[0]) {
1339 ERR("Failed to create a new context\n");
1340 hr = WINED3DERR_NOTAVAILABLE;
1341 goto error;
1342 } else {
1343 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1344 object->win_handle, object->context[0]->glCtx, object->win);
1347 /*********************
1348 * Windowed / Fullscreen
1349 *******************/
1352 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1353 * so we should really check to see if there is a fullscreen swapchain already
1354 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1355 **************************************/
1357 if (!pPresentationParameters->Windowed) {
1359 DEVMODEW devmode;
1360 HDC hdc;
1361 int bpp = 0;
1362 RECT clip_rc;
1364 /* Get info on the current display setup */
1365 hdc = GetDC(0);
1366 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1367 ReleaseDC(0, hdc);
1369 /* Change the display settings */
1370 memset(&devmode, 0, sizeof(DEVMODEW));
1371 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1372 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1373 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1374 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1375 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1376 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1378 /* For GetDisplayMode */
1379 This->ddraw_width = devmode.dmPelsWidth;
1380 This->ddraw_height = devmode.dmPelsHeight;
1381 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1383 IWineD3DDevice_SetFullscreen(iface, TRUE);
1385 /* And finally clip mouse to our screen */
1386 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1387 ClipCursor(&clip_rc);
1390 /*********************
1391 * Create the back, front and stencil buffers
1392 *******************/
1393 if(object->presentParms.BackBufferCount > 0) {
1394 int i;
1396 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1397 if(!object->backBuffer) {
1398 ERR("Out of memory\n");
1399 hr = E_OUTOFMEMORY;
1400 goto error;
1403 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1404 TRACE("calling rendertarget CB\n");
1405 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1406 parent,
1407 object->presentParms.BackBufferWidth,
1408 object->presentParms.BackBufferHeight,
1409 object->presentParms.BackBufferFormat,
1410 object->presentParms.MultiSampleType,
1411 object->presentParms.MultiSampleQuality,
1412 TRUE /* Lockable */,
1413 &object->backBuffer[i],
1414 NULL /* pShared (always null)*/);
1415 if(hr == WINED3D_OK && object->backBuffer[i]) {
1416 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1417 } else {
1418 ERR("Cannot create new back buffer\n");
1419 goto error;
1421 ENTER_GL();
1422 glDrawBuffer(GL_BACK);
1423 checkGLcall("glDrawBuffer(GL_BACK)");
1424 LEAVE_GL();
1426 } else {
1427 object->backBuffer = NULL;
1429 /* Single buffering - draw to front buffer */
1430 ENTER_GL();
1431 glDrawBuffer(GL_FRONT);
1432 checkGLcall("glDrawBuffer(GL_FRONT)");
1433 LEAVE_GL();
1436 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1437 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1438 TRACE("Creating depth stencil buffer\n");
1439 if (This->depthStencilBuffer == NULL ) {
1440 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1441 parent,
1442 object->presentParms.BackBufferWidth,
1443 object->presentParms.BackBufferHeight,
1444 object->presentParms.AutoDepthStencilFormat,
1445 object->presentParms.MultiSampleType,
1446 object->presentParms.MultiSampleQuality,
1447 FALSE /* FIXME: Discard */,
1448 &This->depthStencilBuffer,
1449 NULL /* pShared (always null)*/ );
1450 if (This->depthStencilBuffer != NULL)
1451 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1454 /** TODO: A check on width, height and multisample types
1455 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1456 ****************************/
1457 object->wantsDepthStencilBuffer = TRUE;
1458 } else {
1459 object->wantsDepthStencilBuffer = FALSE;
1462 TRACE("Created swapchain %p\n", object);
1463 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1464 return WINED3D_OK;
1466 error:
1467 if (object->backBuffer) {
1468 int i;
1469 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1470 if(object->backBuffer[i]) {
1471 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1472 IUnknown_Release(bufferParent); /* once for the get parent */
1473 if (IUnknown_Release(bufferParent) > 0) {
1474 FIXME("(%p) Something's still holding the back buffer\n",This);
1478 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1479 object->backBuffer = NULL;
1481 if(object->context[0])
1482 DestroyContext(This, object->context[0]);
1483 if(object->frontBuffer) {
1484 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1485 IUnknown_Release(bufferParent); /* once for the get parent */
1486 if (IUnknown_Release(bufferParent) > 0) {
1487 FIXME("(%p) Something's still holding the front buffer\n",This);
1490 HeapFree(GetProcessHeap(), 0, object);
1491 return hr;
1494 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1495 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1497 TRACE("(%p)\n", This);
1499 return This->NumberOfSwapChains;
1502 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1504 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1506 if(iSwapChain < This->NumberOfSwapChains) {
1507 *pSwapChain = This->swapchains[iSwapChain];
1508 IWineD3DSwapChain_AddRef(*pSwapChain);
1509 TRACE("(%p) returning %p\n", This, *pSwapChain);
1510 return WINED3D_OK;
1511 } else {
1512 TRACE("Swapchain out of range\n");
1513 *pSwapChain = NULL;
1514 return WINED3DERR_INVALIDCALL;
1518 /*****
1519 * Vertex Declaration
1520 *****/
1521 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1522 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1524 IWineD3DVertexDeclarationImpl *object = NULL;
1525 HRESULT hr = WINED3D_OK;
1527 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1528 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1530 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1532 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1534 return hr;
1537 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1539 unsigned int idx, idx2;
1540 unsigned int offset;
1541 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1542 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1543 BOOL has_blend_idx = has_blend &&
1544 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1545 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1546 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1547 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1548 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1549 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1550 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1552 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1553 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1555 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1556 WINED3DVERTEXELEMENT *elements = NULL;
1558 unsigned int size;
1559 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1560 if (has_blend_idx) num_blends--;
1562 /* Compute declaration size */
1563 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1564 has_psize + has_diffuse + has_specular + num_textures + 1;
1566 /* convert the declaration */
1567 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1568 if (!elements)
1569 return 0;
1571 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1572 idx = 0;
1573 if (has_pos) {
1574 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1575 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1576 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1578 else {
1579 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1580 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1582 elements[idx].UsageIndex = 0;
1583 idx++;
1585 if (has_blend && (num_blends > 0)) {
1586 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1587 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1588 else
1589 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1590 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1591 elements[idx].UsageIndex = 0;
1592 idx++;
1594 if (has_blend_idx) {
1595 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1596 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1597 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1598 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1599 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1600 else
1601 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1602 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1603 elements[idx].UsageIndex = 0;
1604 idx++;
1606 if (has_normal) {
1607 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1608 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1609 elements[idx].UsageIndex = 0;
1610 idx++;
1612 if (has_psize) {
1613 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1614 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1615 elements[idx].UsageIndex = 0;
1616 idx++;
1618 if (has_diffuse) {
1619 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1620 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1621 elements[idx].UsageIndex = 0;
1622 idx++;
1624 if (has_specular) {
1625 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1626 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1627 elements[idx].UsageIndex = 1;
1628 idx++;
1630 for (idx2 = 0; idx2 < num_textures; idx2++) {
1631 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1632 switch (numcoords) {
1633 case WINED3DFVF_TEXTUREFORMAT1:
1634 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1635 break;
1636 case WINED3DFVF_TEXTUREFORMAT2:
1637 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1638 break;
1639 case WINED3DFVF_TEXTUREFORMAT3:
1640 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1641 break;
1642 case WINED3DFVF_TEXTUREFORMAT4:
1643 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1644 break;
1646 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1647 elements[idx].UsageIndex = idx2;
1648 idx++;
1651 /* Now compute offsets, and initialize the rest of the fields */
1652 for (idx = 0, offset = 0; idx < size-1; idx++) {
1653 elements[idx].Stream = 0;
1654 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1655 elements[idx].Offset = offset;
1656 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1659 *ppVertexElements = elements;
1660 return size;
1663 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1664 WINED3DVERTEXELEMENT* elements = NULL;
1665 size_t size;
1666 DWORD hr;
1668 size = ConvertFvfToDeclaration(Fvf, &elements);
1669 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1671 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1672 HeapFree(GetProcessHeap(), 0, elements);
1673 if (hr != S_OK) return hr;
1675 return WINED3D_OK;
1678 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1679 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1681 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1682 HRESULT hr = WINED3D_OK;
1683 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1684 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1686 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1688 if (vertex_declaration) {
1689 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1692 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1694 if (WINED3D_OK != hr) {
1695 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1696 IWineD3DVertexShader_Release(*ppVertexShader);
1697 return WINED3DERR_INVALIDCALL;
1700 return WINED3D_OK;
1703 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1705 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1706 HRESULT hr = WINED3D_OK;
1708 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1709 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1710 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1711 if (WINED3D_OK == hr) {
1712 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1713 } else {
1714 WARN("(%p) : Failed to create pixel shader\n", This);
1717 return hr;
1720 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1722 IWineD3DPaletteImpl *object;
1723 HRESULT hr;
1724 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1726 /* Create the new object */
1727 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1728 if(!object) {
1729 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1730 return E_OUTOFMEMORY;
1733 object->lpVtbl = &IWineD3DPalette_Vtbl;
1734 object->ref = 1;
1735 object->Flags = Flags;
1736 object->parent = Parent;
1737 object->wineD3DDevice = This;
1738 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1740 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1742 if(!object->hpal) {
1743 HeapFree( GetProcessHeap(), 0, object);
1744 return E_OUTOFMEMORY;
1747 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1748 if(FAILED(hr)) {
1749 IWineD3DPalette_Release((IWineD3DPalette *) object);
1750 return hr;
1753 *Palette = (IWineD3DPalette *) object;
1755 return WINED3D_OK;
1758 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1760 IWineD3DSwapChainImpl *swapchain;
1761 HRESULT hr;
1762 DWORD state;
1764 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1765 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1767 /* TODO: Test if OpenGL is compiled in and loaded */
1769 TRACE("(%p) : Creating stateblock\n", This);
1770 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1771 hr = IWineD3DDevice_CreateStateBlock(iface,
1772 WINED3DSBT_INIT,
1773 (IWineD3DStateBlock **)&This->stateBlock,
1774 NULL);
1775 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1776 WARN("Failed to create stateblock\n");
1777 return hr;
1779 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1780 This->updateStateBlock = This->stateBlock;
1781 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1783 hr = allocate_shader_constants(This->updateStateBlock);
1784 if (WINED3D_OK != hr)
1785 return hr;
1787 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1788 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1789 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1791 /* Initialize the texture unit mapping to a 1:1 mapping */
1792 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1793 if (state < GL_LIMITS(fragment_samplers)) {
1794 This->texUnitMap[state] = state;
1795 This->rev_tex_unit_map[state] = state;
1796 } else {
1797 This->texUnitMap[state] = -1;
1798 This->rev_tex_unit_map[state] = -1;
1802 /* Setup the implicit swapchain */
1803 TRACE("Creating implicit swapchain\n");
1804 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1805 if (FAILED(hr) || !swapchain) {
1806 WARN("Failed to create implicit swapchain\n");
1807 return hr;
1810 This->NumberOfSwapChains = 1;
1811 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1812 if(!This->swapchains) {
1813 ERR("Out of memory!\n");
1814 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1815 return E_OUTOFMEMORY;
1817 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1819 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1821 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1822 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1823 This->render_targets[0] = swapchain->backBuffer[0];
1824 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1826 else {
1827 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1828 This->render_targets[0] = swapchain->frontBuffer;
1829 This->lastActiveRenderTarget = swapchain->frontBuffer;
1831 IWineD3DSurface_AddRef(This->render_targets[0]);
1832 This->activeContext = swapchain->context[0];
1833 This->lastThread = GetCurrentThreadId();
1835 /* Depth Stencil support */
1836 This->stencilBufferTarget = This->depthStencilBuffer;
1837 if (NULL != This->stencilBufferTarget) {
1838 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1841 /* Set up some starting GL setup */
1842 ENTER_GL();
1844 /* Setup all the devices defaults */
1845 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1846 #if 0
1847 IWineD3DImpl_CheckGraphicsMemory();
1848 #endif
1850 { /* Set a default viewport */
1851 WINED3DVIEWPORT vp;
1852 vp.X = 0;
1853 vp.Y = 0;
1854 vp.Width = pPresentationParameters->BackBufferWidth;
1855 vp.Height = pPresentationParameters->BackBufferHeight;
1856 vp.MinZ = 0.0f;
1857 vp.MaxZ = 1.0f;
1858 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1861 /* Initialize the current view state */
1862 This->view_ident = 1;
1863 This->contexts[0]->last_was_rhw = 0;
1864 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1865 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1867 switch(wined3d_settings.offscreen_rendering_mode) {
1868 case ORM_FBO:
1869 case ORM_PBUFFER:
1870 This->offscreenBuffer = GL_BACK;
1871 break;
1873 case ORM_BACKBUFFER:
1875 if(GL_LIMITS(aux_buffers) > 0) {
1876 TRACE("Using auxilliary buffer for offscreen rendering\n");
1877 This->offscreenBuffer = GL_AUX0;
1878 } else {
1879 TRACE("Using back buffer for offscreen rendering\n");
1880 This->offscreenBuffer = GL_BACK;
1885 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1886 LEAVE_GL();
1888 /* Clear the screen */
1889 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1890 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1891 0x00, 1.0, 0);
1893 This->d3d_initialized = TRUE;
1894 return WINED3D_OK;
1897 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1899 int sampler;
1900 uint i;
1901 TRACE("(%p)\n", This);
1903 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1905 ENTER_GL();
1906 /* I don't think that the interface guarants that the device is destroyed from the same thread
1907 * it was created. Thus make sure a context is active for the glDelete* calls
1909 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1910 LEAVE_GL();
1912 TRACE("Deleting high order patches\n");
1913 for(i = 0; i < PATCHMAP_SIZE; i++) {
1914 struct list *e1, *e2;
1915 struct WineD3DRectPatch *patch;
1916 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1917 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1918 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1922 /* Delete the pbuffer context if there is any */
1923 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1925 /* Delete the mouse cursor texture */
1926 if(This->cursorTexture) {
1927 ENTER_GL();
1928 glDeleteTextures(1, &This->cursorTexture);
1929 LEAVE_GL();
1930 This->cursorTexture = 0;
1933 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1934 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1936 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1937 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1940 /* Release the buffers (with sanity checks)*/
1941 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1942 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1943 if(This->depthStencilBuffer != This->stencilBufferTarget)
1944 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1946 This->stencilBufferTarget = NULL;
1948 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1949 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1950 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1952 TRACE("Setting rendertarget to NULL\n");
1953 This->render_targets[0] = NULL;
1955 if (This->depthStencilBuffer) {
1956 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1957 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1959 This->depthStencilBuffer = NULL;
1962 for(i=0; i < This->NumberOfSwapChains; i++) {
1963 TRACE("Releasing the implicit swapchain %d\n", i);
1964 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1965 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1969 HeapFree(GetProcessHeap(), 0, This->swapchains);
1970 This->swapchains = NULL;
1971 This->NumberOfSwapChains = 0;
1973 /* Release the update stateblock */
1974 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1975 if(This->updateStateBlock != This->stateBlock)
1976 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1978 This->updateStateBlock = NULL;
1980 { /* because were not doing proper internal refcounts releasing the primary state block
1981 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1982 to set this->stateBlock = NULL; first */
1983 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1984 This->stateBlock = NULL;
1986 /* Release the stateblock */
1987 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1988 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1992 HeapFree(GetProcessHeap(), 0, This->render_targets);
1993 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
1994 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1995 This->render_targets = NULL;
1996 This->fbo_color_attachments = NULL;
1997 This->draw_buffers = NULL;
2000 This->d3d_initialized = FALSE;
2001 return WINED3D_OK;
2004 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2008 /* Setup the window for fullscreen mode */
2009 if(fullscreen && !This->ddraw_fullscreen) {
2010 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2011 } else if(!fullscreen && This->ddraw_fullscreen) {
2012 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2015 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2016 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2017 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2018 * separately.
2020 This->ddraw_fullscreen = fullscreen;
2023 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2024 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2025 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2027 * There is no way to deactivate thread safety once it is enabled
2029 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2031 FIXME("No thread safety in wined3d yet\n");
2033 /*For now just store the flag(needed in case of ddraw) */
2034 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2036 return;
2039 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2040 DEVMODEW devmode;
2041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2042 LONG ret;
2043 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2044 RECT clip_rc;
2046 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2048 /* Resize the screen even without a window:
2049 * The app could have unset it with SetCooperativeLevel, but not called
2050 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2051 * but we don't have any hwnd
2054 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2055 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2056 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2057 devmode.dmPelsWidth = pMode->Width;
2058 devmode.dmPelsHeight = pMode->Height;
2060 devmode.dmDisplayFrequency = pMode->RefreshRate;
2061 if (pMode->RefreshRate != 0) {
2062 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2065 /* Only change the mode if necessary */
2066 if( (This->ddraw_width == pMode->Width) &&
2067 (This->ddraw_height == pMode->Height) &&
2068 (This->ddraw_format == pMode->Format) &&
2069 (pMode->RefreshRate == 0) ) {
2070 return WINED3D_OK;
2073 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2074 if (ret != DISP_CHANGE_SUCCESSFUL) {
2075 if(devmode.dmDisplayFrequency != 0) {
2076 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2077 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2078 devmode.dmDisplayFrequency = 0;
2079 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2081 if(ret != DISP_CHANGE_SUCCESSFUL) {
2082 return WINED3DERR_NOTAVAILABLE;
2086 /* Store the new values */
2087 This->ddraw_width = pMode->Width;
2088 This->ddraw_height = pMode->Height;
2089 This->ddraw_format = pMode->Format;
2091 /* Only do this with a window of course */
2092 if(This->ddraw_window)
2093 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2095 /* And finally clip mouse to our screen */
2096 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2097 ClipCursor(&clip_rc);
2099 return WINED3D_OK;
2102 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2104 *ppD3D= This->wineD3D;
2105 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2106 IWineD3D_AddRef(*ppD3D);
2107 return WINED3D_OK;
2110 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2111 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2112 * into the video ram as possible and seeing how many fit
2113 * you can also get the correct initial value from nvidia and ATI's driver via X
2114 * texture memory is video memory + AGP memory
2115 *******************/
2116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2117 static BOOL showfixmes = TRUE;
2118 if (showfixmes) {
2119 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2120 (wined3d_settings.emulated_textureram/(1024*1024)),
2121 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2122 showfixmes = FALSE;
2124 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2125 (wined3d_settings.emulated_textureram/(1024*1024)),
2126 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2127 /* return simulated texture memory left */
2128 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2133 /*****
2134 * Get / Set FVF
2135 *****/
2136 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2139 /* Update the current state block */
2140 This->updateStateBlock->changed.fvf = TRUE;
2141 This->updateStateBlock->set.fvf = TRUE;
2143 if(This->updateStateBlock->fvf == fvf) {
2144 TRACE("Application is setting the old fvf over, nothing to do\n");
2145 return WINED3D_OK;
2148 This->updateStateBlock->fvf = fvf;
2149 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2151 return WINED3D_OK;
2155 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2157 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2158 *pfvf = This->stateBlock->fvf;
2159 return WINED3D_OK;
2162 /*****
2163 * Get / Set Stream Source
2164 *****/
2165 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2167 IWineD3DVertexBuffer *oldSrc;
2169 if (StreamNumber >= MAX_STREAMS) {
2170 WARN("Stream out of range %d\n", StreamNumber);
2171 return WINED3DERR_INVALIDCALL;
2174 oldSrc = This->stateBlock->streamSource[StreamNumber];
2175 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2177 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2178 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2180 if(oldSrc == pStreamData &&
2181 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2182 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2183 TRACE("Application is setting the old values over, nothing to do\n");
2184 return WINED3D_OK;
2187 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2188 if (pStreamData) {
2189 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2190 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2193 /* Handle recording of state blocks */
2194 if (This->isRecordingState) {
2195 TRACE("Recording... not performing anything\n");
2196 return WINED3D_OK;
2199 /* Need to do a getParent and pass the reffs up */
2200 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2201 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2202 so for now, just count internally */
2203 if (pStreamData != NULL) {
2204 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2205 InterlockedIncrement(&vbImpl->bindCount);
2207 if (oldSrc != NULL) {
2208 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2213 return WINED3D_OK;
2216 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2219 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2220 This->stateBlock->streamSource[StreamNumber],
2221 This->stateBlock->streamOffset[StreamNumber],
2222 This->stateBlock->streamStride[StreamNumber]);
2224 if (StreamNumber >= MAX_STREAMS) {
2225 WARN("Stream out of range %d\n", StreamNumber);
2226 return WINED3DERR_INVALIDCALL;
2228 *pStream = This->stateBlock->streamSource[StreamNumber];
2229 *pStride = This->stateBlock->streamStride[StreamNumber];
2230 if (pOffset) {
2231 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2234 if (*pStream != NULL) {
2235 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2237 return WINED3D_OK;
2240 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2242 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2243 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2245 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2246 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2248 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2249 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2250 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2252 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2253 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2257 return WINED3D_OK;
2260 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2263 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2264 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2266 TRACE("(%p) : returning %d\n", This, *Divider);
2268 return WINED3D_OK;
2271 /*****
2272 * Get / Set & Multiply Transform
2273 *****/
2274 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2277 /* Most of this routine, comments included copied from ddraw tree initially: */
2278 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2280 /* Handle recording of state blocks */
2281 if (This->isRecordingState) {
2282 TRACE("Recording... not performing anything\n");
2283 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2284 This->updateStateBlock->set.transform[d3dts] = TRUE;
2285 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2286 return WINED3D_OK;
2290 * If the new matrix is the same as the current one,
2291 * we cut off any further processing. this seems to be a reasonable
2292 * optimization because as was noticed, some apps (warcraft3 for example)
2293 * tend towards setting the same matrix repeatedly for some reason.
2295 * From here on we assume that the new matrix is different, wherever it matters.
2297 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2298 TRACE("The app is setting the same matrix over again\n");
2299 return WINED3D_OK;
2300 } else {
2301 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2305 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2306 where ViewMat = Camera space, WorldMat = world space.
2308 In OpenGL, camera and world space is combined into GL_MODELVIEW
2309 matrix. The Projection matrix stay projection matrix.
2312 /* Capture the times we can just ignore the change for now */
2313 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2314 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2315 /* Handled by the state manager */
2318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2319 return WINED3D_OK;
2322 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2324 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2325 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2326 return WINED3D_OK;
2329 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2330 WINED3DMATRIX *mat = NULL;
2331 WINED3DMATRIX temp;
2333 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2334 * below means it will be recorded in a state block change, but it
2335 * works regardless where it is recorded.
2336 * If this is found to be wrong, change to StateBlock.
2338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2339 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2341 if (State < HIGHEST_TRANSFORMSTATE)
2343 mat = &This->updateStateBlock->transforms[State];
2344 } else {
2345 FIXME("Unhandled transform state!!\n");
2348 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2350 /* Apply change via set transform - will reapply to eg. lights this way */
2351 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2354 /*****
2355 * Get / Set Light
2356 *****/
2357 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2358 you can reference any indexes you want as long as that number max are enabled at any
2359 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2360 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2361 but when recording, just build a chain pretty much of commands to be replayed. */
2363 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2364 float rho;
2365 PLIGHTINFOEL *object = NULL;
2366 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2367 struct list *e;
2369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2370 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2372 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2373 * the gl driver.
2375 if(!pLight) {
2376 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2377 return WINED3DERR_INVALIDCALL;
2380 switch(pLight->Type) {
2381 case WINED3DLIGHT_POINT:
2382 case WINED3DLIGHT_SPOT:
2383 case WINED3DLIGHT_PARALLELPOINT:
2384 case WINED3DLIGHT_GLSPOT:
2385 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2386 * most wanted
2388 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2389 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2390 return WINED3DERR_INVALIDCALL;
2392 break;
2394 case WINED3DLIGHT_DIRECTIONAL:
2395 /* Ignores attenuation */
2396 break;
2398 default:
2399 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2400 return WINED3DERR_INVALIDCALL;
2403 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2404 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2405 if(object->OriginalIndex == Index) break;
2406 object = NULL;
2409 if(!object) {
2410 TRACE("Adding new light\n");
2411 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2412 if(!object) {
2413 ERR("Out of memory error when allocating a light\n");
2414 return E_OUTOFMEMORY;
2416 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2417 object->glIndex = -1;
2418 object->OriginalIndex = Index;
2419 object->changed = TRUE;
2422 /* Initialize the object */
2423 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,
2424 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2425 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2426 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2427 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2428 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2429 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2431 /* Save away the information */
2432 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2434 switch (pLight->Type) {
2435 case WINED3DLIGHT_POINT:
2436 /* Position */
2437 object->lightPosn[0] = pLight->Position.x;
2438 object->lightPosn[1] = pLight->Position.y;
2439 object->lightPosn[2] = pLight->Position.z;
2440 object->lightPosn[3] = 1.0f;
2441 object->cutoff = 180.0f;
2442 /* FIXME: Range */
2443 break;
2445 case WINED3DLIGHT_DIRECTIONAL:
2446 /* Direction */
2447 object->lightPosn[0] = -pLight->Direction.x;
2448 object->lightPosn[1] = -pLight->Direction.y;
2449 object->lightPosn[2] = -pLight->Direction.z;
2450 object->lightPosn[3] = 0.0;
2451 object->exponent = 0.0f;
2452 object->cutoff = 180.0f;
2453 break;
2455 case WINED3DLIGHT_SPOT:
2456 /* Position */
2457 object->lightPosn[0] = pLight->Position.x;
2458 object->lightPosn[1] = pLight->Position.y;
2459 object->lightPosn[2] = pLight->Position.z;
2460 object->lightPosn[3] = 1.0;
2462 /* Direction */
2463 object->lightDirn[0] = pLight->Direction.x;
2464 object->lightDirn[1] = pLight->Direction.y;
2465 object->lightDirn[2] = pLight->Direction.z;
2466 object->lightDirn[3] = 1.0;
2469 * opengl-ish and d3d-ish spot lights use too different models for the
2470 * light "intensity" as a function of the angle towards the main light direction,
2471 * so we only can approximate very roughly.
2472 * however spot lights are rather rarely used in games (if ever used at all).
2473 * furthermore if still used, probably nobody pays attention to such details.
2475 if (pLight->Falloff == 0) {
2476 rho = 6.28f;
2477 } else {
2478 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2480 if (rho < 0.0001) rho = 0.0001f;
2481 object->exponent = -0.3/log(cos(rho/2));
2482 if (object->exponent > 128.0) {
2483 object->exponent = 128.0;
2485 object->cutoff = pLight->Phi*90/M_PI;
2487 /* FIXME: Range */
2488 break;
2490 default:
2491 FIXME("Unrecognized light type %d\n", pLight->Type);
2494 /* Update the live definitions if the light is currently assigned a glIndex */
2495 if (object->glIndex != -1 && !This->isRecordingState) {
2496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2498 return WINED3D_OK;
2501 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2502 PLIGHTINFOEL *lightInfo = NULL;
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2505 struct list *e;
2506 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2508 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2509 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2510 if(lightInfo->OriginalIndex == Index) break;
2511 lightInfo = NULL;
2514 if (lightInfo == NULL) {
2515 TRACE("Light information requested but light not defined\n");
2516 return WINED3DERR_INVALIDCALL;
2519 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2520 return WINED3D_OK;
2523 /*****
2524 * Get / Set Light Enable
2525 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2526 *****/
2527 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2528 PLIGHTINFOEL *lightInfo = NULL;
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2531 struct list *e;
2532 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2534 /* Tests show true = 128...not clear why */
2535 Enable = Enable? 128: 0;
2537 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2538 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2539 if(lightInfo->OriginalIndex == Index) break;
2540 lightInfo = NULL;
2542 TRACE("Found light: %p\n", lightInfo);
2544 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2545 if (lightInfo == NULL) {
2547 TRACE("Light enabled requested but light not defined, so defining one!\n");
2548 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2550 /* Search for it again! Should be fairly quick as near head of list */
2551 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2552 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2553 if(lightInfo->OriginalIndex == Index) break;
2554 lightInfo = NULL;
2556 if (lightInfo == NULL) {
2557 FIXME("Adding default lights has failed dismally\n");
2558 return WINED3DERR_INVALIDCALL;
2562 lightInfo->enabledChanged = TRUE;
2563 if(!Enable) {
2564 if(lightInfo->glIndex != -1) {
2565 if(!This->isRecordingState) {
2566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2569 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2570 lightInfo->glIndex = -1;
2571 } else {
2572 TRACE("Light already disabled, nothing to do\n");
2574 } else {
2575 if (lightInfo->glIndex != -1) {
2576 /* nop */
2577 TRACE("Nothing to do as light was enabled\n");
2578 } else {
2579 int i;
2580 /* Find a free gl light */
2581 for(i = 0; i < This->maxConcurrentLights; i++) {
2582 if(This->stateBlock->activeLights[i] == NULL) {
2583 This->stateBlock->activeLights[i] = lightInfo;
2584 lightInfo->glIndex = i;
2585 break;
2588 if(lightInfo->glIndex == -1) {
2589 ERR("Too many concurrently active lights\n");
2590 return WINED3DERR_INVALIDCALL;
2593 /* i == lightInfo->glIndex */
2594 if(!This->isRecordingState) {
2595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2600 return WINED3D_OK;
2603 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2605 PLIGHTINFOEL *lightInfo = NULL;
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 struct list *e;
2608 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2609 TRACE("(%p) : for idx(%d)\n", This, Index);
2611 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2612 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2613 if(lightInfo->OriginalIndex == Index) break;
2614 lightInfo = NULL;
2617 if (lightInfo == NULL) {
2618 TRACE("Light enabled state requested but light not defined\n");
2619 return WINED3DERR_INVALIDCALL;
2621 /* true is 128 according to SetLightEnable */
2622 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2623 return WINED3D_OK;
2626 /*****
2627 * Get / Set Clip Planes
2628 *****/
2629 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2631 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2633 /* Validate Index */
2634 if (Index >= GL_LIMITS(clipplanes)) {
2635 TRACE("Application has requested clipplane this device doesn't support\n");
2636 return WINED3DERR_INVALIDCALL;
2639 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2640 This->updateStateBlock->set.clipplane[Index] = TRUE;
2642 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2643 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2644 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2645 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2646 TRACE("Application is setting old values over, nothing to do\n");
2647 return WINED3D_OK;
2650 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2651 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2652 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2653 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2655 /* Handle recording of state blocks */
2656 if (This->isRecordingState) {
2657 TRACE("Recording... not performing anything\n");
2658 return WINED3D_OK;
2661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2663 return WINED3D_OK;
2666 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2668 TRACE("(%p) : for idx %d\n", This, Index);
2670 /* Validate Index */
2671 if (Index >= GL_LIMITS(clipplanes)) {
2672 TRACE("Application has requested clipplane this device doesn't support\n");
2673 return WINED3DERR_INVALIDCALL;
2676 pPlane[0] = This->stateBlock->clipplane[Index][0];
2677 pPlane[1] = This->stateBlock->clipplane[Index][1];
2678 pPlane[2] = This->stateBlock->clipplane[Index][2];
2679 pPlane[3] = This->stateBlock->clipplane[Index][3];
2680 return WINED3D_OK;
2683 /*****
2684 * Get / Set Clip Plane Status
2685 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2686 *****/
2687 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 FIXME("(%p) : stub\n", This);
2690 if (NULL == pClipStatus) {
2691 return WINED3DERR_INVALIDCALL;
2693 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2694 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2695 return WINED3D_OK;
2698 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2700 FIXME("(%p) : stub\n", This);
2701 if (NULL == pClipStatus) {
2702 return WINED3DERR_INVALIDCALL;
2704 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2705 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2706 return WINED3D_OK;
2709 /*****
2710 * Get / Set Material
2711 *****/
2712 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2715 This->updateStateBlock->changed.material = TRUE;
2716 This->updateStateBlock->set.material = TRUE;
2717 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2719 /* Handle recording of state blocks */
2720 if (This->isRecordingState) {
2721 TRACE("Recording... not performing anything\n");
2722 return WINED3D_OK;
2725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2726 return WINED3D_OK;
2729 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2732 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2733 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2734 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2735 pMaterial->Ambient.b, pMaterial->Ambient.a);
2736 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2737 pMaterial->Specular.b, pMaterial->Specular.a);
2738 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2739 pMaterial->Emissive.b, pMaterial->Emissive.a);
2740 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2742 return WINED3D_OK;
2745 /*****
2746 * Get / Set Indices
2747 *****/
2748 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 IWineD3DIndexBuffer *oldIdxs;
2752 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2753 oldIdxs = This->updateStateBlock->pIndexData;
2755 This->updateStateBlock->changed.indices = TRUE;
2756 This->updateStateBlock->set.indices = TRUE;
2757 This->updateStateBlock->pIndexData = pIndexData;
2759 /* Handle recording of state blocks */
2760 if (This->isRecordingState) {
2761 TRACE("Recording... not performing anything\n");
2762 return WINED3D_OK;
2765 if(oldIdxs != pIndexData) {
2766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2768 return WINED3D_OK;
2771 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2774 *ppIndexData = This->stateBlock->pIndexData;
2776 /* up ref count on ppindexdata */
2777 if (*ppIndexData) {
2778 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2779 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2780 }else{
2781 TRACE("(%p) No index data set\n", This);
2783 TRACE("Returning %p\n", *ppIndexData);
2785 return WINED3D_OK;
2788 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2789 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2791 TRACE("(%p)->(%d)\n", This, BaseIndex);
2793 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2794 TRACE("Application is setting the old value over, nothing to do\n");
2795 return WINED3D_OK;
2798 This->updateStateBlock->baseVertexIndex = BaseIndex;
2800 if (This->isRecordingState) {
2801 TRACE("Recording... not performing anything\n");
2802 return WINED3D_OK;
2804 /* The base vertex index affects the stream sources */
2805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2806 return WINED3D_OK;
2809 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 TRACE("(%p) : base_index %p\n", This, base_index);
2813 *base_index = This->stateBlock->baseVertexIndex;
2815 TRACE("Returning %u\n", *base_index);
2817 return WINED3D_OK;
2820 /*****
2821 * Get / Set Viewports
2822 *****/
2823 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2826 TRACE("(%p)\n", This);
2827 This->updateStateBlock->changed.viewport = TRUE;
2828 This->updateStateBlock->set.viewport = TRUE;
2829 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2831 /* Handle recording of state blocks */
2832 if (This->isRecordingState) {
2833 TRACE("Recording... not performing anything\n");
2834 return WINED3D_OK;
2837 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2838 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2841 return WINED3D_OK;
2845 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2847 TRACE("(%p)\n", This);
2848 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2849 return WINED3D_OK;
2852 /*****
2853 * Get / Set Render States
2854 * TODO: Verify against dx9 definitions
2855 *****/
2856 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 DWORD oldValue = This->stateBlock->renderState[State];
2861 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2863 This->updateStateBlock->changed.renderState[State] = TRUE;
2864 This->updateStateBlock->set.renderState[State] = TRUE;
2865 This->updateStateBlock->renderState[State] = Value;
2867 /* Handle recording of state blocks */
2868 if (This->isRecordingState) {
2869 TRACE("Recording... not performing anything\n");
2870 return WINED3D_OK;
2873 /* Compared here and not before the assignment to allow proper stateblock recording */
2874 if(Value == oldValue) {
2875 TRACE("Application is setting the old value over, nothing to do\n");
2876 } else {
2877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2880 return WINED3D_OK;
2883 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2885 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2886 *pValue = This->stateBlock->renderState[State];
2887 return WINED3D_OK;
2890 /*****
2891 * Get / Set Sampler States
2892 * TODO: Verify against dx9 definitions
2893 *****/
2895 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 DWORD oldValue;
2899 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2900 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2902 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2903 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2907 * SetSampler is designed to allow for more than the standard up to 8 textures
2908 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2909 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2911 * http://developer.nvidia.com/object/General_FAQ.html#t6
2913 * There are two new settings for GForce
2914 * the sampler one:
2915 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2916 * and the texture one:
2917 * GL_MAX_TEXTURE_COORDS_ARB.
2918 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2919 ******************/
2921 oldValue = This->stateBlock->samplerState[Sampler][Type];
2922 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2923 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2924 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2926 /* Handle recording of state blocks */
2927 if (This->isRecordingState) {
2928 TRACE("Recording... not performing anything\n");
2929 return WINED3D_OK;
2932 if(oldValue == Value) {
2933 TRACE("Application is setting the old value over, nothing to do\n");
2934 return WINED3D_OK;
2937 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2939 return WINED3D_OK;
2942 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2945 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2946 This, Sampler, debug_d3dsamplerstate(Type), Type);
2948 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2949 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2952 *Value = This->stateBlock->samplerState[Sampler][Type];
2953 TRACE("(%p) : Returning %#x\n", This, *Value);
2955 return WINED3D_OK;
2958 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2961 This->updateStateBlock->set.scissorRect = TRUE;
2962 This->updateStateBlock->changed.scissorRect = TRUE;
2963 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2964 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2965 return WINED3D_OK;
2967 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2969 if(This->isRecordingState) {
2970 TRACE("Recording... not performing anything\n");
2971 return WINED3D_OK;
2974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2976 return WINED3D_OK;
2979 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2983 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2984 return WINED3D_OK;
2987 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2989 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2991 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2993 This->updateStateBlock->vertexDecl = pDecl;
2994 This->updateStateBlock->changed.vertexDecl = TRUE;
2995 This->updateStateBlock->set.vertexDecl = TRUE;
2997 if (This->isRecordingState) {
2998 TRACE("Recording... not performing anything\n");
2999 return WINED3D_OK;
3000 } else if(pDecl == oldDecl) {
3001 /* Checked after the assignment to allow proper stateblock recording */
3002 TRACE("Application is setting the old declaration over, nothing to do\n");
3003 return WINED3D_OK;
3006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3007 return WINED3D_OK;
3010 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3015 *ppDecl = This->stateBlock->vertexDecl;
3016 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3017 return WINED3D_OK;
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3024 This->updateStateBlock->vertexShader = pShader;
3025 This->updateStateBlock->changed.vertexShader = TRUE;
3026 This->updateStateBlock->set.vertexShader = TRUE;
3028 if (This->isRecordingState) {
3029 TRACE("Recording... not performing anything\n");
3030 return WINED3D_OK;
3031 } else if(oldShader == pShader) {
3032 /* Checked here to allow proper stateblock recording */
3033 TRACE("App is setting the old shader over, nothing to do\n");
3034 return WINED3D_OK;
3037 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3041 return WINED3D_OK;
3044 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3047 if (NULL == ppShader) {
3048 return WINED3DERR_INVALIDCALL;
3050 *ppShader = This->stateBlock->vertexShader;
3051 if( NULL != *ppShader)
3052 IWineD3DVertexShader_AddRef(*ppShader);
3054 TRACE("(%p) : returning %p\n", This, *ppShader);
3055 return WINED3D_OK;
3058 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3059 IWineD3DDevice *iface,
3060 UINT start,
3061 CONST BOOL *srcData,
3062 UINT count) {
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 int i, cnt = min(count, MAX_CONST_B - start);
3067 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3068 iface, srcData, start, count);
3070 if (srcData == NULL || cnt < 0)
3071 return WINED3DERR_INVALIDCALL;
3073 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3074 for (i = 0; i < cnt; i++)
3075 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3077 for (i = start; i < cnt + start; ++i) {
3078 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3079 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3084 return WINED3D_OK;
3087 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3088 IWineD3DDevice *iface,
3089 UINT start,
3090 BOOL *dstData,
3091 UINT count) {
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 int cnt = min(count, MAX_CONST_B - start);
3096 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3097 iface, dstData, start, count);
3099 if (dstData == NULL || cnt < 0)
3100 return WINED3DERR_INVALIDCALL;
3102 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3103 return WINED3D_OK;
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3107 IWineD3DDevice *iface,
3108 UINT start,
3109 CONST int *srcData,
3110 UINT count) {
3112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3113 int i, cnt = min(count, MAX_CONST_I - start);
3115 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3116 iface, srcData, start, count);
3118 if (srcData == NULL || cnt < 0)
3119 return WINED3DERR_INVALIDCALL;
3121 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3122 for (i = 0; i < cnt; i++)
3123 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3124 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3126 for (i = start; i < cnt + start; ++i) {
3127 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3128 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3133 return WINED3D_OK;
3136 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3137 IWineD3DDevice *iface,
3138 UINT start,
3139 int *dstData,
3140 UINT count) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 int cnt = min(count, MAX_CONST_I - start);
3145 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3146 iface, dstData, start, count);
3148 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3149 return WINED3DERR_INVALIDCALL;
3151 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3152 return WINED3D_OK;
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3156 IWineD3DDevice *iface,
3157 UINT start,
3158 CONST float *srcData,
3159 UINT count) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 int i;
3164 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3165 iface, srcData, start, count);
3167 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3168 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3169 return WINED3DERR_INVALIDCALL;
3171 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3172 if(TRACE_ON(d3d)) {
3173 for (i = 0; i < count; i++)
3174 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3175 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3178 for (i = start; i < count + start; ++i) {
3179 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3180 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3181 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3182 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3183 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3185 ptr->idx[ptr->count++] = i;
3186 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3188 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3193 return WINED3D_OK;
3196 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3197 IWineD3DDevice *iface,
3198 UINT start,
3199 float *dstData,
3200 UINT count) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3205 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3206 iface, dstData, start, count);
3208 if (dstData == NULL || cnt < 0)
3209 return WINED3DERR_INVALIDCALL;
3211 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3212 return WINED3D_OK;
3215 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3216 DWORD i;
3217 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3222 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3223 int i = This->rev_tex_unit_map[unit];
3224 int j = This->texUnitMap[stage];
3226 This->texUnitMap[stage] = unit;
3227 if (i != -1 && i != stage) {
3228 This->texUnitMap[i] = -1;
3231 This->rev_tex_unit_map[unit] = stage;
3232 if (j != -1 && j != unit) {
3233 This->rev_tex_unit_map[j] = -1;
3237 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3238 int i;
3240 for (i = 0; i < MAX_TEXTURES; ++i) {
3241 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3242 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3243 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3244 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3245 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3246 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3247 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3248 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3250 if (color_op == WINED3DTOP_DISABLE) {
3251 /* Not used, and disable higher stages */
3252 while (i < MAX_TEXTURES) {
3253 This->fixed_function_usage_map[i] = FALSE;
3254 ++i;
3256 break;
3259 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3260 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3261 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3262 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3263 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3264 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3265 This->fixed_function_usage_map[i] = TRUE;
3266 } else {
3267 This->fixed_function_usage_map[i] = FALSE;
3270 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3271 This->fixed_function_usage_map[i+1] = TRUE;
3276 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3277 int i, tex;
3279 device_update_fixed_function_usage_map(This);
3281 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3282 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3283 if (!This->fixed_function_usage_map[i]) continue;
3285 if (This->texUnitMap[i] != i) {
3286 device_map_stage(This, i, i);
3287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3288 markTextureStagesDirty(This, i);
3291 return;
3294 /* Now work out the mapping */
3295 tex = 0;
3296 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3297 if (!This->fixed_function_usage_map[i]) continue;
3299 if (This->texUnitMap[i] != tex) {
3300 device_map_stage(This, i, tex);
3301 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3302 markTextureStagesDirty(This, i);
3305 ++tex;
3309 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3310 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3311 int i;
3313 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3314 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3315 device_map_stage(This, i, i);
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3317 if (i < MAX_TEXTURES) {
3318 markTextureStagesDirty(This, i);
3324 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3325 int current_mapping = This->rev_tex_unit_map[unit];
3327 if (current_mapping == -1) {
3328 /* Not currently used */
3329 return TRUE;
3332 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3333 /* Used by a fragment sampler */
3335 if (!pshader_sampler_tokens) {
3336 /* No pixel shader, check fixed function */
3337 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3340 /* Pixel shader, check the shader's sampler map */
3341 return !pshader_sampler_tokens[current_mapping];
3344 /* Used by a vertex sampler */
3345 return !vshader_sampler_tokens[current_mapping];
3348 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3349 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3350 DWORD *pshader_sampler_tokens = NULL;
3351 int start = GL_LIMITS(combined_samplers) - 1;
3352 int i;
3354 if (ps) {
3355 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3357 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3358 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3359 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3362 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3363 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3364 if (vshader_sampler_tokens[i]) {
3365 if (This->texUnitMap[vsampler_idx] != -1) {
3366 /* Already mapped somewhere */
3367 continue;
3370 while (start >= 0) {
3371 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3372 device_map_stage(This, vsampler_idx, start);
3373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3375 --start;
3376 break;
3379 --start;
3385 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3386 BOOL vs = use_vs(This);
3387 BOOL ps = use_ps(This);
3389 * Rules are:
3390 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3391 * that would be really messy and require shader recompilation
3392 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3393 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3395 if (ps) {
3396 device_map_psamplers(This);
3397 } else {
3398 device_map_fixed_function_samplers(This);
3401 if (vs) {
3402 device_map_vsamplers(This, ps);
3406 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3408 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3409 This->updateStateBlock->pixelShader = pShader;
3410 This->updateStateBlock->changed.pixelShader = TRUE;
3411 This->updateStateBlock->set.pixelShader = TRUE;
3413 /* Handle recording of state blocks */
3414 if (This->isRecordingState) {
3415 TRACE("Recording... not performing anything\n");
3418 if (This->isRecordingState) {
3419 TRACE("Recording... not performing anything\n");
3420 return WINED3D_OK;
3423 if(pShader == oldShader) {
3424 TRACE("App is setting the old pixel shader over, nothing to do\n");
3425 return WINED3D_OK;
3428 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3431 return WINED3D_OK;
3434 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 if (NULL == ppShader) {
3438 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3439 return WINED3DERR_INVALIDCALL;
3442 *ppShader = This->stateBlock->pixelShader;
3443 if (NULL != *ppShader) {
3444 IWineD3DPixelShader_AddRef(*ppShader);
3446 TRACE("(%p) : returning %p\n", This, *ppShader);
3447 return WINED3D_OK;
3450 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3451 IWineD3DDevice *iface,
3452 UINT start,
3453 CONST BOOL *srcData,
3454 UINT count) {
3456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3457 int i, cnt = min(count, MAX_CONST_B - start);
3459 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3460 iface, srcData, start, count);
3462 if (srcData == NULL || cnt < 0)
3463 return WINED3DERR_INVALIDCALL;
3465 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3466 for (i = 0; i < cnt; i++)
3467 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3469 for (i = start; i < cnt + start; ++i) {
3470 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3471 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3476 return WINED3D_OK;
3479 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3480 IWineD3DDevice *iface,
3481 UINT start,
3482 BOOL *dstData,
3483 UINT count) {
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3486 int cnt = min(count, MAX_CONST_B - start);
3488 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3489 iface, dstData, start, count);
3491 if (dstData == NULL || cnt < 0)
3492 return WINED3DERR_INVALIDCALL;
3494 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3495 return WINED3D_OK;
3498 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3499 IWineD3DDevice *iface,
3500 UINT start,
3501 CONST int *srcData,
3502 UINT count) {
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505 int i, cnt = min(count, MAX_CONST_I - start);
3507 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3508 iface, srcData, start, count);
3510 if (srcData == NULL || cnt < 0)
3511 return WINED3DERR_INVALIDCALL;
3513 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3514 for (i = 0; i < cnt; i++)
3515 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3516 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3518 for (i = start; i < cnt + start; ++i) {
3519 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3520 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3525 return WINED3D_OK;
3528 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3529 IWineD3DDevice *iface,
3530 UINT start,
3531 int *dstData,
3532 UINT count) {
3534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3535 int cnt = min(count, MAX_CONST_I - start);
3537 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3538 iface, dstData, start, count);
3540 if (dstData == NULL || cnt < 0)
3541 return WINED3DERR_INVALIDCALL;
3543 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3544 return WINED3D_OK;
3547 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3548 IWineD3DDevice *iface,
3549 UINT start,
3550 CONST float *srcData,
3551 UINT count) {
3553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3554 int i;
3556 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3557 iface, srcData, start, count);
3559 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3560 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3561 return WINED3DERR_INVALIDCALL;
3563 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3564 if(TRACE_ON(d3d)) {
3565 for (i = 0; i < count; i++)
3566 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3567 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3570 for (i = start; i < count + start; ++i) {
3571 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3572 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3573 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3574 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3575 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3577 ptr->idx[ptr->count++] = i;
3578 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3580 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3585 return WINED3D_OK;
3588 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3589 IWineD3DDevice *iface,
3590 UINT start,
3591 float *dstData,
3592 UINT count) {
3594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3595 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3597 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3598 iface, dstData, start, count);
3600 if (dstData == NULL || cnt < 0)
3601 return WINED3DERR_INVALIDCALL;
3603 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3604 return WINED3D_OK;
3607 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3608 static HRESULT
3609 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3610 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3611 unsigned int i;
3612 DWORD DestFVF = dest->fvf;
3613 WINED3DVIEWPORT vp;
3614 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3615 BOOL doClip;
3616 int numTextures;
3618 if (lpStrideData->u.s.normal.lpData) {
3619 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3622 if (lpStrideData->u.s.position.lpData == NULL) {
3623 ERR("Source has no position mask\n");
3624 return WINED3DERR_INVALIDCALL;
3627 /* We might access VBOs from this code, so hold the lock */
3628 ENTER_GL();
3630 if (dest->resource.allocatedMemory == NULL) {
3631 /* This may happen if we do direct locking into a vbo. Unlikely,
3632 * but theoretically possible(ddraw processvertices test)
3634 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3635 if(!dest->resource.allocatedMemory) {
3636 LEAVE_GL();
3637 ERR("Out of memory\n");
3638 return E_OUTOFMEMORY;
3640 if(dest->vbo) {
3641 void *src;
3642 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3643 checkGLcall("glBindBufferARB");
3644 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3645 if(src) {
3646 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3648 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3649 checkGLcall("glUnmapBufferARB");
3653 /* Get a pointer into the destination vbo(create one if none exists) and
3654 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3656 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3657 CreateVBO(dest);
3660 if(dest->vbo) {
3661 unsigned char extrabytes = 0;
3662 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3663 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3664 * this may write 4 extra bytes beyond the area that should be written
3666 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3667 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3668 if(!dest_conv_addr) {
3669 ERR("Out of memory\n");
3670 /* Continue without storing converted vertices */
3672 dest_conv = dest_conv_addr;
3675 /* Should I clip?
3676 * a) WINED3DRS_CLIPPING is enabled
3677 * b) WINED3DVOP_CLIP is passed
3679 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3680 static BOOL warned = FALSE;
3682 * The clipping code is not quite correct. Some things need
3683 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3684 * so disable clipping for now.
3685 * (The graphics in Half-Life are broken, and my processvertices
3686 * test crashes with IDirect3DDevice3)
3687 doClip = TRUE;
3689 doClip = FALSE;
3690 if(!warned) {
3691 warned = TRUE;
3692 FIXME("Clipping is broken and disabled for now\n");
3694 } else doClip = FALSE;
3695 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3697 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3698 WINED3DTS_VIEW,
3699 &view_mat);
3700 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3701 WINED3DTS_PROJECTION,
3702 &proj_mat);
3703 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3704 WINED3DTS_WORLDMATRIX(0),
3705 &world_mat);
3707 TRACE("View mat:\n");
3708 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);
3709 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);
3710 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);
3711 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);
3713 TRACE("Proj mat:\n");
3714 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);
3715 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);
3716 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);
3717 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);
3719 TRACE("World mat:\n");
3720 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);
3721 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);
3722 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);
3723 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);
3725 /* Get the viewport */
3726 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3727 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3728 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3730 multiply_matrix(&mat,&view_mat,&world_mat);
3731 multiply_matrix(&mat,&proj_mat,&mat);
3733 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3735 for (i = 0; i < dwCount; i+= 1) {
3736 unsigned int tex_index;
3738 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3739 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3740 /* The position first */
3741 float *p =
3742 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3743 float x, y, z, rhw;
3744 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3746 /* Multiplication with world, view and projection matrix */
3747 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);
3748 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);
3749 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);
3750 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);
3752 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3754 /* WARNING: The following things are taken from d3d7 and were not yet checked
3755 * against d3d8 or d3d9!
3758 /* Clipping conditions: From
3759 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3761 * A vertex is clipped if it does not match the following requirements
3762 * -rhw < x <= rhw
3763 * -rhw < y <= rhw
3764 * 0 < z <= rhw
3765 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3767 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3768 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3772 if( !doClip ||
3773 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3774 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3775 ( rhw > eps ) ) ) {
3777 /* "Normal" viewport transformation (not clipped)
3778 * 1) The values are divided by rhw
3779 * 2) The y axis is negative, so multiply it with -1
3780 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3781 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3782 * 4) Multiply x with Width/2 and add Width/2
3783 * 5) The same for the height
3784 * 6) Add the viewpoint X and Y to the 2D coordinates and
3785 * The minimum Z value to z
3786 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3788 * Well, basically it's simply a linear transformation into viewport
3789 * coordinates
3792 x /= rhw;
3793 y /= rhw;
3794 z /= rhw;
3796 y *= -1;
3798 x *= vp.Width / 2;
3799 y *= vp.Height / 2;
3800 z *= vp.MaxZ - vp.MinZ;
3802 x += vp.Width / 2 + vp.X;
3803 y += vp.Height / 2 + vp.Y;
3804 z += vp.MinZ;
3806 rhw = 1 / rhw;
3807 } else {
3808 /* That vertex got clipped
3809 * Contrary to OpenGL it is not dropped completely, it just
3810 * undergoes a different calculation.
3812 TRACE("Vertex got clipped\n");
3813 x += rhw;
3814 y += rhw;
3816 x /= 2;
3817 y /= 2;
3819 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3820 * outside of the main vertex buffer memory. That needs some more
3821 * investigation...
3825 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3828 ( (float *) dest_ptr)[0] = x;
3829 ( (float *) dest_ptr)[1] = y;
3830 ( (float *) dest_ptr)[2] = z;
3831 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3833 dest_ptr += 3 * sizeof(float);
3835 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3836 dest_ptr += sizeof(float);
3839 if(dest_conv) {
3840 float w = 1 / rhw;
3841 ( (float *) dest_conv)[0] = x * w;
3842 ( (float *) dest_conv)[1] = y * w;
3843 ( (float *) dest_conv)[2] = z * w;
3844 ( (float *) dest_conv)[3] = w;
3846 dest_conv += 3 * sizeof(float);
3848 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3849 dest_conv += sizeof(float);
3853 if (DestFVF & WINED3DFVF_PSIZE) {
3854 dest_ptr += sizeof(DWORD);
3855 if(dest_conv) dest_conv += sizeof(DWORD);
3857 if (DestFVF & WINED3DFVF_NORMAL) {
3858 float *normal =
3859 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3860 /* AFAIK this should go into the lighting information */
3861 FIXME("Didn't expect the destination to have a normal\n");
3862 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3863 if(dest_conv) {
3864 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3868 if (DestFVF & WINED3DFVF_DIFFUSE) {
3869 DWORD *color_d =
3870 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3871 if(!color_d) {
3872 static BOOL warned = FALSE;
3874 if(!warned) {
3875 ERR("No diffuse color in source, but destination has one\n");
3876 warned = TRUE;
3879 *( (DWORD *) dest_ptr) = 0xffffffff;
3880 dest_ptr += sizeof(DWORD);
3882 if(dest_conv) {
3883 *( (DWORD *) dest_conv) = 0xffffffff;
3884 dest_conv += sizeof(DWORD);
3887 else {
3888 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3889 if(dest_conv) {
3890 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3891 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3892 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3893 dest_conv += sizeof(DWORD);
3898 if (DestFVF & WINED3DFVF_SPECULAR) {
3899 /* What's the color value in the feedback buffer? */
3900 DWORD *color_s =
3901 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3902 if(!color_s) {
3903 static BOOL warned = FALSE;
3905 if(!warned) {
3906 ERR("No specular color in source, but destination has one\n");
3907 warned = TRUE;
3910 *( (DWORD *) dest_ptr) = 0xFF000000;
3911 dest_ptr += sizeof(DWORD);
3913 if(dest_conv) {
3914 *( (DWORD *) dest_conv) = 0xFF000000;
3915 dest_conv += sizeof(DWORD);
3918 else {
3919 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3920 if(dest_conv) {
3921 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3922 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3923 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3924 dest_conv += sizeof(DWORD);
3929 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3930 float *tex_coord =
3931 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3932 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3933 if(!tex_coord) {
3934 ERR("No source texture, but destination requests one\n");
3935 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3936 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3938 else {
3939 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3940 if(dest_conv) {
3941 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3947 if(dest_conv) {
3948 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3949 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3950 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3951 dwCount * get_flexible_vertex_size(DestFVF),
3952 dest_conv_addr));
3953 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3954 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3957 LEAVE_GL();
3959 return WINED3D_OK;
3961 #undef copy_and_next
3963 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3965 WineDirect3DVertexStridedData strided;
3966 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3967 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3969 if(pVertexDecl) {
3970 ERR("Output vertex declaration not implemented yet\n");
3973 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3974 * and this call is quite performance critical, so don't call needlessly
3976 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3977 ENTER_GL();
3978 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3979 LEAVE_GL();
3982 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3983 * control the streamIsUP flag, thus restore it afterwards.
3985 This->stateBlock->streamIsUP = FALSE;
3986 memset(&strided, 0, sizeof(strided));
3987 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3988 This->stateBlock->streamIsUP = streamWasUP;
3990 if(vbo || SrcStartIndex) {
3991 unsigned int i;
3992 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3993 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3995 * Also get the start index in, but only loop over all elements if there's something to add at all.
3997 #define FIXSRC(type) \
3998 if(strided.u.s.type.VBO) { \
3999 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4000 strided.u.s.type.VBO = 0; \
4001 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4002 ENTER_GL(); \
4003 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4004 vb->vbo = 0; \
4005 LEAVE_GL(); \
4007 if(strided.u.s.type.lpData) { \
4008 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4010 FIXSRC(position);
4011 FIXSRC(blendWeights);
4012 FIXSRC(blendMatrixIndices);
4013 FIXSRC(normal);
4014 FIXSRC(pSize);
4015 FIXSRC(diffuse);
4016 FIXSRC(specular);
4017 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4018 FIXSRC(texCoords[i]);
4020 FIXSRC(position2);
4021 FIXSRC(normal2);
4022 FIXSRC(tangent);
4023 FIXSRC(binormal);
4024 FIXSRC(tessFactor);
4025 FIXSRC(fog);
4026 FIXSRC(depth);
4027 FIXSRC(sample);
4028 #undef FIXSRC
4031 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4034 /*****
4035 * Get / Set Texture Stage States
4036 * TODO: Verify against dx9 definitions
4037 *****/
4038 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4040 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4042 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4044 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4046 if (Stage >= MAX_TEXTURES) {
4047 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4048 return WINED3D_OK;
4051 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4052 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4053 This->updateStateBlock->textureState[Stage][Type] = Value;
4055 if (This->isRecordingState) {
4056 TRACE("Recording... not performing anything\n");
4057 return WINED3D_OK;
4060 /* Checked after the assignments to allow proper stateblock recording */
4061 if(oldValue == Value) {
4062 TRACE("App is setting the old value over, nothing to do\n");
4063 return WINED3D_OK;
4066 if(Stage > This->stateBlock->lowest_disabled_stage &&
4067 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4068 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4069 * Changes in other states are important on disabled stages too
4071 return WINED3D_OK;
4074 if(Type == WINED3DTSS_COLOROP) {
4075 int i;
4077 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4078 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4079 * they have to be disabled
4081 * The current stage is dirtified below.
4083 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4084 TRACE("Additionally dirtifying stage %d\n", i);
4085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4087 This->stateBlock->lowest_disabled_stage = Stage;
4088 TRACE("New lowest disabled: %d\n", Stage);
4089 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4090 /* Previously disabled stage enabled. Stages above it may need enabling
4091 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4092 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4094 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4097 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4098 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4099 break;
4101 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4104 This->stateBlock->lowest_disabled_stage = i;
4105 TRACE("New lowest disabled: %d\n", i);
4107 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4108 /* TODO: Built a stage -> texture unit mapping for register combiners */
4112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4114 return WINED3D_OK;
4117 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4119 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4120 *pValue = This->updateStateBlock->textureState[Stage][Type];
4121 return WINED3D_OK;
4124 /*****
4125 * Get / Set Texture
4126 *****/
4127 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4129 IWineD3DBaseTexture *oldTexture;
4131 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4133 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4134 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4137 oldTexture = This->updateStateBlock->textures[Stage];
4139 if(pTexture != NULL) {
4140 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4142 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4143 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4144 return WINED3DERR_INVALIDCALL;
4146 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4149 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4150 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4152 This->updateStateBlock->set.textures[Stage] = TRUE;
4153 This->updateStateBlock->changed.textures[Stage] = TRUE;
4154 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4155 This->updateStateBlock->textures[Stage] = pTexture;
4157 /* Handle recording of state blocks */
4158 if (This->isRecordingState) {
4159 TRACE("Recording... not performing anything\n");
4160 return WINED3D_OK;
4163 if(oldTexture == pTexture) {
4164 TRACE("App is setting the same texture again, nothing to do\n");
4165 return WINED3D_OK;
4168 /** NOTE: MSDN says that setTexture increases the reference count,
4169 * and the the application must set the texture back to null (or have a leaky application),
4170 * This means we should pass the refcount up to the parent
4171 *******************************/
4172 if (NULL != This->updateStateBlock->textures[Stage]) {
4173 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4174 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4176 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4177 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4178 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4179 * so the COLOROP and ALPHAOP have to be dirtified.
4181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4184 if(bindCount == 1) {
4185 new->baseTexture.sampler = Stage;
4187 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4191 if (NULL != oldTexture) {
4192 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4193 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4195 IWineD3DBaseTexture_Release(oldTexture);
4196 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4197 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4201 if(bindCount && old->baseTexture.sampler == Stage) {
4202 int i;
4203 /* Have to do a search for the other sampler(s) where the texture is bound to
4204 * Shouldn't happen as long as apps bind a texture only to one stage
4206 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4207 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4208 if(This->updateStateBlock->textures[i] == oldTexture) {
4209 old->baseTexture.sampler = i;
4210 break;
4216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4218 return WINED3D_OK;
4221 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4224 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4226 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4227 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4230 *ppTexture=This->stateBlock->textures[Stage];
4231 if (*ppTexture)
4232 IWineD3DBaseTexture_AddRef(*ppTexture);
4234 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4236 return WINED3D_OK;
4239 /*****
4240 * Get Back Buffer
4241 *****/
4242 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4243 IWineD3DSurface **ppBackBuffer) {
4244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4245 IWineD3DSwapChain *swapChain;
4246 HRESULT hr;
4248 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4250 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4251 if (hr == WINED3D_OK) {
4252 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4253 IWineD3DSwapChain_Release(swapChain);
4254 } else {
4255 *ppBackBuffer = NULL;
4257 return hr;
4260 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4262 WARN("(%p) : stub, calling idirect3d for now\n", This);
4263 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4266 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4268 IWineD3DSwapChain *swapChain;
4269 HRESULT hr;
4271 if(iSwapChain > 0) {
4272 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4273 if (hr == WINED3D_OK) {
4274 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4275 IWineD3DSwapChain_Release(swapChain);
4276 } else {
4277 FIXME("(%p) Error getting display mode\n", This);
4279 } else {
4280 /* Don't read the real display mode,
4281 but return the stored mode instead. X11 can't change the color
4282 depth, and some apps are pretty angry if they SetDisplayMode from
4283 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4285 Also don't relay to the swapchain because with ddraw it's possible
4286 that there isn't a swapchain at all */
4287 pMode->Width = This->ddraw_width;
4288 pMode->Height = This->ddraw_height;
4289 pMode->Format = This->ddraw_format;
4290 pMode->RefreshRate = 0;
4291 hr = WINED3D_OK;
4294 return hr;
4297 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4299 TRACE("(%p)->(%p)\n", This, hWnd);
4301 if(This->ddraw_fullscreen) {
4302 if(This->ddraw_window && This->ddraw_window != hWnd) {
4303 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4305 if(hWnd && This->ddraw_window != hWnd) {
4306 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4310 This->ddraw_window = hWnd;
4311 return WINED3D_OK;
4314 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4316 TRACE("(%p)->(%p)\n", This, hWnd);
4318 *hWnd = This->ddraw_window;
4319 return WINED3D_OK;
4322 /*****
4323 * Stateblock related functions
4324 *****/
4326 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4328 IWineD3DStateBlockImpl *object;
4329 HRESULT temp_result;
4330 int i;
4332 TRACE("(%p)\n", This);
4334 if (This->isRecordingState) {
4335 return WINED3DERR_INVALIDCALL;
4338 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4339 if (NULL == object ) {
4340 FIXME("(%p)Error allocating memory for stateblock\n", This);
4341 return E_OUTOFMEMORY;
4343 TRACE("(%p) created object %p\n", This, object);
4344 object->wineD3DDevice= This;
4345 /** FIXME: object->parent = parent; **/
4346 object->parent = NULL;
4347 object->blockType = WINED3DSBT_ALL;
4348 object->ref = 1;
4349 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4351 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4352 list_init(&object->lightMap[i]);
4355 temp_result = allocate_shader_constants(object);
4356 if (WINED3D_OK != temp_result)
4357 return temp_result;
4359 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4360 This->updateStateBlock = object;
4361 This->isRecordingState = TRUE;
4363 TRACE("(%p) recording stateblock %p\n",This , object);
4364 return WINED3D_OK;
4367 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4370 if (!This->isRecordingState) {
4371 FIXME("(%p) not recording! returning error\n", This);
4372 *ppStateBlock = NULL;
4373 return WINED3DERR_INVALIDCALL;
4376 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4377 This->isRecordingState = FALSE;
4378 This->updateStateBlock = This->stateBlock;
4379 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4380 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4381 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4382 return WINED3D_OK;
4385 /*****
4386 * Scene related functions
4387 *****/
4388 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4389 /* At the moment we have no need for any functionality at the beginning
4390 of a scene */
4391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4392 TRACE("(%p)\n", This);
4394 if(This->inScene) {
4395 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4396 return WINED3DERR_INVALIDCALL;
4398 This->inScene = TRUE;
4399 return WINED3D_OK;
4402 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4404 TRACE("(%p)\n", This);
4406 if(!This->inScene) {
4407 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4408 return WINED3DERR_INVALIDCALL;
4411 ENTER_GL();
4412 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4413 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4415 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4416 glFlush();
4417 checkGLcall("glFlush");
4418 LEAVE_GL();
4420 This->inScene = FALSE;
4421 return WINED3D_OK;
4424 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4425 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4426 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4428 IWineD3DSwapChain *swapChain = NULL;
4429 int i;
4430 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4432 TRACE("(%p) Presenting the frame\n", This);
4434 for(i = 0 ; i < swapchains ; i ++) {
4436 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4437 TRACE("presentinng chain %d, %p\n", i, swapChain);
4438 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4439 IWineD3DSwapChain_Release(swapChain);
4442 return WINED3D_OK;
4445 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4446 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4448 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4450 GLbitfield glMask = 0;
4451 unsigned int i;
4452 CONST WINED3DRECT* curRect;
4454 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4455 Count, pRects, Flags, Color, Z, Stencil);
4457 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4458 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4459 /* TODO: What about depth stencil buffers without stencil bits? */
4460 return WINED3DERR_INVALIDCALL;
4463 ENTER_GL();
4464 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4465 * and not the last active one.
4468 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4469 apply_fbo_state(iface);
4472 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4474 if (Count > 0 && pRects) {
4475 curRect = pRects;
4476 } else {
4477 curRect = NULL;
4480 /* Only set the values up once, as they are not changing */
4481 if (Flags & WINED3DCLEAR_STENCIL) {
4482 glClearStencil(Stencil);
4483 checkGLcall("glClearStencil");
4484 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4485 glStencilMask(0xFFFFFFFF);
4488 if (Flags & WINED3DCLEAR_ZBUFFER) {
4489 glDepthMask(GL_TRUE);
4490 glClearDepth(Z);
4491 checkGLcall("glClearDepth");
4492 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4496 if (Flags & WINED3DCLEAR_TARGET) {
4497 TRACE("Clearing screen with glClear to color %x\n", Color);
4498 glClearColor(D3DCOLOR_R(Color),
4499 D3DCOLOR_G(Color),
4500 D3DCOLOR_B(Color),
4501 D3DCOLOR_A(Color));
4502 checkGLcall("glClearColor");
4504 /* Clear ALL colors! */
4505 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4506 glMask = glMask | GL_COLOR_BUFFER_BIT;
4509 if (!curRect) {
4510 /* In drawable flag is set below */
4512 glScissor(This->stateBlock->viewport.X,
4513 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4514 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4515 This->stateBlock->viewport.Width,
4516 This->stateBlock->viewport.Height);
4517 checkGLcall("glScissor");
4518 glClear(glMask);
4519 checkGLcall("glClear");
4520 } else {
4521 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4522 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4524 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4525 curRect[0].x2 < target->currentDesc.Width ||
4526 curRect[0].y2 < target->currentDesc.Height) {
4527 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4528 blt_to_drawable(This, target);
4532 /* Now process each rect in turn */
4533 for (i = 0; i < Count; i++) {
4534 /* Note gl uses lower left, width/height */
4535 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4536 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4537 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4538 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4540 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4541 * The rectangle is not cleared, no error is returned, but further rectanlges are
4542 * still cleared if they are valid
4544 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4545 TRACE("Rectangle with negative dimensions, ignoring\n");
4546 continue;
4549 if(This->render_offscreen) {
4550 glScissor(curRect[i].x1, curRect[i].y1,
4551 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4552 } else {
4553 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4554 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4556 checkGLcall("glScissor");
4558 glClear(glMask);
4559 checkGLcall("glClear");
4563 /* Restore the old values (why..?) */
4564 if (Flags & WINED3DCLEAR_STENCIL) {
4565 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4567 if (Flags & WINED3DCLEAR_TARGET) {
4568 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4569 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4570 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4571 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4572 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4575 LEAVE_GL();
4577 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4578 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4580 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4581 target->Flags |= SFLAG_INTEXTURE;
4582 target->Flags &= ~SFLAG_INSYSMEM;
4583 } else {
4584 target->Flags |= SFLAG_INDRAWABLE;
4585 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4587 return WINED3D_OK;
4590 /*****
4591 * Drawing functions
4592 *****/
4593 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4594 UINT PrimitiveCount) {
4596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4598 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4599 debug_d3dprimitivetype(PrimitiveType),
4600 StartVertex, PrimitiveCount);
4602 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4603 if(This->stateBlock->streamIsUP) {
4604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4605 This->stateBlock->streamIsUP = FALSE;
4608 if(This->stateBlock->loadBaseVertexIndex != 0) {
4609 This->stateBlock->loadBaseVertexIndex = 0;
4610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4612 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4613 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4614 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4615 return WINED3D_OK;
4618 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4619 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4620 WINED3DPRIMITIVETYPE PrimitiveType,
4621 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 UINT idxStride = 2;
4625 IWineD3DIndexBuffer *pIB;
4626 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4627 GLuint vbo;
4629 pIB = This->stateBlock->pIndexData;
4630 if (!pIB) {
4631 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4632 * without an index buffer set. (The first time at least...)
4633 * D3D8 simply dies, but I doubt it can do much harm to return
4634 * D3DERR_INVALIDCALL there as well. */
4635 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4636 return WINED3DERR_INVALIDCALL;
4639 if(This->stateBlock->streamIsUP) {
4640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4641 This->stateBlock->streamIsUP = FALSE;
4643 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4645 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4646 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4647 minIndex, NumVertices, startIndex, primCount);
4649 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4650 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4651 idxStride = 2;
4652 } else {
4653 idxStride = 4;
4656 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4657 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4661 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4662 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4664 return WINED3D_OK;
4667 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4668 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4669 UINT VertexStreamZeroStride) {
4670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4673 debug_d3dprimitivetype(PrimitiveType),
4674 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4676 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4677 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4678 This->stateBlock->streamOffset[0] = 0;
4679 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4680 This->stateBlock->streamIsUP = TRUE;
4681 This->stateBlock->loadBaseVertexIndex = 0;
4683 /* TODO: Only mark dirty if drawing from a different UP address */
4684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4686 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4687 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4689 /* MSDN specifies stream zero settings must be set to NULL */
4690 This->stateBlock->streamStride[0] = 0;
4691 This->stateBlock->streamSource[0] = NULL;
4693 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4694 * the new stream sources or use UP drawing again
4696 return WINED3D_OK;
4699 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4700 UINT MinVertexIndex, UINT NumVertices,
4701 UINT PrimitiveCount, CONST void* pIndexData,
4702 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4703 UINT VertexStreamZeroStride) {
4704 int idxStride;
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4708 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4709 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4710 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4712 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4713 idxStride = 2;
4714 } else {
4715 idxStride = 4;
4718 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4719 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4720 This->stateBlock->streamIsUP = TRUE;
4721 This->stateBlock->streamOffset[0] = 0;
4722 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4724 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4725 This->stateBlock->baseVertexIndex = 0;
4726 This->stateBlock->loadBaseVertexIndex = 0;
4727 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4731 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4733 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4734 This->stateBlock->streamSource[0] = NULL;
4735 This->stateBlock->streamStride[0] = 0;
4736 This->stateBlock->pIndexData = NULL;
4737 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4738 * SetStreamSource to specify a vertex buffer
4741 return WINED3D_OK;
4744 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4747 /* Mark the state dirty until we have nicer tracking
4748 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4749 * that value.
4751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4753 This->stateBlock->baseVertexIndex = 0;
4754 This->up_strided = DrawPrimStrideData;
4755 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4756 This->up_strided = NULL;
4757 return WINED3D_OK;
4759 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4760 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4762 HRESULT hr = WINED3D_OK;
4763 WINED3DRESOURCETYPE sourceType;
4764 WINED3DRESOURCETYPE destinationType;
4765 int i ,levels;
4767 /* TODO: think about moving the code into IWineD3DBaseTexture */
4769 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4771 /* verify that the source and destination textures aren't NULL */
4772 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4773 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4774 This, pSourceTexture, pDestinationTexture);
4775 hr = WINED3DERR_INVALIDCALL;
4778 if (pSourceTexture == pDestinationTexture) {
4779 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4780 This, pSourceTexture, pDestinationTexture);
4781 hr = WINED3DERR_INVALIDCALL;
4783 /* Verify that the source and destination textures are the same type */
4784 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4785 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4787 if (sourceType != destinationType) {
4788 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4789 This);
4790 hr = WINED3DERR_INVALIDCALL;
4793 /* check that both textures have the identical numbers of levels */
4794 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4795 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4796 hr = WINED3DERR_INVALIDCALL;
4799 if (WINED3D_OK == hr) {
4801 /* Make sure that the destination texture is loaded */
4802 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4804 /* Update every surface level of the texture */
4805 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4807 switch (sourceType) {
4808 case WINED3DRTYPE_TEXTURE:
4810 IWineD3DSurface *srcSurface;
4811 IWineD3DSurface *destSurface;
4813 for (i = 0 ; i < levels ; ++i) {
4814 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4815 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4816 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4817 IWineD3DSurface_Release(srcSurface);
4818 IWineD3DSurface_Release(destSurface);
4819 if (WINED3D_OK != hr) {
4820 WARN("(%p) : Call to update surface failed\n", This);
4821 return hr;
4825 break;
4826 case WINED3DRTYPE_CUBETEXTURE:
4828 IWineD3DSurface *srcSurface;
4829 IWineD3DSurface *destSurface;
4830 WINED3DCUBEMAP_FACES faceType;
4832 for (i = 0 ; i < levels ; ++i) {
4833 /* Update each cube face */
4834 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4835 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4836 if (WINED3D_OK != hr) {
4837 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4838 } else {
4839 TRACE("Got srcSurface %p\n", srcSurface);
4841 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4842 if (WINED3D_OK != hr) {
4843 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4844 } else {
4845 TRACE("Got desrSurface %p\n", destSurface);
4847 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4848 IWineD3DSurface_Release(srcSurface);
4849 IWineD3DSurface_Release(destSurface);
4850 if (WINED3D_OK != hr) {
4851 WARN("(%p) : Call to update surface failed\n", This);
4852 return hr;
4857 break;
4858 #if 0 /* TODO: Add support for volume textures */
4859 case WINED3DRTYPE_VOLUMETEXTURE:
4861 IWineD3DVolume srcVolume = NULL;
4862 IWineD3DSurface destVolume = NULL;
4864 for (i = 0 ; i < levels ; ++i) {
4865 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4866 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4867 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4868 IWineD3DVolume_Release(srcSurface);
4869 IWineD3DVolume_Release(destSurface);
4870 if (WINED3D_OK != hr) {
4871 WARN("(%p) : Call to update volume failed\n", This);
4872 return hr;
4876 break;
4877 #endif
4878 default:
4879 FIXME("(%p) : Unsupported source and destination type\n", This);
4880 hr = WINED3DERR_INVALIDCALL;
4884 return hr;
4887 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4888 IWineD3DSwapChain *swapChain;
4889 HRESULT hr;
4890 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4891 if(hr == WINED3D_OK) {
4892 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4893 IWineD3DSwapChain_Release(swapChain);
4895 return hr;
4898 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4900 /* return a sensible default */
4901 *pNumPasses = 1;
4902 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4903 FIXME("(%p) : stub\n", This);
4904 return WINED3D_OK;
4907 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4909 int j;
4910 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4911 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4912 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4913 return WINED3DERR_INVALIDCALL;
4915 for (j = 0; j < 256; ++j) {
4916 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4917 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4918 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4919 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4921 TRACE("(%p) : returning\n", This);
4922 return WINED3D_OK;
4925 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4927 int j;
4928 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4929 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4930 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4931 return WINED3DERR_INVALIDCALL;
4933 for (j = 0; j < 256; ++j) {
4934 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4935 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4936 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4937 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4939 TRACE("(%p) : returning\n", This);
4940 return WINED3D_OK;
4943 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4945 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4946 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4947 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4948 return WINED3DERR_INVALIDCALL;
4950 /*TODO: stateblocks */
4951 This->currentPalette = PaletteNumber;
4952 TRACE("(%p) : returning\n", This);
4953 return WINED3D_OK;
4956 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4958 if (PaletteNumber == NULL) {
4959 WARN("(%p) : returning Invalid Call\n", This);
4960 return WINED3DERR_INVALIDCALL;
4962 /*TODO: stateblocks */
4963 *PaletteNumber = This->currentPalette;
4964 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4965 return WINED3D_OK;
4968 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4970 static BOOL showFixmes = TRUE;
4971 if (showFixmes) {
4972 FIXME("(%p) : stub\n", This);
4973 showFixmes = FALSE;
4976 This->softwareVertexProcessing = bSoftware;
4977 return WINED3D_OK;
4981 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4983 static BOOL showFixmes = TRUE;
4984 if (showFixmes) {
4985 FIXME("(%p) : stub\n", This);
4986 showFixmes = FALSE;
4988 return This->softwareVertexProcessing;
4992 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4994 IWineD3DSwapChain *swapChain;
4995 HRESULT hr;
4997 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4999 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5000 if(hr == WINED3D_OK){
5001 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5002 IWineD3DSwapChain_Release(swapChain);
5003 }else{
5004 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5006 return hr;
5010 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5012 static BOOL showfixmes = TRUE;
5013 if(nSegments != 0.0f) {
5014 if( showfixmes) {
5015 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5016 showfixmes = FALSE;
5019 return WINED3D_OK;
5022 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5024 static BOOL showfixmes = TRUE;
5025 if( showfixmes) {
5026 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5027 showfixmes = FALSE;
5029 return 0.0f;
5032 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5034 /** TODO: remove casts to IWineD3DSurfaceImpl
5035 * NOTE: move code to surface to accomplish this
5036 ****************************************/
5037 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5038 int srcWidth, srcHeight;
5039 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5040 WINED3DFORMAT destFormat, srcFormat;
5041 UINT destSize;
5042 int srcLeft, destLeft, destTop;
5043 WINED3DPOOL srcPool, destPool;
5044 int offset = 0;
5045 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5046 glDescriptor *glDescription = NULL;
5048 WINED3DSURFACE_DESC winedesc;
5050 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5051 memset(&winedesc, 0, sizeof(winedesc));
5052 winedesc.Width = &srcSurfaceWidth;
5053 winedesc.Height = &srcSurfaceHeight;
5054 winedesc.Pool = &srcPool;
5055 winedesc.Format = &srcFormat;
5057 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5059 winedesc.Width = &destSurfaceWidth;
5060 winedesc.Height = &destSurfaceHeight;
5061 winedesc.Pool = &destPool;
5062 winedesc.Format = &destFormat;
5063 winedesc.Size = &destSize;
5065 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5067 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5068 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5069 return WINED3DERR_INVALIDCALL;
5072 if (destFormat == WINED3DFMT_UNKNOWN) {
5073 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5074 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5076 /* Get the update surface description */
5077 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5080 ENTER_GL();
5082 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5084 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5085 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5086 checkGLcall("glActiveTextureARB");
5089 /* Make sure the surface is loaded and up to date */
5090 IWineD3DSurface_PreLoad(pDestinationSurface);
5092 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5094 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5095 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5096 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5097 srcLeft = pSourceRect ? pSourceRect->left : 0;
5098 destLeft = pDestPoint ? pDestPoint->x : 0;
5099 destTop = pDestPoint ? pDestPoint->y : 0;
5102 /* This function doesn't support compressed textures
5103 the pitch is just bytesPerPixel * width */
5104 if(srcWidth != srcSurfaceWidth || srcLeft ){
5105 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5106 offset += srcLeft * pSrcSurface->bytesPerPixel;
5107 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5109 /* TODO DXT formats */
5111 if(pSourceRect != NULL && pSourceRect->top != 0){
5112 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5114 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5115 ,This
5116 ,glDescription->level
5117 ,destLeft
5118 ,destTop
5119 ,srcWidth
5120 ,srcHeight
5121 ,glDescription->glFormat
5122 ,glDescription->glType
5123 ,IWineD3DSurface_GetData(pSourceSurface)
5126 /* Sanity check */
5127 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5129 /* need to lock the surface to get the data */
5130 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5133 /* TODO: Cube and volume support */
5134 if(rowoffset != 0){
5135 /* not a whole row so we have to do it a line at a time */
5136 int j;
5138 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5139 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5141 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5143 glTexSubImage2D(glDescription->target
5144 ,glDescription->level
5145 ,destLeft
5147 ,srcWidth
5149 ,glDescription->glFormat
5150 ,glDescription->glType
5151 ,data /* could be quicker using */
5153 data += rowoffset;
5156 } else { /* Full width, so just write out the whole texture */
5158 if (WINED3DFMT_DXT1 == destFormat ||
5159 WINED3DFMT_DXT2 == destFormat ||
5160 WINED3DFMT_DXT3 == destFormat ||
5161 WINED3DFMT_DXT4 == destFormat ||
5162 WINED3DFMT_DXT5 == destFormat) {
5163 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5164 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5165 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5166 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5167 } if (destFormat != srcFormat) {
5168 FIXME("Updating mixed format compressed texture is not curretly support\n");
5169 } else {
5170 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5171 glDescription->level,
5172 glDescription->glFormatInternal,
5173 srcWidth,
5174 srcHeight,
5176 destSize,
5177 IWineD3DSurface_GetData(pSourceSurface));
5179 } else {
5180 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5184 } else {
5185 glTexSubImage2D(glDescription->target
5186 ,glDescription->level
5187 ,destLeft
5188 ,destTop
5189 ,srcWidth
5190 ,srcHeight
5191 ,glDescription->glFormat
5192 ,glDescription->glType
5193 ,IWineD3DSurface_GetData(pSourceSurface)
5197 checkGLcall("glTexSubImage2D");
5199 LEAVE_GL();
5201 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5202 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5205 return WINED3D_OK;
5208 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5210 struct WineD3DRectPatch *patch;
5211 unsigned int i;
5212 struct list *e;
5213 BOOL found;
5214 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5216 if(!(Handle || pRectPatchInfo)) {
5217 /* TODO: Write a test for the return value, thus the FIXME */
5218 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5219 return WINED3DERR_INVALIDCALL;
5222 if(Handle) {
5223 i = PATCHMAP_HASHFUNC(Handle);
5224 found = FALSE;
5225 LIST_FOR_EACH(e, &This->patches[i]) {
5226 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5227 if(patch->Handle == Handle) {
5228 found = TRUE;
5229 break;
5233 if(!found) {
5234 TRACE("Patch does not exist. Creating a new one\n");
5235 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5236 patch->Handle = Handle;
5237 list_add_head(&This->patches[i], &patch->entry);
5238 } else {
5239 TRACE("Found existing patch %p\n", patch);
5241 } else {
5242 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5243 * attributes we have to tesselate, read back, and draw. This needs a patch
5244 * management structure instance. Create one.
5246 * A possible improvement is to check if a vertex shader is used, and if not directly
5247 * draw the patch.
5249 FIXME("Drawing an uncached patch. This is slow\n");
5250 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5253 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5254 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5255 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5256 HRESULT hr;
5257 TRACE("Tesselation density or patch info changed, retesselating\n");
5259 if(pRectPatchInfo) {
5260 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5262 patch->numSegs[0] = pNumSegs[0];
5263 patch->numSegs[1] = pNumSegs[1];
5264 patch->numSegs[2] = pNumSegs[2];
5265 patch->numSegs[3] = pNumSegs[3];
5267 hr = tesselate_rectpatch(This, patch);
5268 if(FAILED(hr)) {
5269 WARN("Patch tesselation failed\n");
5271 /* Do not release the handle to store the params of the patch */
5272 if(!Handle) {
5273 HeapFree(GetProcessHeap(), 0, patch);
5275 return hr;
5279 This->currentPatch = patch;
5280 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5281 This->currentPatch = NULL;
5283 /* Destroy uncached patches */
5284 if(!Handle) {
5285 HeapFree(GetProcessHeap(), 0, patch->mem);
5286 HeapFree(GetProcessHeap(), 0, patch);
5288 return WINED3D_OK;
5291 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5292 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5294 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5295 FIXME("(%p) : Stub\n", This);
5296 return WINED3D_OK;
5299 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5301 int i;
5302 struct WineD3DRectPatch *patch;
5303 struct list *e;
5304 TRACE("(%p) Handle(%d)\n", This, Handle);
5306 i = PATCHMAP_HASHFUNC(Handle);
5307 LIST_FOR_EACH(e, &This->patches[i]) {
5308 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5309 if(patch->Handle == Handle) {
5310 TRACE("Deleting patch %p\n", patch);
5311 list_remove(&patch->entry);
5312 HeapFree(GetProcessHeap(), 0, patch->mem);
5313 HeapFree(GetProcessHeap(), 0, patch);
5314 return WINED3D_OK;
5318 /* TODO: Write a test for the return value */
5319 FIXME("Attempt to destroy nonexistant patch\n");
5320 return WINED3DERR_INVALIDCALL;
5323 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5324 HRESULT hr;
5325 IWineD3DSwapChain *swapchain;
5327 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5328 if (SUCCEEDED(hr)) {
5329 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5330 return swapchain;
5333 return NULL;
5336 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5339 if (!*fbo) {
5340 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5341 checkGLcall("glGenFramebuffersEXT()");
5343 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5344 checkGLcall("glBindFramebuffer()");
5347 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5348 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5349 IWineD3DBaseTextureImpl *texture_impl;
5350 GLenum texttarget, target;
5351 GLint old_binding;
5353 texttarget = surface_impl->glDescription.target;
5354 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5355 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5357 IWineD3DSurface_PreLoad(surface);
5359 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5360 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5361 glBindTexture(target, old_binding);
5363 /* Update base texture states array */
5364 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5365 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5366 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5367 if (texture_impl->baseTexture.bindCount) {
5368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5371 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5374 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5376 checkGLcall("attach_surface_fbo");
5379 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5381 IWineD3DSwapChain *swapchain;
5383 swapchain = get_swapchain(surface);
5384 if (swapchain) {
5385 GLenum buffer;
5387 TRACE("Surface %p is onscreen\n", surface);
5389 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5390 buffer = surface_get_gl_buffer(surface, swapchain);
5391 glDrawBuffer(buffer);
5392 checkGLcall("glDrawBuffer()");
5393 } else {
5394 TRACE("Surface %p is offscreen\n", surface);
5395 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5396 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5399 if (rect) {
5400 glEnable(GL_SCISSOR_TEST);
5401 if(!swapchain) {
5402 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5403 } else {
5404 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5405 rect->x2 - rect->x1, rect->y2 - rect->y1);
5407 checkGLcall("glScissor");
5408 } else {
5409 glDisable(GL_SCISSOR_TEST);
5411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5413 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5416 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5417 glClear(GL_COLOR_BUFFER_BIT);
5418 checkGLcall("glClear");
5420 if (This->render_offscreen) {
5421 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5422 } else {
5423 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5424 checkGLcall("glBindFramebuffer()");
5427 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5428 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5429 glDrawBuffer(GL_BACK);
5430 checkGLcall("glDrawBuffer()");
5434 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5436 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5437 WINEDDBLTFX BltFx;
5438 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5440 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5441 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5442 return WINED3DERR_INVALIDCALL;
5445 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5446 color_fill_fbo(iface, pSurface, pRect, color);
5447 return WINED3D_OK;
5448 } else {
5449 /* Just forward this to the DirectDraw blitting engine */
5450 memset(&BltFx, 0, sizeof(BltFx));
5451 BltFx.dwSize = sizeof(BltFx);
5452 BltFx.u5.dwFillColor = color;
5453 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5457 /* rendertarget and deptth stencil functions */
5458 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5461 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5462 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5463 return WINED3DERR_INVALIDCALL;
5466 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5467 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5468 /* Note inc ref on returned surface */
5469 if(*ppRenderTarget != NULL)
5470 IWineD3DSurface_AddRef(*ppRenderTarget);
5471 return WINED3D_OK;
5474 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5476 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5477 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5478 IWineD3DSwapChainImpl *Swapchain;
5479 HRESULT hr;
5481 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5483 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5484 if(hr != WINED3D_OK) {
5485 ERR("Can't get the swapchain\n");
5486 return hr;
5489 /* Make sure to release the swapchain */
5490 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5492 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5493 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5494 return WINED3DERR_INVALIDCALL;
5496 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5497 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5498 return WINED3DERR_INVALIDCALL;
5501 if(Swapchain->frontBuffer != Front) {
5502 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5504 if(Swapchain->frontBuffer)
5505 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5506 Swapchain->frontBuffer = Front;
5508 if(Swapchain->frontBuffer) {
5509 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5513 if(Back && !Swapchain->backBuffer) {
5514 /* We need memory for the back buffer array - only one back buffer this way */
5515 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5516 if(!Swapchain->backBuffer) {
5517 ERR("Out of memory\n");
5518 return E_OUTOFMEMORY;
5522 if(Swapchain->backBuffer[0] != Back) {
5523 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5525 /* What to do about the context here in the case of multithreading? Not sure.
5526 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5528 ENTER_GL();
5529 if(!Swapchain->backBuffer[0]) {
5530 /* GL was told to draw to the front buffer at creation,
5531 * undo that
5533 glDrawBuffer(GL_BACK);
5534 checkGLcall("glDrawBuffer(GL_BACK)");
5535 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5536 Swapchain->presentParms.BackBufferCount = 1;
5537 } else if (!Back) {
5538 /* That makes problems - disable for now */
5539 /* glDrawBuffer(GL_FRONT); */
5540 checkGLcall("glDrawBuffer(GL_FRONT)");
5541 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5542 Swapchain->presentParms.BackBufferCount = 0;
5544 LEAVE_GL();
5546 if(Swapchain->backBuffer[0])
5547 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5548 Swapchain->backBuffer[0] = Back;
5550 if(Swapchain->backBuffer[0]) {
5551 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5552 } else {
5553 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5558 return WINED3D_OK;
5561 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 *ppZStencilSurface = This->depthStencilBuffer;
5564 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5566 if(*ppZStencilSurface != NULL) {
5567 /* Note inc ref on returned surface */
5568 IWineD3DSurface_AddRef(*ppZStencilSurface);
5570 return WINED3D_OK;
5573 /* TODO: Handle stencil attachments */
5574 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5576 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5578 TRACE("Set depth stencil to %p\n", depth_stencil);
5580 if (depth_stencil_impl) {
5581 if (depth_stencil_impl->current_renderbuffer) {
5582 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5583 checkGLcall("glFramebufferRenderbufferEXT()");
5584 } else {
5585 IWineD3DBaseTextureImpl *texture_impl;
5586 GLenum texttarget, target;
5587 GLint old_binding = 0;
5589 texttarget = depth_stencil_impl->glDescription.target;
5590 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5591 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5593 IWineD3DSurface_PreLoad(depth_stencil);
5595 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5596 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5597 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5598 glBindTexture(target, old_binding);
5600 /* Update base texture states array */
5601 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5602 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5603 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5604 if (texture_impl->baseTexture.bindCount) {
5605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5608 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5611 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5612 checkGLcall("glFramebufferTexture2DEXT()");
5614 } else {
5615 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5616 checkGLcall("glFramebufferTexture2DEXT()");
5620 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5622 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5624 TRACE("Set render target %u to %p\n", idx, render_target);
5626 if (rtimpl) {
5627 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5628 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5629 } else {
5630 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5631 checkGLcall("glFramebufferTexture2DEXT()");
5633 This->draw_buffers[idx] = GL_NONE;
5637 static void check_fbo_status(IWineD3DDevice *iface) {
5638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5639 GLenum status;
5641 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5642 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5643 TRACE("FBO complete\n");
5644 } else {
5645 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5647 /* Dump the FBO attachments */
5648 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5649 IWineD3DSurfaceImpl *attachment;
5650 int i;
5652 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5653 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5654 if (attachment) {
5655 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5656 attachment->pow2Width, attachment->pow2Height);
5659 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5660 if (attachment) {
5661 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5662 attachment->pow2Width, attachment->pow2Height);
5668 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5670 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5671 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5673 if (!ds_impl) return FALSE;
5675 if (ds_impl->current_renderbuffer) {
5676 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5677 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5680 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5681 rt_impl->pow2Height != ds_impl->pow2Height);
5684 void apply_fbo_state(IWineD3DDevice *iface) {
5685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5686 unsigned int i;
5688 if (This->render_offscreen) {
5689 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5691 /* Apply render targets */
5692 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5693 IWineD3DSurface *render_target = This->render_targets[i];
5694 if (This->fbo_color_attachments[i] != render_target) {
5695 set_render_target_fbo(iface, i, render_target);
5696 This->fbo_color_attachments[i] = render_target;
5700 /* Apply depth targets */
5701 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5702 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5703 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5705 if (This->stencilBufferTarget) {
5706 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5708 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5709 This->fbo_depth_attachment = This->stencilBufferTarget;
5712 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5713 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5714 checkGLcall("glDrawBuffers()");
5715 } else {
5716 glDrawBuffer(This->draw_buffers[0]);
5717 checkGLcall("glDrawBuffer()");
5719 } else {
5720 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5723 check_fbo_status(iface);
5726 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5727 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5729 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5730 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5731 GLenum gl_filter;
5733 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5734 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5735 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5736 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5738 switch (filter) {
5739 case WINED3DTEXF_LINEAR:
5740 gl_filter = GL_LINEAR;
5741 break;
5743 default:
5744 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5745 case WINED3DTEXF_NONE:
5746 case WINED3DTEXF_POINT:
5747 gl_filter = GL_NEAREST;
5748 break;
5751 /* Attach src surface to src fbo */
5752 src_swapchain = get_swapchain(src_surface);
5753 ENTER_GL();
5754 if (src_swapchain) {
5755 GLenum buffer;
5757 TRACE("Source surface %p is onscreen\n", src_surface);
5758 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5760 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5761 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5762 glReadBuffer(buffer);
5763 checkGLcall("glReadBuffer()");
5765 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5766 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5767 } else {
5768 TRACE("Source surface %p is offscreen\n", src_surface);
5769 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5770 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5771 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5772 checkGLcall("glReadBuffer()");
5775 /* Attach dst surface to dst fbo */
5776 dst_swapchain = get_swapchain(dst_surface);
5777 if (dst_swapchain) {
5778 GLenum buffer;
5780 TRACE("Destination surface %p is onscreen\n", dst_surface);
5781 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5783 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5784 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5785 glDrawBuffer(buffer);
5786 checkGLcall("glDrawBuffer()");
5788 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5789 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5790 } else {
5791 TRACE("Destination surface %p is offscreen\n", dst_surface);
5793 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5794 if(!src_swapchain) {
5795 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5798 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5799 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5800 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5801 checkGLcall("glDrawBuffer()");
5803 glDisable(GL_SCISSOR_TEST);
5804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5806 if (flip) {
5807 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5808 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5809 checkGLcall("glBlitFramebuffer()");
5810 } else {
5811 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5812 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5813 checkGLcall("glBlitFramebuffer()");
5816 if (This->render_offscreen) {
5817 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5818 } else {
5819 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5820 checkGLcall("glBindFramebuffer()");
5823 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5824 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5825 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5826 glDrawBuffer(GL_BACK);
5827 checkGLcall("glDrawBuffer()");
5829 LEAVE_GL();
5832 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5834 WINED3DVIEWPORT viewport;
5836 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5838 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5839 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5840 return WINED3DERR_INVALIDCALL;
5843 /* MSDN says that null disables the render target
5844 but a device must always be associated with a render target
5845 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5847 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5848 for more details
5850 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5851 FIXME("Trying to set render target 0 to NULL\n");
5852 return WINED3DERR_INVALIDCALL;
5854 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5855 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);
5856 return WINED3DERR_INVALIDCALL;
5859 /* If we are trying to set what we already have, don't bother */
5860 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5861 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5862 return WINED3D_OK;
5864 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5865 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5866 This->render_targets[RenderTargetIndex] = pRenderTarget;
5868 /* Render target 0 is special */
5869 if(RenderTargetIndex == 0) {
5870 /* Finally, reset the viewport as the MSDN states. */
5871 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5872 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5873 viewport.X = 0;
5874 viewport.Y = 0;
5875 viewport.MaxZ = 1.0f;
5876 viewport.MinZ = 0.0f;
5877 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5878 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5879 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5883 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5884 * ctx properly.
5885 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5886 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5888 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5890 return WINED3D_OK;
5893 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5895 HRESULT hr = WINED3D_OK;
5896 IWineD3DSurface *tmp;
5898 TRACE("(%p) Swapping z-buffer\n",This);
5900 if (pNewZStencil == This->stencilBufferTarget) {
5901 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5902 } else {
5903 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5904 * depending on the renter target implementation being used.
5905 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5906 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5907 * stencil buffer and incure an extra memory overhead
5908 ******************************************************/
5910 tmp = This->stencilBufferTarget;
5911 This->stencilBufferTarget = pNewZStencil;
5912 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5913 /* should we be calling the parent or the wined3d surface? */
5914 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5915 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5916 hr = WINED3D_OK;
5918 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5919 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5921 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5926 return hr;
5929 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5930 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5932 /* TODO: the use of Impl is deprecated. */
5933 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5934 WINED3DLOCKED_RECT lockedRect;
5936 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5938 /* some basic validation checks */
5939 if(This->cursorTexture) {
5940 ENTER_GL();
5941 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5942 glDeleteTextures(1, &This->cursorTexture);
5943 LEAVE_GL();
5944 This->cursorTexture = 0;
5947 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5948 This->haveHardwareCursor = TRUE;
5949 else
5950 This->haveHardwareCursor = FALSE;
5952 if(pCursorBitmap) {
5953 WINED3DLOCKED_RECT rect;
5955 /* MSDN: Cursor must be A8R8G8B8 */
5956 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5957 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5958 return WINED3DERR_INVALIDCALL;
5961 /* MSDN: Cursor must be smaller than the display mode */
5962 if(pSur->currentDesc.Width > This->ddraw_width ||
5963 pSur->currentDesc.Height > This->ddraw_height) {
5964 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);
5965 return WINED3DERR_INVALIDCALL;
5968 if (!This->haveHardwareCursor) {
5969 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5971 /* Do not store the surface's pointer because the application may
5972 * release it after setting the cursor image. Windows doesn't
5973 * addref the set surface, so we can't do this either without
5974 * creating circular refcount dependencies. Copy out the gl texture
5975 * instead.
5977 This->cursorWidth = pSur->currentDesc.Width;
5978 This->cursorHeight = pSur->currentDesc.Height;
5979 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5981 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5982 char *mem, *bits = (char *)rect.pBits;
5983 GLint intfmt = tableEntry->glInternal;
5984 GLint format = tableEntry->glFormat;
5985 GLint type = tableEntry->glType;
5986 INT height = This->cursorHeight;
5987 INT width = This->cursorWidth;
5988 INT bpp = tableEntry->bpp;
5989 INT i;
5991 /* Reformat the texture memory (pitch and width can be
5992 * different) */
5993 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5994 for(i = 0; i < height; i++)
5995 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5996 IWineD3DSurface_UnlockRect(pCursorBitmap);
5997 ENTER_GL();
5999 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6000 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6001 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6004 /* Make sure that a proper texture unit is selected */
6005 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6006 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6007 checkGLcall("glActiveTextureARB");
6009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6010 /* Create a new cursor texture */
6011 glGenTextures(1, &This->cursorTexture);
6012 checkGLcall("glGenTextures");
6013 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6014 checkGLcall("glBindTexture");
6015 /* Copy the bitmap memory into the cursor texture */
6016 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6017 HeapFree(GetProcessHeap(), 0, mem);
6018 checkGLcall("glTexImage2D");
6020 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6021 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6022 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6025 LEAVE_GL();
6027 else
6029 FIXME("A cursor texture was not returned.\n");
6030 This->cursorTexture = 0;
6033 else
6035 /* Draw a hardware cursor */
6036 ICONINFO cursorInfo;
6037 HCURSOR cursor;
6038 /* Create and clear maskBits because it is not needed for
6039 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6040 * chunks. */
6041 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6042 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6043 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6044 WINED3DLOCK_NO_DIRTY_UPDATE |
6045 WINED3DLOCK_READONLY
6047 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6048 pSur->currentDesc.Height);
6050 cursorInfo.fIcon = FALSE;
6051 cursorInfo.xHotspot = XHotSpot;
6052 cursorInfo.yHotspot = YHotSpot;
6053 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6054 pSur->currentDesc.Height, 1,
6055 1, &maskBits);
6056 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6057 pSur->currentDesc.Height, 1,
6058 32, lockedRect.pBits);
6059 IWineD3DSurface_UnlockRect(pCursorBitmap);
6060 /* Create our cursor and clean up. */
6061 cursor = CreateIconIndirect(&cursorInfo);
6062 SetCursor(cursor);
6063 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6064 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6065 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6066 This->hardwareCursor = cursor;
6067 HeapFree(GetProcessHeap(), 0, maskBits);
6071 This->xHotSpot = XHotSpot;
6072 This->yHotSpot = YHotSpot;
6073 return WINED3D_OK;
6076 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6078 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6080 This->xScreenSpace = XScreenSpace;
6081 This->yScreenSpace = YScreenSpace;
6083 return;
6087 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6089 BOOL oldVisible = This->bCursorVisible;
6090 POINT pt;
6092 TRACE("(%p) : visible(%d)\n", This, bShow);
6095 * When ShowCursor is first called it should make the cursor appear at the OS's last
6096 * known cursor position. Because of this, some applications just repetitively call
6097 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6099 GetCursorPos(&pt);
6100 This->xScreenSpace = pt.x;
6101 This->yScreenSpace = pt.y;
6103 if (This->haveHardwareCursor) {
6104 This->bCursorVisible = bShow;
6105 if (bShow)
6106 SetCursor(This->hardwareCursor);
6107 else
6108 SetCursor(NULL);
6110 else
6112 if (This->cursorTexture)
6113 This->bCursorVisible = bShow;
6116 return oldVisible;
6119 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6121 TRACE("(%p) : state (%u)\n", This, This->state);
6122 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6123 switch (This->state) {
6124 case WINED3D_OK:
6125 return WINED3D_OK;
6126 case WINED3DERR_DEVICELOST:
6128 ResourceList *resourceList = This->resources;
6129 while (NULL != resourceList) {
6130 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6131 return WINED3DERR_DEVICENOTRESET;
6132 resourceList = resourceList->next;
6134 return WINED3DERR_DEVICELOST;
6136 case WINED3DERR_DRIVERINTERNALERROR:
6137 return WINED3DERR_DRIVERINTERNALERROR;
6140 /* Unknown state */
6141 return WINED3DERR_DRIVERINTERNALERROR;
6145 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6147 /** FIXME: Resource tracking needs to be done,
6148 * The closes we can do to this is set the priorities of all managed textures low
6149 * and then reset them.
6150 ***********************************************************/
6151 FIXME("(%p) : stub\n", This);
6152 return WINED3D_OK;
6155 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6156 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6158 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6159 if(surface->Flags & SFLAG_DIBSECTION) {
6160 /* Release the DC */
6161 SelectObject(surface->hDC, surface->dib.holdbitmap);
6162 DeleteDC(surface->hDC);
6163 /* Release the DIB section */
6164 DeleteObject(surface->dib.DIBsection);
6165 surface->dib.bitmap_data = NULL;
6166 surface->resource.allocatedMemory = NULL;
6167 surface->Flags &= ~SFLAG_DIBSECTION;
6169 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6170 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6171 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6172 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6173 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6174 } else {
6175 surface->pow2Width = surface->pow2Height = 1;
6176 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6177 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6179 if(surface->glDescription.textureName) {
6180 ENTER_GL();
6181 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6182 glDeleteTextures(1, &surface->glDescription.textureName);
6183 LEAVE_GL();
6184 surface->glDescription.textureName = 0;
6185 surface->Flags &= ~SFLAG_CLIENT;
6187 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6188 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6189 surface->Flags |= SFLAG_NONPOW2;
6190 } else {
6191 surface->Flags &= ~SFLAG_NONPOW2;
6193 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6194 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6197 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6199 IWineD3DSwapChainImpl *swapchain;
6200 HRESULT hr;
6201 BOOL DisplayModeChanged = FALSE;
6202 WINED3DDISPLAYMODE mode;
6203 TRACE("(%p)\n", This);
6205 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6206 if(FAILED(hr)) {
6207 ERR("Failed to get the first implicit swapchain\n");
6208 return hr;
6211 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6212 * on an existing gl context, so there's no real need for recreation.
6214 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6216 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6218 TRACE("New params:\n");
6219 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6220 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6221 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6222 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6223 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6224 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6225 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6226 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6227 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6228 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6229 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6230 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6231 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6233 /* No special treatment of these parameters. Just store them */
6234 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6235 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6236 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6237 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6239 /* What to do about these? */
6240 if(pPresentationParameters->BackBufferCount != 0 &&
6241 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6242 ERR("Cannot change the back buffer count yet\n");
6244 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6245 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6246 ERR("Cannot change the back buffer format yet\n");
6248 if(pPresentationParameters->hDeviceWindow != NULL &&
6249 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6250 ERR("Cannot change the device window yet\n");
6252 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6253 ERR("What do do about a changed auto depth stencil parameter?\n");
6256 if(pPresentationParameters->Windowed) {
6257 mode.Width = swapchain->orig_width;
6258 mode.Height = swapchain->orig_height;
6259 mode.RefreshRate = 0;
6260 mode.Format = swapchain->presentParms.BackBufferFormat;
6261 } else {
6262 mode.Width = pPresentationParameters->BackBufferWidth;
6263 mode.Height = pPresentationParameters->BackBufferHeight;
6264 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6265 mode.Format = swapchain->presentParms.BackBufferFormat;
6268 /* Should Width == 800 && Height == 0 set 800x600? */
6269 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6270 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6271 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6273 WINED3DVIEWPORT vp;
6274 int i;
6276 vp.X = 0;
6277 vp.Y = 0;
6278 vp.Width = pPresentationParameters->BackBufferWidth;
6279 vp.Height = pPresentationParameters->BackBufferHeight;
6280 vp.MinZ = 0;
6281 vp.MaxZ = 1;
6283 if(!pPresentationParameters->Windowed) {
6284 DisplayModeChanged = TRUE;
6286 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6287 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6289 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6290 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6291 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6294 /* Now set the new viewport */
6295 IWineD3DDevice_SetViewport(iface, &vp);
6298 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6299 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6300 DisplayModeChanged) {
6302 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6303 if(!pPresentationParameters->Windowed) {
6304 IWineD3DDevice_SetFullscreen(iface, TRUE);
6307 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6309 /* Switching out of fullscreen mode? First set the original res, then change the window */
6310 if(pPresentationParameters->Windowed) {
6311 IWineD3DDevice_SetFullscreen(iface, FALSE);
6313 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6316 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6317 return WINED3D_OK;
6320 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6322 /** FIXME: always true at the moment **/
6323 if(!bEnableDialogs) {
6324 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6326 return WINED3D_OK;
6330 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6332 TRACE("(%p) : pParameters %p\n", This, pParameters);
6334 *pParameters = This->createParms;
6335 return WINED3D_OK;
6338 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6339 IWineD3DSwapChain *swapchain;
6340 HRESULT hrc = WINED3D_OK;
6342 TRACE("Relaying to swapchain\n");
6344 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6345 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6346 IWineD3DSwapChain_Release(swapchain);
6348 return;
6351 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6352 IWineD3DSwapChain *swapchain;
6353 HRESULT hrc = WINED3D_OK;
6355 TRACE("Relaying to swapchain\n");
6357 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6358 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6359 IWineD3DSwapChain_Release(swapchain);
6361 return;
6365 /** ********************************************************
6366 * Notification functions
6367 ** ********************************************************/
6368 /** This function must be called in the release of a resource when ref == 0,
6369 * the contents of resource must still be correct,
6370 * any handels to other resource held by the caller must be closed
6371 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6372 *****************************************************/
6373 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6375 ResourceList* resourceList;
6377 TRACE("(%p) : resource %p\n", This, resource);
6378 /* add a new texture to the frot of the linked list */
6379 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6380 resourceList->resource = resource;
6382 /* Get the old head */
6383 resourceList->next = This->resources;
6385 This->resources = resourceList;
6386 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6388 return;
6391 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6393 ResourceList* resourceList = NULL;
6394 ResourceList* previousResourceList = NULL;
6396 TRACE("(%p) : resource %p\n", This, resource);
6398 resourceList = This->resources;
6400 while (resourceList != NULL) {
6401 if(resourceList->resource == resource) break;
6402 previousResourceList = resourceList;
6403 resourceList = resourceList->next;
6406 if (resourceList == NULL) {
6407 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6408 return;
6409 } else {
6410 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6412 /* make sure we don't leave a hole in the list */
6413 if (previousResourceList != NULL) {
6414 previousResourceList->next = resourceList->next;
6415 } else {
6416 This->resources = resourceList->next;
6419 return;
6423 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6425 int counter;
6427 TRACE("(%p) : resource %p\n", This, resource);
6428 switch(IWineD3DResource_GetType(resource)){
6429 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6430 case WINED3DRTYPE_SURFACE: {
6431 unsigned int i;
6433 /* Cleanup any FBO attachments if d3d is enabled */
6434 if(This->d3d_initialized) {
6435 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6436 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6437 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6438 set_render_target_fbo(iface, i, NULL);
6439 This->fbo_color_attachments[i] = NULL;
6442 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6443 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6444 set_depth_stencil_fbo(iface, NULL);
6445 This->fbo_depth_attachment = NULL;
6449 break;
6452 case WINED3DRTYPE_TEXTURE:
6453 case WINED3DRTYPE_CUBETEXTURE:
6454 case WINED3DRTYPE_VOLUMETEXTURE:
6455 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6456 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6457 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6458 This->stateBlock->textures[counter] = NULL;
6460 if (This->updateStateBlock != This->stateBlock ){
6461 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6462 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6463 This->updateStateBlock->textures[counter] = NULL;
6467 break;
6468 case WINED3DRTYPE_VOLUME:
6469 /* TODO: nothing really? */
6470 break;
6471 case WINED3DRTYPE_VERTEXBUFFER:
6472 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6474 int streamNumber;
6475 TRACE("Cleaning up stream pointers\n");
6477 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6478 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6479 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6481 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6482 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6483 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6484 This->updateStateBlock->streamSource[streamNumber] = 0;
6485 /* Set changed flag? */
6488 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) */
6489 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6490 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6491 This->stateBlock->streamSource[streamNumber] = 0;
6494 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6495 else { /* This shouldn't happen */
6496 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6498 #endif
6502 break;
6503 case WINED3DRTYPE_INDEXBUFFER:
6504 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6505 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6506 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6507 This->updateStateBlock->pIndexData = NULL;
6510 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6511 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6512 This->stateBlock->pIndexData = NULL;
6516 break;
6517 default:
6518 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6519 break;
6523 /* Remove the resoruce from the resourceStore */
6524 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6526 TRACE("Resource released\n");
6530 /**********************************************************
6531 * IWineD3DDevice VTbl follows
6532 **********************************************************/
6534 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6536 /*** IUnknown methods ***/
6537 IWineD3DDeviceImpl_QueryInterface,
6538 IWineD3DDeviceImpl_AddRef,
6539 IWineD3DDeviceImpl_Release,
6540 /*** IWineD3DDevice methods ***/
6541 IWineD3DDeviceImpl_GetParent,
6542 /*** Creation methods**/
6543 IWineD3DDeviceImpl_CreateVertexBuffer,
6544 IWineD3DDeviceImpl_CreateIndexBuffer,
6545 IWineD3DDeviceImpl_CreateStateBlock,
6546 IWineD3DDeviceImpl_CreateSurface,
6547 IWineD3DDeviceImpl_CreateTexture,
6548 IWineD3DDeviceImpl_CreateVolumeTexture,
6549 IWineD3DDeviceImpl_CreateVolume,
6550 IWineD3DDeviceImpl_CreateCubeTexture,
6551 IWineD3DDeviceImpl_CreateQuery,
6552 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6553 IWineD3DDeviceImpl_CreateVertexDeclaration,
6554 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6555 IWineD3DDeviceImpl_CreateVertexShader,
6556 IWineD3DDeviceImpl_CreatePixelShader,
6557 IWineD3DDeviceImpl_CreatePalette,
6558 /*** Odd functions **/
6559 IWineD3DDeviceImpl_Init3D,
6560 IWineD3DDeviceImpl_Uninit3D,
6561 IWineD3DDeviceImpl_SetFullscreen,
6562 IWineD3DDeviceImpl_SetMultithreaded,
6563 IWineD3DDeviceImpl_EvictManagedResources,
6564 IWineD3DDeviceImpl_GetAvailableTextureMem,
6565 IWineD3DDeviceImpl_GetBackBuffer,
6566 IWineD3DDeviceImpl_GetCreationParameters,
6567 IWineD3DDeviceImpl_GetDeviceCaps,
6568 IWineD3DDeviceImpl_GetDirect3D,
6569 IWineD3DDeviceImpl_GetDisplayMode,
6570 IWineD3DDeviceImpl_SetDisplayMode,
6571 IWineD3DDeviceImpl_GetHWND,
6572 IWineD3DDeviceImpl_SetHWND,
6573 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6574 IWineD3DDeviceImpl_GetRasterStatus,
6575 IWineD3DDeviceImpl_GetSwapChain,
6576 IWineD3DDeviceImpl_Reset,
6577 IWineD3DDeviceImpl_SetDialogBoxMode,
6578 IWineD3DDeviceImpl_SetCursorProperties,
6579 IWineD3DDeviceImpl_SetCursorPosition,
6580 IWineD3DDeviceImpl_ShowCursor,
6581 IWineD3DDeviceImpl_TestCooperativeLevel,
6582 /*** Getters and setters **/
6583 IWineD3DDeviceImpl_SetClipPlane,
6584 IWineD3DDeviceImpl_GetClipPlane,
6585 IWineD3DDeviceImpl_SetClipStatus,
6586 IWineD3DDeviceImpl_GetClipStatus,
6587 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6588 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6589 IWineD3DDeviceImpl_SetDepthStencilSurface,
6590 IWineD3DDeviceImpl_GetDepthStencilSurface,
6591 IWineD3DDeviceImpl_SetFVF,
6592 IWineD3DDeviceImpl_GetFVF,
6593 IWineD3DDeviceImpl_SetGammaRamp,
6594 IWineD3DDeviceImpl_GetGammaRamp,
6595 IWineD3DDeviceImpl_SetIndices,
6596 IWineD3DDeviceImpl_GetIndices,
6597 IWineD3DDeviceImpl_SetBaseVertexIndex,
6598 IWineD3DDeviceImpl_GetBaseVertexIndex,
6599 IWineD3DDeviceImpl_SetLight,
6600 IWineD3DDeviceImpl_GetLight,
6601 IWineD3DDeviceImpl_SetLightEnable,
6602 IWineD3DDeviceImpl_GetLightEnable,
6603 IWineD3DDeviceImpl_SetMaterial,
6604 IWineD3DDeviceImpl_GetMaterial,
6605 IWineD3DDeviceImpl_SetNPatchMode,
6606 IWineD3DDeviceImpl_GetNPatchMode,
6607 IWineD3DDeviceImpl_SetPaletteEntries,
6608 IWineD3DDeviceImpl_GetPaletteEntries,
6609 IWineD3DDeviceImpl_SetPixelShader,
6610 IWineD3DDeviceImpl_GetPixelShader,
6611 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6612 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6613 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6614 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6615 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6616 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6617 IWineD3DDeviceImpl_SetRenderState,
6618 IWineD3DDeviceImpl_GetRenderState,
6619 IWineD3DDeviceImpl_SetRenderTarget,
6620 IWineD3DDeviceImpl_GetRenderTarget,
6621 IWineD3DDeviceImpl_SetFrontBackBuffers,
6622 IWineD3DDeviceImpl_SetSamplerState,
6623 IWineD3DDeviceImpl_GetSamplerState,
6624 IWineD3DDeviceImpl_SetScissorRect,
6625 IWineD3DDeviceImpl_GetScissorRect,
6626 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6627 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6628 IWineD3DDeviceImpl_SetStreamSource,
6629 IWineD3DDeviceImpl_GetStreamSource,
6630 IWineD3DDeviceImpl_SetStreamSourceFreq,
6631 IWineD3DDeviceImpl_GetStreamSourceFreq,
6632 IWineD3DDeviceImpl_SetTexture,
6633 IWineD3DDeviceImpl_GetTexture,
6634 IWineD3DDeviceImpl_SetTextureStageState,
6635 IWineD3DDeviceImpl_GetTextureStageState,
6636 IWineD3DDeviceImpl_SetTransform,
6637 IWineD3DDeviceImpl_GetTransform,
6638 IWineD3DDeviceImpl_SetVertexDeclaration,
6639 IWineD3DDeviceImpl_GetVertexDeclaration,
6640 IWineD3DDeviceImpl_SetVertexShader,
6641 IWineD3DDeviceImpl_GetVertexShader,
6642 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6643 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6644 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6645 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6646 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6647 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6648 IWineD3DDeviceImpl_SetViewport,
6649 IWineD3DDeviceImpl_GetViewport,
6650 IWineD3DDeviceImpl_MultiplyTransform,
6651 IWineD3DDeviceImpl_ValidateDevice,
6652 IWineD3DDeviceImpl_ProcessVertices,
6653 /*** State block ***/
6654 IWineD3DDeviceImpl_BeginStateBlock,
6655 IWineD3DDeviceImpl_EndStateBlock,
6656 /*** Scene management ***/
6657 IWineD3DDeviceImpl_BeginScene,
6658 IWineD3DDeviceImpl_EndScene,
6659 IWineD3DDeviceImpl_Present,
6660 IWineD3DDeviceImpl_Clear,
6661 /*** Drawing ***/
6662 IWineD3DDeviceImpl_DrawPrimitive,
6663 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6664 IWineD3DDeviceImpl_DrawPrimitiveUP,
6665 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6666 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6667 IWineD3DDeviceImpl_DrawRectPatch,
6668 IWineD3DDeviceImpl_DrawTriPatch,
6669 IWineD3DDeviceImpl_DeletePatch,
6670 IWineD3DDeviceImpl_ColorFill,
6671 IWineD3DDeviceImpl_UpdateTexture,
6672 IWineD3DDeviceImpl_UpdateSurface,
6673 IWineD3DDeviceImpl_GetFrontBufferData,
6674 /*** object tracking ***/
6675 IWineD3DDeviceImpl_ResourceReleased
6679 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6680 WINED3DRS_ALPHABLENDENABLE ,
6681 WINED3DRS_ALPHAFUNC ,
6682 WINED3DRS_ALPHAREF ,
6683 WINED3DRS_ALPHATESTENABLE ,
6684 WINED3DRS_BLENDOP ,
6685 WINED3DRS_COLORWRITEENABLE ,
6686 WINED3DRS_DESTBLEND ,
6687 WINED3DRS_DITHERENABLE ,
6688 WINED3DRS_FILLMODE ,
6689 WINED3DRS_FOGDENSITY ,
6690 WINED3DRS_FOGEND ,
6691 WINED3DRS_FOGSTART ,
6692 WINED3DRS_LASTPIXEL ,
6693 WINED3DRS_SHADEMODE ,
6694 WINED3DRS_SRCBLEND ,
6695 WINED3DRS_STENCILENABLE ,
6696 WINED3DRS_STENCILFAIL ,
6697 WINED3DRS_STENCILFUNC ,
6698 WINED3DRS_STENCILMASK ,
6699 WINED3DRS_STENCILPASS ,
6700 WINED3DRS_STENCILREF ,
6701 WINED3DRS_STENCILWRITEMASK ,
6702 WINED3DRS_STENCILZFAIL ,
6703 WINED3DRS_TEXTUREFACTOR ,
6704 WINED3DRS_WRAP0 ,
6705 WINED3DRS_WRAP1 ,
6706 WINED3DRS_WRAP2 ,
6707 WINED3DRS_WRAP3 ,
6708 WINED3DRS_WRAP4 ,
6709 WINED3DRS_WRAP5 ,
6710 WINED3DRS_WRAP6 ,
6711 WINED3DRS_WRAP7 ,
6712 WINED3DRS_ZENABLE ,
6713 WINED3DRS_ZFUNC ,
6714 WINED3DRS_ZWRITEENABLE
6717 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6718 WINED3DTSS_ADDRESSW ,
6719 WINED3DTSS_ALPHAARG0 ,
6720 WINED3DTSS_ALPHAARG1 ,
6721 WINED3DTSS_ALPHAARG2 ,
6722 WINED3DTSS_ALPHAOP ,
6723 WINED3DTSS_BUMPENVLOFFSET ,
6724 WINED3DTSS_BUMPENVLSCALE ,
6725 WINED3DTSS_BUMPENVMAT00 ,
6726 WINED3DTSS_BUMPENVMAT01 ,
6727 WINED3DTSS_BUMPENVMAT10 ,
6728 WINED3DTSS_BUMPENVMAT11 ,
6729 WINED3DTSS_COLORARG0 ,
6730 WINED3DTSS_COLORARG1 ,
6731 WINED3DTSS_COLORARG2 ,
6732 WINED3DTSS_COLOROP ,
6733 WINED3DTSS_RESULTARG ,
6734 WINED3DTSS_TEXCOORDINDEX ,
6735 WINED3DTSS_TEXTURETRANSFORMFLAGS
6738 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6739 WINED3DSAMP_ADDRESSU ,
6740 WINED3DSAMP_ADDRESSV ,
6741 WINED3DSAMP_ADDRESSW ,
6742 WINED3DSAMP_BORDERCOLOR ,
6743 WINED3DSAMP_MAGFILTER ,
6744 WINED3DSAMP_MINFILTER ,
6745 WINED3DSAMP_MIPFILTER ,
6746 WINED3DSAMP_MIPMAPLODBIAS ,
6747 WINED3DSAMP_MAXMIPLEVEL ,
6748 WINED3DSAMP_MAXANISOTROPY ,
6749 WINED3DSAMP_SRGBTEXTURE ,
6750 WINED3DSAMP_ELEMENTINDEX
6753 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6754 WINED3DRS_AMBIENT ,
6755 WINED3DRS_AMBIENTMATERIALSOURCE ,
6756 WINED3DRS_CLIPPING ,
6757 WINED3DRS_CLIPPLANEENABLE ,
6758 WINED3DRS_COLORVERTEX ,
6759 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6760 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6761 WINED3DRS_FOGDENSITY ,
6762 WINED3DRS_FOGEND ,
6763 WINED3DRS_FOGSTART ,
6764 WINED3DRS_FOGTABLEMODE ,
6765 WINED3DRS_FOGVERTEXMODE ,
6766 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6767 WINED3DRS_LIGHTING ,
6768 WINED3DRS_LOCALVIEWER ,
6769 WINED3DRS_MULTISAMPLEANTIALIAS ,
6770 WINED3DRS_MULTISAMPLEMASK ,
6771 WINED3DRS_NORMALIZENORMALS ,
6772 WINED3DRS_PATCHEDGESTYLE ,
6773 WINED3DRS_POINTSCALE_A ,
6774 WINED3DRS_POINTSCALE_B ,
6775 WINED3DRS_POINTSCALE_C ,
6776 WINED3DRS_POINTSCALEENABLE ,
6777 WINED3DRS_POINTSIZE ,
6778 WINED3DRS_POINTSIZE_MAX ,
6779 WINED3DRS_POINTSIZE_MIN ,
6780 WINED3DRS_POINTSPRITEENABLE ,
6781 WINED3DRS_RANGEFOGENABLE ,
6782 WINED3DRS_SPECULARMATERIALSOURCE ,
6783 WINED3DRS_TWEENFACTOR ,
6784 WINED3DRS_VERTEXBLEND
6787 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6788 WINED3DTSS_TEXCOORDINDEX ,
6789 WINED3DTSS_TEXTURETRANSFORMFLAGS
6792 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6793 WINED3DSAMP_DMAPOFFSET
6796 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6797 DWORD rep = StateTable[state].representative;
6798 DWORD idx;
6799 BYTE shift;
6800 UINT i;
6801 WineD3DContext *context;
6803 if(!rep) return;
6804 for(i = 0; i < This->numContexts; i++) {
6805 context = This->contexts[i];
6806 if(isStateDirty(context, rep)) continue;
6808 context->dirtyArray[context->numDirtyEntries++] = rep;
6809 idx = rep >> 5;
6810 shift = rep & 0x1f;
6811 context->isStateDirty[idx] |= (1 << shift);