wined3d: Use UINT instead of uint.
[wine.git] / dlls / wined3d / device.c
blob65c5382c46113b5794529e5b7780f29bd34936ba
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
141 _basetexture.is_srgb = FALSE; \
142 _basetexture.srgb_mode_change_count = 0; \
145 /**********************************************************
146 * Global variable / Constants follow
147 **********************************************************/
148 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
150 /**********************************************************
151 * IUnknown parts follows
152 **********************************************************/
154 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
158 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
159 if (IsEqualGUID(riid, &IID_IUnknown)
160 || IsEqualGUID(riid, &IID_IWineD3DBase)
161 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
162 IUnknown_AddRef(iface);
163 *ppobj = This;
164 return S_OK;
166 *ppobj = NULL;
167 return E_NOINTERFACE;
170 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 ULONG refCount = InterlockedIncrement(&This->ref);
174 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
175 return refCount;
178 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
180 ULONG refCount = InterlockedDecrement(&This->ref);
182 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
184 if (!refCount) {
185 if (This->fbo) {
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
188 if (This->src_fbo) {
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
191 if (This->dst_fbo) {
192 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
195 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
197 /* TODO: Clean up all the surfaces and textures! */
198 /* NOTE: You must release the parent if the object was created via a callback
199 ** ***************************/
201 if (This->resources != NULL ) {
202 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
203 dumpResources(This->resources);
206 if(This->contexts) ERR("Context array not freed!\n");
207 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
208 This->haveHardwareCursor = FALSE;
210 IWineD3D_Release(This->wineD3D);
211 This->wineD3D = NULL;
212 HeapFree(GetProcessHeap(), 0, This);
213 TRACE("Freed device %p\n", This);
214 This = NULL;
216 return refCount;
219 /**********************************************************
220 * IWineD3DDevice implementation follows
221 **********************************************************/
222 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
224 *pParent = This->parent;
225 IUnknown_AddRef(This->parent);
226 return WINED3D_OK;
229 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
230 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
231 GLenum error, glUsage;
232 DWORD vboUsage = object->resource.usage;
233 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
234 WARN("Creating a vbo failed once, not trying again\n");
235 return;
238 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
240 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
241 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
242 ENTER_GL();
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 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
371 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
372 ENTER_GL();
374 while(glGetError());
376 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
377 error = glGetError();
378 if(error != GL_NO_ERROR || object->vbo == 0) {
379 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
380 goto out;
383 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
384 error = glGetError();
385 if(error != GL_NO_ERROR) {
386 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
387 goto out;
390 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
391 * copy no readback will be needed
393 glUsage = GL_STATIC_DRAW_ARB;
394 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
395 error = glGetError();
396 if(error != GL_NO_ERROR) {
397 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
398 goto out;
400 LEAVE_GL();
401 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
402 return;
404 out:
405 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
406 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
407 LEAVE_GL();
408 object->vbo = 0;
411 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
412 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
413 HANDLE *sharedHandle, IUnknown *parent) {
414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
415 IWineD3DIndexBufferImpl *object;
416 TRACE("(%p) Creating index buffer\n", This);
418 /* Allocate the storage for the device */
419 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
421 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
422 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
425 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
426 CreateIndexBufferVBO(This, object);
429 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
430 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
431 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
433 return WINED3D_OK;
436 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DStateBlockImpl *object;
440 int i, j;
441 HRESULT temp_result;
443 D3DCREATEOBJECTINSTANCE(object, StateBlock)
444 object->blockType = Type;
446 for(i = 0; i < LIGHTMAP_SIZE; i++) {
447 list_init(&object->lightMap[i]);
450 /* Special case - Used during initialization to produce a placeholder stateblock
451 so other functions called can update a state block */
452 if (Type == WINED3DSBT_INIT) {
453 /* Don't bother increasing the reference count otherwise a device will never
454 be freed due to circular dependencies */
455 return WINED3D_OK;
458 temp_result = allocate_shader_constants(object);
459 if (WINED3D_OK != temp_result)
460 return temp_result;
462 /* Otherwise, might as well set the whole state block to the appropriate values */
463 if (This->stateBlock != NULL)
464 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
465 else
466 memset(object->streamFreq, 1, sizeof(object->streamFreq));
468 /* Reset the ref and type after kludging it */
469 object->wineD3DDevice = This;
470 object->ref = 1;
471 object->blockType = Type;
473 TRACE("Updating changed flags appropriate for type %d\n", Type);
475 if (Type == WINED3DSBT_ALL) {
477 TRACE("ALL => Pretend everything has changed\n");
478 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
480 /* Lights are not part of the changed / set structure */
481 for(j = 0; j < LIGHTMAP_SIZE; j++) {
482 struct list *e;
483 LIST_FOR_EACH(e, &object->lightMap[j]) {
484 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
485 light->changed = TRUE;
486 light->enabledChanged = TRUE;
489 } else if (Type == WINED3DSBT_PIXELSTATE) {
491 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
492 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
494 object->changed.pixelShader = TRUE;
496 /* Pixel Shader Constants */
497 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
498 object->changed.pixelShaderConstantsF[i] = TRUE;
499 for (i = 0; i < MAX_CONST_B; ++i)
500 object->changed.pixelShaderConstantsB[i] = TRUE;
501 for (i = 0; i < MAX_CONST_I; ++i)
502 object->changed.pixelShaderConstantsI[i] = TRUE;
504 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
505 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
507 for (j = 0; j < MAX_TEXTURES; j++) {
508 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
509 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
512 for (j = 0 ; j < 16; j++) {
513 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
515 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
519 } else if (Type == WINED3DSBT_VERTEXSTATE) {
521 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
522 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
524 object->changed.vertexShader = TRUE;
526 /* Vertex Shader Constants */
527 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
528 object->changed.vertexShaderConstantsF[i] = TRUE;
529 for (i = 0; i < MAX_CONST_B; ++i)
530 object->changed.vertexShaderConstantsB[i] = TRUE;
531 for (i = 0; i < MAX_CONST_I; ++i)
532 object->changed.vertexShaderConstantsI[i] = TRUE;
534 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
535 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 for (j = 0; j < MAX_TEXTURES; j++) {
538 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
539 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
542 for (j = 0 ; j < 16; j++){
543 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
544 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
548 for(j = 0; j < LIGHTMAP_SIZE; j++) {
549 struct list *e;
550 LIST_FOR_EACH(e, &object->lightMap[j]) {
551 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
552 light->changed = TRUE;
553 light->enabledChanged = TRUE;
556 } else {
557 FIXME("Unrecognized state block type %d\n", Type);
560 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
561 return WINED3D_OK;
564 /* ************************************
565 MSDN:
566 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
568 Discard
569 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
571 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
573 ******************************** */
575 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
577 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
578 unsigned int Size = 1;
579 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
580 TRACE("(%p) Create surface\n",This);
582 /** FIXME: Check ranges on the inputs are valid
583 * MSDN
584 * MultisampleQuality
585 * [in] Quality level. The valid range is between zero and one less than the level
586 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
587 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
588 * values of paired render targets, depth stencil surfaces, and the MultiSample type
589 * must all match.
590 *******************************/
594 * TODO: Discard MSDN
595 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
597 * If this flag is set, the contents of the depth stencil buffer will be
598 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
599 * with a different depth surface.
601 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
602 ***************************/
604 if(MultisampleQuality < 0) {
605 FIXME("Invalid multisample level %d\n", MultisampleQuality);
606 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
609 if(MultisampleQuality > 0) {
610 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
611 MultisampleQuality=0;
614 /** FIXME: Check that the format is supported
615 * by the device.
616 *******************************/
618 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
619 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
620 * space!
621 *********************************/
622 if (WINED3DFMT_UNKNOWN == Format) {
623 Size = 0;
624 } else if (Format == WINED3DFMT_DXT1) {
625 /* DXT1 is half byte per pixel */
626 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
628 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
629 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
630 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
631 } else {
632 /* The pitch is a multiple of 4 bytes */
633 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
634 Size *= Height;
637 /** Create and initialise the surface resource **/
638 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
639 /* "Standalone" surface */
640 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
642 object->currentDesc.Width = Width;
643 object->currentDesc.Height = Height;
644 object->currentDesc.MultiSampleType = MultiSample;
645 object->currentDesc.MultiSampleQuality = MultisampleQuality;
646 object->glDescription.level = Level;
648 /* Flags */
649 object->Flags = 0;
650 object->Flags |= Discard ? SFLAG_DISCARD : 0;
651 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
652 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
655 if (WINED3DFMT_UNKNOWN != Format) {
656 object->bytesPerPixel = tableEntry->bpp;
657 } else {
658 object->bytesPerPixel = 0;
661 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
663 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
665 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
666 * this function is too deep to need to care about things like this.
667 * Levels need to be checked too, and possibly Type since they all affect what can be done.
668 * ****************************************/
669 switch(Pool) {
670 case WINED3DPOOL_SCRATCH:
671 if(!Lockable)
672 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
673 "which are mutually exclusive, setting lockable to TRUE\n");
674 Lockable = TRUE;
675 break;
676 case WINED3DPOOL_SYSTEMMEM:
677 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
678 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
679 case WINED3DPOOL_MANAGED:
680 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
681 "Usage of DYNAMIC which are mutually exclusive, not doing "
682 "anything just telling you.\n");
683 break;
684 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
685 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
686 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
687 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
688 break;
689 default:
690 FIXME("(%p) Unknown pool %d\n", This, Pool);
691 break;
694 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
695 FIXME("Trying to create a render target that isn't in the default pool\n");
698 /* mark the texture as dirty so that it gets loaded first time around*/
699 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
700 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
701 This, Width, Height, Format, debug_d3dformat(Format),
702 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
704 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
705 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
706 This->ddraw_primary = (IWineD3DSurface *) object;
708 /* Look at the implementation and set the correct Vtable */
709 switch(Impl) {
710 case SURFACE_OPENGL:
711 /* Check if a 3D adapter is available when creating gl surfaces */
712 if(!This->adapter) {
713 ERR("OpenGL surfaces are not available without opengl\n");
714 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
715 HeapFree(GetProcessHeap(), 0, object);
716 return WINED3DERR_NOTAVAILABLE;
718 break;
720 case SURFACE_GDI:
721 object->lpVtbl = &IWineGDISurface_Vtbl;
722 break;
724 default:
725 /* To be sure to catch this */
726 ERR("Unknown requested surface implementation %d!\n", Impl);
727 IWineD3DSurface_Release((IWineD3DSurface *) object);
728 return WINED3DERR_INVALIDCALL;
731 list_init(&object->renderbuffers);
733 /* Call the private setup routine */
734 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
738 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
739 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
740 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
741 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
744 IWineD3DTextureImpl *object;
745 unsigned int i;
746 UINT tmpW;
747 UINT tmpH;
748 HRESULT hr;
749 unsigned int pow2Width;
750 unsigned int pow2Height;
753 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
754 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
755 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
757 /* TODO: It should only be possible to create textures for formats
758 that are reported as supported */
759 if (WINED3DFMT_UNKNOWN >= Format) {
760 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
761 return WINED3DERR_INVALIDCALL;
764 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
765 D3DINITIALIZEBASETEXTURE(object->baseTexture);
766 object->width = Width;
767 object->height = Height;
769 /** Non-power2 support **/
770 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
771 pow2Width = Width;
772 pow2Height = Height;
773 } else {
774 /* Find the nearest pow2 match */
775 pow2Width = pow2Height = 1;
776 while (pow2Width < Width) pow2Width <<= 1;
777 while (pow2Height < Height) pow2Height <<= 1;
780 /** FIXME: add support for real non-power-two if it's provided by the video card **/
781 /* Precalculated scaling for 'faked' non power of two texture coords */
782 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
783 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
784 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
786 /* Calculate levels for mip mapping */
787 if (Levels == 0) {
788 TRACE("calculating levels %d\n", object->baseTexture.levels);
789 object->baseTexture.levels++;
790 tmpW = Width;
791 tmpH = Height;
792 while (tmpW > 1 || tmpH > 1) {
793 tmpW = max(1, tmpW >> 1);
794 tmpH = max(1, tmpH >> 1);
795 object->baseTexture.levels++;
797 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
800 /* Generate all the surfaces */
801 tmpW = Width;
802 tmpH = Height;
803 for (i = 0; i < object->baseTexture.levels; i++)
805 /* use the callback to create the texture surface */
806 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
807 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
808 FIXME("Failed to create surface %p\n", object);
809 /* clean up */
810 object->surfaces[i] = NULL;
811 IWineD3DTexture_Release((IWineD3DTexture *)object);
813 *ppTexture = NULL;
814 return hr;
817 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
818 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
819 /* calculate the next mipmap level */
820 tmpW = max(1, tmpW >> 1);
821 tmpH = max(1, tmpH >> 1);
824 TRACE("(%p) : Created texture %p\n", This, object);
825 return WINED3D_OK;
828 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
829 UINT Width, UINT Height, UINT Depth,
830 UINT Levels, DWORD Usage,
831 WINED3DFORMAT Format, WINED3DPOOL Pool,
832 IWineD3DVolumeTexture **ppVolumeTexture,
833 HANDLE *pSharedHandle, IUnknown *parent,
834 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
837 IWineD3DVolumeTextureImpl *object;
838 unsigned int i;
839 UINT tmpW;
840 UINT tmpH;
841 UINT tmpD;
843 /* TODO: It should only be possible to create textures for formats
844 that are reported as supported */
845 if (WINED3DFMT_UNKNOWN >= Format) {
846 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
847 return WINED3DERR_INVALIDCALL;
850 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
851 D3DINITIALIZEBASETEXTURE(object->baseTexture);
853 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
854 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
856 object->width = Width;
857 object->height = Height;
858 object->depth = Depth;
860 /* Calculate levels for mip mapping */
861 if (Levels == 0) {
862 object->baseTexture.levels++;
863 tmpW = Width;
864 tmpH = Height;
865 tmpD = Depth;
866 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
867 tmpW = max(1, tmpW >> 1);
868 tmpH = max(1, tmpH >> 1);
869 tmpD = max(1, tmpD >> 1);
870 object->baseTexture.levels++;
872 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
875 /* Generate all the surfaces */
876 tmpW = Width;
877 tmpH = Height;
878 tmpD = Depth;
880 for (i = 0; i < object->baseTexture.levels; i++)
882 HRESULT hr;
883 /* Create the volume */
884 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
885 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
887 if(FAILED(hr)) {
888 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
889 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
890 *ppVolumeTexture = NULL;
891 return hr;
894 /* Set its container to this object */
895 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
897 /* calcualte the next mipmap level */
898 tmpW = max(1, tmpW >> 1);
899 tmpH = max(1, tmpH >> 1);
900 tmpD = max(1, tmpD >> 1);
903 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
904 TRACE("(%p) : Created volume texture %p\n", This, object);
905 return WINED3D_OK;
908 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
909 UINT Width, UINT Height, UINT Depth,
910 DWORD Usage,
911 WINED3DFORMAT Format, WINED3DPOOL Pool,
912 IWineD3DVolume** ppVolume,
913 HANDLE* pSharedHandle, IUnknown *parent) {
915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
916 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
917 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
919 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
921 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object->currentDesc.Width = Width;
925 object->currentDesc.Height = Height;
926 object->currentDesc.Depth = Depth;
927 object->bytesPerPixel = formatDesc->bpp;
929 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
930 object->lockable = TRUE;
931 object->locked = FALSE;
932 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
933 object->dirty = TRUE;
935 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
938 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
939 UINT Levels, DWORD Usage,
940 WINED3DFORMAT Format, WINED3DPOOL Pool,
941 IWineD3DCubeTexture **ppCubeTexture,
942 HANDLE *pSharedHandle, IUnknown *parent,
943 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
946 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
947 unsigned int i, j;
948 UINT tmpW;
949 HRESULT hr;
950 unsigned int pow2EdgeLength = EdgeLength;
952 /* TODO: It should only be possible to create textures for formats
953 that are reported as supported */
954 if (WINED3DFMT_UNKNOWN >= Format) {
955 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
956 return WINED3DERR_INVALIDCALL;
959 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
960 WARN("(%p) : Tried to create not supported cube texture\n", This);
961 return WINED3DERR_INVALIDCALL;
964 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
965 D3DINITIALIZEBASETEXTURE(object->baseTexture);
967 TRACE("(%p) Create Cube Texture\n", This);
969 /** Non-power2 support **/
971 /* Find the nearest pow2 match */
972 pow2EdgeLength = 1;
973 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
975 object->edgeLength = EdgeLength;
976 /* TODO: support for native non-power 2 */
977 /* Precalculated scaling for 'faked' non power of two texture coords */
978 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
980 /* Calculate levels for mip mapping */
981 if (Levels == 0) {
982 object->baseTexture.levels++;
983 tmpW = EdgeLength;
984 while (tmpW > 1) {
985 tmpW = max(1, tmpW >> 1);
986 object->baseTexture.levels++;
988 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
991 /* Generate all the surfaces */
992 tmpW = EdgeLength;
993 for (i = 0; i < object->baseTexture.levels; i++) {
995 /* Create the 6 faces */
996 for (j = 0; j < 6; j++) {
998 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
999 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1001 if(hr!= WINED3D_OK) {
1002 /* clean up */
1003 int k;
1004 int l;
1005 for (l = 0; l < j; l++) {
1006 IWineD3DSurface_Release(object->surfaces[j][i]);
1008 for (k = 0; k < i; k++) {
1009 for (l = 0; l < 6; l++) {
1010 IWineD3DSurface_Release(object->surfaces[l][j]);
1014 FIXME("(%p) Failed to create surface\n",object);
1015 HeapFree(GetProcessHeap(),0,object);
1016 *ppCubeTexture = NULL;
1017 return hr;
1019 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1020 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1022 tmpW = max(1, tmpW >> 1);
1025 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1026 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1027 return WINED3D_OK;
1030 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1032 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1033 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1035 /* Just a check to see if we support this type of query */
1036 switch(Type) {
1037 case WINED3DQUERYTYPE_OCCLUSION:
1038 TRACE("(%p) occlusion query\n", This);
1039 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1040 hr = WINED3D_OK;
1041 else
1042 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1043 break;
1045 case WINED3DQUERYTYPE_EVENT:
1046 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1047 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1048 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1050 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1052 hr = WINED3D_OK;
1053 break;
1055 case WINED3DQUERYTYPE_VCACHE:
1056 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1057 case WINED3DQUERYTYPE_VERTEXSTATS:
1058 case WINED3DQUERYTYPE_TIMESTAMP:
1059 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1060 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1061 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1062 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1063 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1064 case WINED3DQUERYTYPE_PIXELTIMINGS:
1065 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1066 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1067 default:
1068 FIXME("(%p) Unhandled query type %d\n", This, Type);
1070 if(NULL == ppQuery || hr != WINED3D_OK) {
1071 return hr;
1074 D3DCREATEOBJECTINSTANCE(object, Query)
1075 object->type = Type;
1076 /* allocated the 'extended' data based on the type of query requested */
1077 switch(Type){
1078 case WINED3DQUERYTYPE_OCCLUSION:
1079 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1080 TRACE("(%p) Allocating data for an occlusion query\n", This);
1081 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1082 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1083 break;
1085 case WINED3DQUERYTYPE_EVENT:
1086 /* TODO: GL_APPLE_fence */
1087 if(GL_SUPPORT(APPLE_FENCE)) {
1088 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1089 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1090 checkGLcall("glGenFencesAPPLE");
1091 } else if(GL_SUPPORT(NV_FENCE)) {
1092 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1093 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1094 checkGLcall("glGenFencesNV");
1096 break;
1098 case WINED3DQUERYTYPE_VCACHE:
1099 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1100 case WINED3DQUERYTYPE_VERTEXSTATS:
1101 case WINED3DQUERYTYPE_TIMESTAMP:
1102 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1103 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1104 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1105 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1106 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1107 case WINED3DQUERYTYPE_PIXELTIMINGS:
1108 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1109 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1110 default:
1111 object->extendedData = 0;
1112 FIXME("(%p) Unhandled query type %d\n",This , Type);
1114 TRACE("(%p) : Created Query %p\n", This, object);
1115 return WINED3D_OK;
1118 /*****************************************************************************
1119 * IWineD3DDeviceImpl_SetupFullscreenWindow
1121 * Helper function that modifies a HWND's Style and ExStyle for proper
1122 * fullscreen use.
1124 * Params:
1125 * iface: Pointer to the IWineD3DDevice interface
1126 * window: Window to setup
1128 *****************************************************************************/
1129 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1132 LONG style, exStyle;
1133 /* Don't do anything if an original style is stored.
1134 * That shouldn't happen
1136 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1137 if (This->style || This->exStyle) {
1138 ERR("(%p): Want to change the window parameters of HWND %p, but "
1139 "another style is stored for restoration afterwards\n", This, window);
1142 /* Get the parameters and save them */
1143 style = GetWindowLongW(window, GWL_STYLE);
1144 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1145 This->style = style;
1146 This->exStyle = exStyle;
1148 /* Filter out window decorations */
1149 style &= ~WS_CAPTION;
1150 style &= ~WS_THICKFRAME;
1151 exStyle &= ~WS_EX_WINDOWEDGE;
1152 exStyle &= ~WS_EX_CLIENTEDGE;
1154 /* Make sure the window is managed, otherwise we won't get keyboard input */
1155 style |= WS_POPUP | WS_SYSMENU;
1157 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1158 This->style, This->exStyle, style, exStyle);
1160 SetWindowLongW(window, GWL_STYLE, style);
1161 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1163 /* Inform the window about the update. */
1164 SetWindowPos(window, HWND_TOP, 0, 0,
1165 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1166 ShowWindow(window, SW_NORMAL);
1169 /*****************************************************************************
1170 * IWineD3DDeviceImpl_RestoreWindow
1172 * Helper function that restores a windows' properties when taking it out
1173 * of fullscreen mode
1175 * Params:
1176 * iface: Pointer to the IWineD3DDevice interface
1177 * window: Window to setup
1179 *****************************************************************************/
1180 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1183 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1184 * switch, do nothing
1186 if (!This->style && !This->exStyle) return;
1188 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1189 This, window, This->style, This->exStyle);
1191 SetWindowLongW(window, GWL_STYLE, This->style);
1192 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1194 /* Delete the old values */
1195 This->style = 0;
1196 This->exStyle = 0;
1198 /* Inform the window about the update */
1199 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1200 0, 0, 0, 0, /* Pos, Size, ignored */
1201 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1204 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1205 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1206 IUnknown* parent,
1207 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1208 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1211 HDC hDc;
1212 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1213 HRESULT hr = WINED3D_OK;
1214 IUnknown *bufferParent;
1215 Display *display;
1217 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1219 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1220 * does a device hold a reference to a swap chain giving them a lifetime of the device
1221 * or does the swap chain notify the device of its destruction.
1222 *******************************/
1224 /* Check the params */
1225 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1226 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1227 return WINED3DERR_INVALIDCALL;
1228 } else if (pPresentationParameters->BackBufferCount > 1) {
1229 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1232 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1234 /*********************
1235 * Lookup the window Handle and the relating X window handle
1236 ********************/
1238 /* Setup hwnd we are using, plus which display this equates to */
1239 object->win_handle = pPresentationParameters->hDeviceWindow;
1240 if (!object->win_handle) {
1241 object->win_handle = This->createParms.hFocusWindow;
1244 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1245 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1246 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1247 return WINED3DERR_NOTAVAILABLE;
1249 hDc = GetDC(object->win_handle);
1250 display = get_display(hDc);
1251 ReleaseDC(object->win_handle, hDc);
1252 TRACE("Using a display of %p %p\n", display, hDc);
1254 if (NULL == display || NULL == hDc) {
1255 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1256 return WINED3DERR_NOTAVAILABLE;
1259 if (object->win == 0) {
1260 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1261 return WINED3DERR_NOTAVAILABLE;
1264 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1265 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1266 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1268 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1269 * then the corresponding dimension of the client area of the hDeviceWindow
1270 * (or the focus window, if hDeviceWindow is NULL) is taken.
1271 **********************/
1273 if (pPresentationParameters->Windowed &&
1274 ((pPresentationParameters->BackBufferWidth == 0) ||
1275 (pPresentationParameters->BackBufferHeight == 0))) {
1277 RECT Rect;
1278 GetClientRect(object->win_handle, &Rect);
1280 if (pPresentationParameters->BackBufferWidth == 0) {
1281 pPresentationParameters->BackBufferWidth = Rect.right;
1282 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1284 if (pPresentationParameters->BackBufferHeight == 0) {
1285 pPresentationParameters->BackBufferHeight = Rect.bottom;
1286 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1290 /* Put the correct figures in the presentation parameters */
1291 TRACE("Copying across presentation parameters\n");
1292 object->presentParms = *pPresentationParameters;
1294 TRACE("calling rendertarget CB\n");
1295 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1296 parent,
1297 object->presentParms.BackBufferWidth,
1298 object->presentParms.BackBufferHeight,
1299 object->presentParms.BackBufferFormat,
1300 object->presentParms.MultiSampleType,
1301 object->presentParms.MultiSampleQuality,
1302 TRUE /* Lockable */,
1303 &object->frontBuffer,
1304 NULL /* pShared (always null)*/);
1305 if (object->frontBuffer != NULL) {
1306 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1307 } else {
1308 ERR("Failed to create the front buffer\n");
1309 goto error;
1313 * Create an opengl context for the display visual
1314 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1315 * use different properties after that point in time. FIXME: How to handle when requested format
1316 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1317 * it chooses is identical to the one already being used!
1318 **********************************/
1319 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1321 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1322 if(!object->context)
1323 return E_OUTOFMEMORY;
1324 object->num_contexts = 1;
1326 ENTER_GL();
1327 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1328 LEAVE_GL();
1330 if (!object->context[0]) {
1331 ERR("Failed to create a new context\n");
1332 hr = WINED3DERR_NOTAVAILABLE;
1333 goto error;
1334 } else {
1335 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1336 object->win_handle, object->context[0]->glCtx, object->win);
1339 /*********************
1340 * Windowed / Fullscreen
1341 *******************/
1344 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1345 * so we should really check to see if there is a fullscreen swapchain already
1346 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1347 **************************************/
1349 if (!pPresentationParameters->Windowed) {
1351 DEVMODEW devmode;
1352 HDC hdc;
1353 int bpp = 0;
1354 RECT clip_rc;
1356 /* Get info on the current display setup */
1357 hdc = GetDC(0);
1358 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1359 ReleaseDC(0, hdc);
1361 /* Change the display settings */
1362 memset(&devmode, 0, sizeof(devmode));
1363 devmode.dmSize = sizeof(devmode);
1364 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1365 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1366 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1367 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1368 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1369 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1371 /* For GetDisplayMode */
1372 This->ddraw_width = devmode.dmPelsWidth;
1373 This->ddraw_height = devmode.dmPelsHeight;
1374 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1376 IWineD3DDevice_SetFullscreen(iface, TRUE);
1378 /* And finally clip mouse to our screen */
1379 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1380 ClipCursor(&clip_rc);
1383 /*********************
1384 * Create the back, front and stencil buffers
1385 *******************/
1386 if(object->presentParms.BackBufferCount > 0) {
1387 int i;
1389 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1390 if(!object->backBuffer) {
1391 ERR("Out of memory\n");
1392 hr = E_OUTOFMEMORY;
1393 goto error;
1396 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1397 TRACE("calling rendertarget CB\n");
1398 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1399 parent,
1400 object->presentParms.BackBufferWidth,
1401 object->presentParms.BackBufferHeight,
1402 object->presentParms.BackBufferFormat,
1403 object->presentParms.MultiSampleType,
1404 object->presentParms.MultiSampleQuality,
1405 TRUE /* Lockable */,
1406 &object->backBuffer[i],
1407 NULL /* pShared (always null)*/);
1408 if(hr == WINED3D_OK && object->backBuffer[i]) {
1409 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1410 } else {
1411 ERR("Cannot create new back buffer\n");
1412 goto error;
1414 ENTER_GL();
1415 glDrawBuffer(GL_BACK);
1416 checkGLcall("glDrawBuffer(GL_BACK)");
1417 LEAVE_GL();
1419 } else {
1420 object->backBuffer = NULL;
1422 /* Single buffering - draw to front buffer */
1423 ENTER_GL();
1424 glDrawBuffer(GL_FRONT);
1425 checkGLcall("glDrawBuffer(GL_FRONT)");
1426 LEAVE_GL();
1429 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1430 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1431 TRACE("Creating depth stencil buffer\n");
1432 if (This->depthStencilBuffer == NULL ) {
1433 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1434 parent,
1435 object->presentParms.BackBufferWidth,
1436 object->presentParms.BackBufferHeight,
1437 object->presentParms.AutoDepthStencilFormat,
1438 object->presentParms.MultiSampleType,
1439 object->presentParms.MultiSampleQuality,
1440 FALSE /* FIXME: Discard */,
1441 &This->depthStencilBuffer,
1442 NULL /* pShared (always null)*/ );
1443 if (This->depthStencilBuffer != NULL)
1444 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1447 /** TODO: A check on width, height and multisample types
1448 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1449 ****************************/
1450 object->wantsDepthStencilBuffer = TRUE;
1451 } else {
1452 object->wantsDepthStencilBuffer = FALSE;
1455 TRACE("Created swapchain %p\n", object);
1456 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1457 return WINED3D_OK;
1459 error:
1460 if (object->backBuffer) {
1461 int i;
1462 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1463 if(object->backBuffer[i]) {
1464 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1465 IUnknown_Release(bufferParent); /* once for the get parent */
1466 if (IUnknown_Release(bufferParent) > 0) {
1467 FIXME("(%p) Something's still holding the back buffer\n",This);
1471 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1472 object->backBuffer = NULL;
1474 if(object->context[0])
1475 DestroyContext(This, object->context[0]);
1476 if(object->frontBuffer) {
1477 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1478 IUnknown_Release(bufferParent); /* once for the get parent */
1479 if (IUnknown_Release(bufferParent) > 0) {
1480 FIXME("(%p) Something's still holding the front buffer\n",This);
1483 HeapFree(GetProcessHeap(), 0, object);
1484 return hr;
1487 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1488 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1490 TRACE("(%p)\n", This);
1492 return This->NumberOfSwapChains;
1495 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1497 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1499 if(iSwapChain < This->NumberOfSwapChains) {
1500 *pSwapChain = This->swapchains[iSwapChain];
1501 IWineD3DSwapChain_AddRef(*pSwapChain);
1502 TRACE("(%p) returning %p\n", This, *pSwapChain);
1503 return WINED3D_OK;
1504 } else {
1505 TRACE("Swapchain out of range\n");
1506 *pSwapChain = NULL;
1507 return WINED3DERR_INVALIDCALL;
1511 /*****
1512 * Vertex Declaration
1513 *****/
1514 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1515 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1517 IWineD3DVertexDeclarationImpl *object = NULL;
1518 HRESULT hr = WINED3D_OK;
1520 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1521 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1523 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1525 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1527 return hr;
1530 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1532 unsigned int idx, idx2;
1533 unsigned int offset;
1534 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1535 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1536 BOOL has_blend_idx = has_blend &&
1537 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1538 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1539 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1540 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1541 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1542 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1543 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1545 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1546 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1548 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1549 WINED3DVERTEXELEMENT *elements = NULL;
1551 unsigned int size;
1552 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1553 if (has_blend_idx) num_blends--;
1555 /* Compute declaration size */
1556 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1557 has_psize + has_diffuse + has_specular + num_textures + 1;
1559 /* convert the declaration */
1560 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1561 if (!elements)
1562 return 0;
1564 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1565 idx = 0;
1566 if (has_pos) {
1567 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1568 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1569 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1571 else {
1572 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1573 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1575 elements[idx].UsageIndex = 0;
1576 idx++;
1578 if (has_blend && (num_blends > 0)) {
1579 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1580 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1581 else
1582 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1583 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1584 elements[idx].UsageIndex = 0;
1585 idx++;
1587 if (has_blend_idx) {
1588 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1589 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1590 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1591 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1592 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1593 else
1594 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1595 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1596 elements[idx].UsageIndex = 0;
1597 idx++;
1599 if (has_normal) {
1600 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1601 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1602 elements[idx].UsageIndex = 0;
1603 idx++;
1605 if (has_psize) {
1606 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1607 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1608 elements[idx].UsageIndex = 0;
1609 idx++;
1611 if (has_diffuse) {
1612 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1613 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1614 elements[idx].UsageIndex = 0;
1615 idx++;
1617 if (has_specular) {
1618 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1619 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1620 elements[idx].UsageIndex = 1;
1621 idx++;
1623 for (idx2 = 0; idx2 < num_textures; idx2++) {
1624 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1625 switch (numcoords) {
1626 case WINED3DFVF_TEXTUREFORMAT1:
1627 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1628 break;
1629 case WINED3DFVF_TEXTUREFORMAT2:
1630 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1631 break;
1632 case WINED3DFVF_TEXTUREFORMAT3:
1633 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1634 break;
1635 case WINED3DFVF_TEXTUREFORMAT4:
1636 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1637 break;
1639 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1640 elements[idx].UsageIndex = idx2;
1641 idx++;
1644 /* Now compute offsets, and initialize the rest of the fields */
1645 for (idx = 0, offset = 0; idx < size-1; idx++) {
1646 elements[idx].Stream = 0;
1647 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1648 elements[idx].Offset = offset;
1649 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1652 *ppVertexElements = elements;
1653 return size;
1656 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1657 WINED3DVERTEXELEMENT* elements = NULL;
1658 size_t size;
1659 DWORD hr;
1661 size = ConvertFvfToDeclaration(Fvf, &elements);
1662 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1664 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1665 HeapFree(GetProcessHeap(), 0, elements);
1666 if (hr != S_OK) return hr;
1668 return WINED3D_OK;
1671 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1672 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1674 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1675 HRESULT hr = WINED3D_OK;
1676 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1677 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1679 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1681 if (vertex_declaration) {
1682 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1685 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1687 if (WINED3D_OK != hr) {
1688 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1689 IWineD3DVertexShader_Release(*ppVertexShader);
1690 return WINED3DERR_INVALIDCALL;
1693 return WINED3D_OK;
1696 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1698 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1699 HRESULT hr = WINED3D_OK;
1701 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1702 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1703 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1704 if (WINED3D_OK == hr) {
1705 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1706 } else {
1707 WARN("(%p) : Failed to create pixel shader\n", This);
1710 return hr;
1713 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1715 IWineD3DPaletteImpl *object;
1716 HRESULT hr;
1717 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1719 /* Create the new object */
1720 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1721 if(!object) {
1722 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1723 return E_OUTOFMEMORY;
1726 object->lpVtbl = &IWineD3DPalette_Vtbl;
1727 object->ref = 1;
1728 object->Flags = Flags;
1729 object->parent = Parent;
1730 object->wineD3DDevice = This;
1731 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1733 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1735 if(!object->hpal) {
1736 HeapFree( GetProcessHeap(), 0, object);
1737 return E_OUTOFMEMORY;
1740 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1741 if(FAILED(hr)) {
1742 IWineD3DPalette_Release((IWineD3DPalette *) object);
1743 return hr;
1746 *Palette = (IWineD3DPalette *) object;
1748 return WINED3D_OK;
1751 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1753 IWineD3DSwapChainImpl *swapchain;
1754 HRESULT hr;
1755 DWORD state;
1757 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1758 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1760 /* TODO: Test if OpenGL is compiled in and loaded */
1762 TRACE("(%p) : Creating stateblock\n", This);
1763 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1764 hr = IWineD3DDevice_CreateStateBlock(iface,
1765 WINED3DSBT_INIT,
1766 (IWineD3DStateBlock **)&This->stateBlock,
1767 NULL);
1768 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1769 WARN("Failed to create stateblock\n");
1770 return hr;
1772 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1773 This->updateStateBlock = This->stateBlock;
1774 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1776 hr = allocate_shader_constants(This->updateStateBlock);
1777 if (WINED3D_OK != hr)
1778 return hr;
1780 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1781 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1782 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1784 /* Initialize the texture unit mapping to a 1:1 mapping */
1785 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1786 if (state < GL_LIMITS(fragment_samplers)) {
1787 This->texUnitMap[state] = state;
1788 This->rev_tex_unit_map[state] = state;
1789 } else {
1790 This->texUnitMap[state] = -1;
1791 This->rev_tex_unit_map[state] = -1;
1795 /* Setup the implicit swapchain */
1796 TRACE("Creating implicit swapchain\n");
1797 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1798 if (FAILED(hr) || !swapchain) {
1799 WARN("Failed to create implicit swapchain\n");
1800 return hr;
1803 This->NumberOfSwapChains = 1;
1804 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1805 if(!This->swapchains) {
1806 ERR("Out of memory!\n");
1807 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1808 return E_OUTOFMEMORY;
1810 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1812 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1814 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1815 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1816 This->render_targets[0] = swapchain->backBuffer[0];
1817 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1819 else {
1820 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1821 This->render_targets[0] = swapchain->frontBuffer;
1822 This->lastActiveRenderTarget = swapchain->frontBuffer;
1824 IWineD3DSurface_AddRef(This->render_targets[0]);
1825 This->activeContext = swapchain->context[0];
1826 This->lastThread = GetCurrentThreadId();
1828 /* Depth Stencil support */
1829 This->stencilBufferTarget = This->depthStencilBuffer;
1830 if (NULL != This->stencilBufferTarget) {
1831 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1834 /* Set up some starting GL setup */
1835 ENTER_GL();
1837 /* Setup all the devices defaults */
1838 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1839 #if 0
1840 IWineD3DImpl_CheckGraphicsMemory();
1841 #endif
1843 { /* Set a default viewport */
1844 WINED3DVIEWPORT vp;
1845 vp.X = 0;
1846 vp.Y = 0;
1847 vp.Width = pPresentationParameters->BackBufferWidth;
1848 vp.Height = pPresentationParameters->BackBufferHeight;
1849 vp.MinZ = 0.0f;
1850 vp.MaxZ = 1.0f;
1851 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1854 /* Initialize the current view state */
1855 This->view_ident = 1;
1856 This->contexts[0]->last_was_rhw = 0;
1857 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1858 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1860 switch(wined3d_settings.offscreen_rendering_mode) {
1861 case ORM_FBO:
1862 case ORM_PBUFFER:
1863 This->offscreenBuffer = GL_BACK;
1864 break;
1866 case ORM_BACKBUFFER:
1868 if(GL_LIMITS(aux_buffers) > 0) {
1869 TRACE("Using auxilliary buffer for offscreen rendering\n");
1870 This->offscreenBuffer = GL_AUX0;
1871 } else {
1872 TRACE("Using back buffer for offscreen rendering\n");
1873 This->offscreenBuffer = GL_BACK;
1878 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1879 LEAVE_GL();
1881 /* Clear the screen */
1882 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1883 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1884 0x00, 1.0, 0);
1886 This->d3d_initialized = TRUE;
1887 return WINED3D_OK;
1890 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1892 int sampler;
1893 UINT i;
1894 TRACE("(%p)\n", This);
1896 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1898 /* I don't think that the interface guarants that the device is destroyed from the same thread
1899 * it was created. Thus make sure a context is active for the glDelete* calls
1901 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1903 TRACE("Deleting high order patches\n");
1904 for(i = 0; i < PATCHMAP_SIZE; i++) {
1905 struct list *e1, *e2;
1906 struct WineD3DRectPatch *patch;
1907 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1908 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1909 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1913 /* Delete the pbuffer context if there is any */
1914 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1916 /* Delete the mouse cursor texture */
1917 if(This->cursorTexture) {
1918 ENTER_GL();
1919 glDeleteTextures(1, &This->cursorTexture);
1920 LEAVE_GL();
1921 This->cursorTexture = 0;
1924 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1925 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1927 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1928 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1931 /* Release the buffers (with sanity checks)*/
1932 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1933 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1934 if(This->depthStencilBuffer != This->stencilBufferTarget)
1935 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1937 This->stencilBufferTarget = NULL;
1939 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1940 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1941 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1943 TRACE("Setting rendertarget to NULL\n");
1944 This->render_targets[0] = NULL;
1946 if (This->depthStencilBuffer) {
1947 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1948 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1950 This->depthStencilBuffer = NULL;
1953 for(i=0; i < This->NumberOfSwapChains; i++) {
1954 TRACE("Releasing the implicit swapchain %d\n", i);
1955 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1956 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1960 HeapFree(GetProcessHeap(), 0, This->swapchains);
1961 This->swapchains = NULL;
1962 This->NumberOfSwapChains = 0;
1964 /* Release the update stateblock */
1965 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1966 if(This->updateStateBlock != This->stateBlock)
1967 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1969 This->updateStateBlock = NULL;
1971 { /* because were not doing proper internal refcounts releasing the primary state block
1972 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1973 to set this->stateBlock = NULL; first */
1974 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1975 This->stateBlock = NULL;
1977 /* Release the stateblock */
1978 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1979 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1983 HeapFree(GetProcessHeap(), 0, This->render_targets);
1984 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
1985 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1986 This->render_targets = NULL;
1987 This->fbo_color_attachments = NULL;
1988 This->draw_buffers = NULL;
1991 This->d3d_initialized = FALSE;
1992 return WINED3D_OK;
1995 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1997 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1999 /* Setup the window for fullscreen mode */
2000 if(fullscreen && !This->ddraw_fullscreen) {
2001 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2002 } else if(!fullscreen && This->ddraw_fullscreen) {
2003 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2006 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2007 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2008 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2009 * separately.
2011 This->ddraw_fullscreen = fullscreen;
2014 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2015 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2016 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2018 * There is no way to deactivate thread safety once it is enabled
2020 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2023 /*For now just store the flag(needed in case of ddraw) */
2024 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2026 return;
2029 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2030 DEVMODEW devmode;
2031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2032 LONG ret;
2033 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2034 RECT clip_rc;
2036 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2038 /* Resize the screen even without a window:
2039 * The app could have unset it with SetCooperativeLevel, but not called
2040 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2041 * but we don't have any hwnd
2044 memset(&devmode, 0, sizeof(devmode));
2045 devmode.dmSize = sizeof(devmode);
2046 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2047 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2048 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2049 devmode.dmPelsWidth = pMode->Width;
2050 devmode.dmPelsHeight = pMode->Height;
2052 devmode.dmDisplayFrequency = pMode->RefreshRate;
2053 if (pMode->RefreshRate != 0) {
2054 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2057 /* Only change the mode if necessary */
2058 if( (This->ddraw_width == pMode->Width) &&
2059 (This->ddraw_height == pMode->Height) &&
2060 (This->ddraw_format == pMode->Format) &&
2061 (pMode->RefreshRate == 0) ) {
2062 return WINED3D_OK;
2065 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2066 if (ret != DISP_CHANGE_SUCCESSFUL) {
2067 if(devmode.dmDisplayFrequency != 0) {
2068 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2069 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2070 devmode.dmDisplayFrequency = 0;
2071 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2073 if(ret != DISP_CHANGE_SUCCESSFUL) {
2074 return WINED3DERR_NOTAVAILABLE;
2078 /* Store the new values */
2079 This->ddraw_width = pMode->Width;
2080 This->ddraw_height = pMode->Height;
2081 This->ddraw_format = pMode->Format;
2083 /* Only do this with a window of course */
2084 if(This->ddraw_window)
2085 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2087 /* And finally clip mouse to our screen */
2088 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2089 ClipCursor(&clip_rc);
2091 return WINED3D_OK;
2094 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2096 *ppD3D= This->wineD3D;
2097 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2098 IWineD3D_AddRef(*ppD3D);
2099 return WINED3D_OK;
2102 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2103 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2104 * into the video ram as possible and seeing how many fit
2105 * you can also get the correct initial value from nvidia and ATI's driver via X
2106 * texture memory is video memory + AGP memory
2107 *******************/
2108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2109 static BOOL showfixmes = TRUE;
2110 if (showfixmes) {
2111 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2112 (wined3d_settings.emulated_textureram/(1024*1024)),
2113 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2114 showfixmes = FALSE;
2116 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2117 (wined3d_settings.emulated_textureram/(1024*1024)),
2118 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2119 /* return simulated texture memory left */
2120 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2125 /*****
2126 * Get / Set FVF
2127 *****/
2128 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2131 /* Update the current state block */
2132 This->updateStateBlock->changed.fvf = TRUE;
2133 This->updateStateBlock->set.fvf = TRUE;
2135 if(This->updateStateBlock->fvf == fvf) {
2136 TRACE("Application is setting the old fvf over, nothing to do\n");
2137 return WINED3D_OK;
2140 This->updateStateBlock->fvf = fvf;
2141 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2142 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2143 return WINED3D_OK;
2147 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2149 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2150 *pfvf = This->stateBlock->fvf;
2151 return WINED3D_OK;
2154 /*****
2155 * Get / Set Stream Source
2156 *****/
2157 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2159 IWineD3DVertexBuffer *oldSrc;
2161 if (StreamNumber >= MAX_STREAMS) {
2162 WARN("Stream out of range %d\n", StreamNumber);
2163 return WINED3DERR_INVALIDCALL;
2166 oldSrc = This->stateBlock->streamSource[StreamNumber];
2167 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2169 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2170 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2172 if(oldSrc == pStreamData &&
2173 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2174 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2175 TRACE("Application is setting the old values over, nothing to do\n");
2176 return WINED3D_OK;
2179 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2180 if (pStreamData) {
2181 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2182 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2185 /* Handle recording of state blocks */
2186 if (This->isRecordingState) {
2187 TRACE("Recording... not performing anything\n");
2188 return WINED3D_OK;
2191 /* Need to do a getParent and pass the reffs up */
2192 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2193 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2194 so for now, just count internally */
2195 if (pStreamData != NULL) {
2196 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2197 InterlockedIncrement(&vbImpl->bindCount);
2199 if (oldSrc != NULL) {
2200 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2205 return WINED3D_OK;
2208 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2211 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2212 This->stateBlock->streamSource[StreamNumber],
2213 This->stateBlock->streamOffset[StreamNumber],
2214 This->stateBlock->streamStride[StreamNumber]);
2216 if (StreamNumber >= MAX_STREAMS) {
2217 WARN("Stream out of range %d\n", StreamNumber);
2218 return WINED3DERR_INVALIDCALL;
2220 *pStream = This->stateBlock->streamSource[StreamNumber];
2221 *pStride = This->stateBlock->streamStride[StreamNumber];
2222 if (pOffset) {
2223 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2226 if (*pStream != NULL) {
2227 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2229 return WINED3D_OK;
2232 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2234 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2235 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2237 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2238 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2240 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2241 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2242 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2244 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2245 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2249 return WINED3D_OK;
2252 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2255 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2256 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2258 TRACE("(%p) : returning %d\n", This, *Divider);
2260 return WINED3D_OK;
2263 /*****
2264 * Get / Set & Multiply Transform
2265 *****/
2266 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2269 /* Most of this routine, comments included copied from ddraw tree initially: */
2270 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2272 /* Handle recording of state blocks */
2273 if (This->isRecordingState) {
2274 TRACE("Recording... not performing anything\n");
2275 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2276 This->updateStateBlock->set.transform[d3dts] = TRUE;
2277 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2278 return WINED3D_OK;
2282 * If the new matrix is the same as the current one,
2283 * we cut off any further processing. this seems to be a reasonable
2284 * optimization because as was noticed, some apps (warcraft3 for example)
2285 * tend towards setting the same matrix repeatedly for some reason.
2287 * From here on we assume that the new matrix is different, wherever it matters.
2289 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2290 TRACE("The app is setting the same matrix over again\n");
2291 return WINED3D_OK;
2292 } else {
2293 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2297 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2298 where ViewMat = Camera space, WorldMat = world space.
2300 In OpenGL, camera and world space is combined into GL_MODELVIEW
2301 matrix. The Projection matrix stay projection matrix.
2304 /* Capture the times we can just ignore the change for now */
2305 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2306 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2307 /* Handled by the state manager */
2310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2311 return WINED3D_OK;
2314 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2316 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2317 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2318 return WINED3D_OK;
2321 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2322 WINED3DMATRIX *mat = NULL;
2323 WINED3DMATRIX temp;
2325 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2326 * below means it will be recorded in a state block change, but it
2327 * works regardless where it is recorded.
2328 * If this is found to be wrong, change to StateBlock.
2330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2331 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2333 if (State < HIGHEST_TRANSFORMSTATE)
2335 mat = &This->updateStateBlock->transforms[State];
2336 } else {
2337 FIXME("Unhandled transform state!!\n");
2340 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2342 /* Apply change via set transform - will reapply to eg. lights this way */
2343 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2346 /*****
2347 * Get / Set Light
2348 *****/
2349 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2350 you can reference any indexes you want as long as that number max are enabled at any
2351 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2352 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2353 but when recording, just build a chain pretty much of commands to be replayed. */
2355 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2356 float rho;
2357 PLIGHTINFOEL *object = NULL;
2358 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2359 struct list *e;
2361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2362 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2364 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2365 * the gl driver.
2367 if(!pLight) {
2368 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2369 return WINED3DERR_INVALIDCALL;
2372 switch(pLight->Type) {
2373 case WINED3DLIGHT_POINT:
2374 case WINED3DLIGHT_SPOT:
2375 case WINED3DLIGHT_PARALLELPOINT:
2376 case WINED3DLIGHT_GLSPOT:
2377 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2378 * most wanted
2380 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2381 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2382 return WINED3DERR_INVALIDCALL;
2384 break;
2386 case WINED3DLIGHT_DIRECTIONAL:
2387 /* Ignores attenuation */
2388 break;
2390 default:
2391 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2392 return WINED3DERR_INVALIDCALL;
2395 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2396 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2397 if(object->OriginalIndex == Index) break;
2398 object = NULL;
2401 if(!object) {
2402 TRACE("Adding new light\n");
2403 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2404 if(!object) {
2405 ERR("Out of memory error when allocating a light\n");
2406 return E_OUTOFMEMORY;
2408 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2409 object->glIndex = -1;
2410 object->OriginalIndex = Index;
2411 object->changed = TRUE;
2414 /* Initialize the object */
2415 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,
2416 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2417 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2418 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2419 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2420 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2421 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2423 /* Save away the information */
2424 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2426 switch (pLight->Type) {
2427 case WINED3DLIGHT_POINT:
2428 /* Position */
2429 object->lightPosn[0] = pLight->Position.x;
2430 object->lightPosn[1] = pLight->Position.y;
2431 object->lightPosn[2] = pLight->Position.z;
2432 object->lightPosn[3] = 1.0f;
2433 object->cutoff = 180.0f;
2434 /* FIXME: Range */
2435 break;
2437 case WINED3DLIGHT_DIRECTIONAL:
2438 /* Direction */
2439 object->lightPosn[0] = -pLight->Direction.x;
2440 object->lightPosn[1] = -pLight->Direction.y;
2441 object->lightPosn[2] = -pLight->Direction.z;
2442 object->lightPosn[3] = 0.0;
2443 object->exponent = 0.0f;
2444 object->cutoff = 180.0f;
2445 break;
2447 case WINED3DLIGHT_SPOT:
2448 /* Position */
2449 object->lightPosn[0] = pLight->Position.x;
2450 object->lightPosn[1] = pLight->Position.y;
2451 object->lightPosn[2] = pLight->Position.z;
2452 object->lightPosn[3] = 1.0;
2454 /* Direction */
2455 object->lightDirn[0] = pLight->Direction.x;
2456 object->lightDirn[1] = pLight->Direction.y;
2457 object->lightDirn[2] = pLight->Direction.z;
2458 object->lightDirn[3] = 1.0;
2461 * opengl-ish and d3d-ish spot lights use too different models for the
2462 * light "intensity" as a function of the angle towards the main light direction,
2463 * so we only can approximate very roughly.
2464 * however spot lights are rather rarely used in games (if ever used at all).
2465 * furthermore if still used, probably nobody pays attention to such details.
2467 if (pLight->Falloff == 0) {
2468 rho = 6.28f;
2469 } else {
2470 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2472 if (rho < 0.0001) rho = 0.0001f;
2473 object->exponent = -0.3/log(cos(rho/2));
2474 if (object->exponent > 128.0) {
2475 object->exponent = 128.0;
2477 object->cutoff = pLight->Phi*90/M_PI;
2479 /* FIXME: Range */
2480 break;
2482 default:
2483 FIXME("Unrecognized light type %d\n", pLight->Type);
2486 /* Update the live definitions if the light is currently assigned a glIndex */
2487 if (object->glIndex != -1 && !This->isRecordingState) {
2488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2490 return WINED3D_OK;
2493 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2494 PLIGHTINFOEL *lightInfo = NULL;
2495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2496 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2497 struct list *e;
2498 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2500 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2501 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2502 if(lightInfo->OriginalIndex == Index) break;
2503 lightInfo = NULL;
2506 if (lightInfo == NULL) {
2507 TRACE("Light information requested but light not defined\n");
2508 return WINED3DERR_INVALIDCALL;
2511 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2512 return WINED3D_OK;
2515 /*****
2516 * Get / Set Light Enable
2517 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2518 *****/
2519 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2520 PLIGHTINFOEL *lightInfo = NULL;
2521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2522 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2523 struct list *e;
2524 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2526 /* Tests show true = 128...not clear why */
2527 Enable = Enable? 128: 0;
2529 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2530 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2531 if(lightInfo->OriginalIndex == Index) break;
2532 lightInfo = NULL;
2534 TRACE("Found light: %p\n", lightInfo);
2536 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2537 if (lightInfo == NULL) {
2539 TRACE("Light enabled requested but light not defined, so defining one!\n");
2540 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2542 /* Search for it again! Should be fairly quick as near head of list */
2543 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2544 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2545 if(lightInfo->OriginalIndex == Index) break;
2546 lightInfo = NULL;
2548 if (lightInfo == NULL) {
2549 FIXME("Adding default lights has failed dismally\n");
2550 return WINED3DERR_INVALIDCALL;
2554 lightInfo->enabledChanged = TRUE;
2555 if(!Enable) {
2556 if(lightInfo->glIndex != -1) {
2557 if(!This->isRecordingState) {
2558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2561 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2562 lightInfo->glIndex = -1;
2563 } else {
2564 TRACE("Light already disabled, nothing to do\n");
2566 } else {
2567 if (lightInfo->glIndex != -1) {
2568 /* nop */
2569 TRACE("Nothing to do as light was enabled\n");
2570 } else {
2571 int i;
2572 /* Find a free gl light */
2573 for(i = 0; i < This->maxConcurrentLights; i++) {
2574 if(This->stateBlock->activeLights[i] == NULL) {
2575 This->stateBlock->activeLights[i] = lightInfo;
2576 lightInfo->glIndex = i;
2577 break;
2580 if(lightInfo->glIndex == -1) {
2581 ERR("Too many concurrently active lights\n");
2582 return WINED3DERR_INVALIDCALL;
2585 /* i == lightInfo->glIndex */
2586 if(!This->isRecordingState) {
2587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2592 return WINED3D_OK;
2595 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2597 PLIGHTINFOEL *lightInfo = NULL;
2598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2599 struct list *e;
2600 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2601 TRACE("(%p) : for idx(%d)\n", This, Index);
2603 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2604 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2605 if(lightInfo->OriginalIndex == Index) break;
2606 lightInfo = NULL;
2609 if (lightInfo == NULL) {
2610 TRACE("Light enabled state requested but light not defined\n");
2611 return WINED3DERR_INVALIDCALL;
2613 /* true is 128 according to SetLightEnable */
2614 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2615 return WINED3D_OK;
2618 /*****
2619 * Get / Set Clip Planes
2620 *****/
2621 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2623 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2625 /* Validate Index */
2626 if (Index >= GL_LIMITS(clipplanes)) {
2627 TRACE("Application has requested clipplane this device doesn't support\n");
2628 return WINED3DERR_INVALIDCALL;
2631 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2632 This->updateStateBlock->set.clipplane[Index] = TRUE;
2634 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2635 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2636 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2637 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2638 TRACE("Application is setting old values over, nothing to do\n");
2639 return WINED3D_OK;
2642 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];
2647 /* Handle recording of state blocks */
2648 if (This->isRecordingState) {
2649 TRACE("Recording... not performing anything\n");
2650 return WINED3D_OK;
2653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2655 return WINED3D_OK;
2658 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2660 TRACE("(%p) : for idx %d\n", This, Index);
2662 /* Validate Index */
2663 if (Index >= GL_LIMITS(clipplanes)) {
2664 TRACE("Application has requested clipplane this device doesn't support\n");
2665 return WINED3DERR_INVALIDCALL;
2668 pPlane[0] = This->stateBlock->clipplane[Index][0];
2669 pPlane[1] = This->stateBlock->clipplane[Index][1];
2670 pPlane[2] = This->stateBlock->clipplane[Index][2];
2671 pPlane[3] = This->stateBlock->clipplane[Index][3];
2672 return WINED3D_OK;
2675 /*****
2676 * Get / Set Clip Plane Status
2677 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2678 *****/
2679 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2681 FIXME("(%p) : stub\n", This);
2682 if (NULL == pClipStatus) {
2683 return WINED3DERR_INVALIDCALL;
2685 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2686 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2687 return WINED3D_OK;
2690 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2692 FIXME("(%p) : stub\n", This);
2693 if (NULL == pClipStatus) {
2694 return WINED3DERR_INVALIDCALL;
2696 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2697 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2698 return WINED3D_OK;
2701 /*****
2702 * Get / Set Material
2703 *****/
2704 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2707 This->updateStateBlock->changed.material = TRUE;
2708 This->updateStateBlock->set.material = TRUE;
2709 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2711 /* Handle recording of state blocks */
2712 if (This->isRecordingState) {
2713 TRACE("Recording... not performing anything\n");
2714 return WINED3D_OK;
2717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2718 return WINED3D_OK;
2721 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2724 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2725 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2726 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2727 pMaterial->Ambient.b, pMaterial->Ambient.a);
2728 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2729 pMaterial->Specular.b, pMaterial->Specular.a);
2730 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2731 pMaterial->Emissive.b, pMaterial->Emissive.a);
2732 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2734 return WINED3D_OK;
2737 /*****
2738 * Get / Set Indices
2739 *****/
2740 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2742 IWineD3DIndexBuffer *oldIdxs;
2744 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2745 oldIdxs = This->updateStateBlock->pIndexData;
2747 This->updateStateBlock->changed.indices = TRUE;
2748 This->updateStateBlock->set.indices = TRUE;
2749 This->updateStateBlock->pIndexData = pIndexData;
2751 /* Handle recording of state blocks */
2752 if (This->isRecordingState) {
2753 TRACE("Recording... not performing anything\n");
2754 return WINED3D_OK;
2757 if(oldIdxs != pIndexData) {
2758 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2760 return WINED3D_OK;
2763 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2766 *ppIndexData = This->stateBlock->pIndexData;
2768 /* up ref count on ppindexdata */
2769 if (*ppIndexData) {
2770 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2771 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2772 }else{
2773 TRACE("(%p) No index data set\n", This);
2775 TRACE("Returning %p\n", *ppIndexData);
2777 return WINED3D_OK;
2780 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2781 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2783 TRACE("(%p)->(%d)\n", This, BaseIndex);
2785 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2786 TRACE("Application is setting the old value over, nothing to do\n");
2787 return WINED3D_OK;
2790 This->updateStateBlock->baseVertexIndex = BaseIndex;
2792 if (This->isRecordingState) {
2793 TRACE("Recording... not performing anything\n");
2794 return WINED3D_OK;
2796 /* The base vertex index affects the stream sources */
2797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2798 return WINED3D_OK;
2801 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2803 TRACE("(%p) : base_index %p\n", This, base_index);
2805 *base_index = This->stateBlock->baseVertexIndex;
2807 TRACE("Returning %u\n", *base_index);
2809 return WINED3D_OK;
2812 /*****
2813 * Get / Set Viewports
2814 *****/
2815 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2818 TRACE("(%p)\n", This);
2819 This->updateStateBlock->changed.viewport = TRUE;
2820 This->updateStateBlock->set.viewport = TRUE;
2821 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2823 /* Handle recording of state blocks */
2824 if (This->isRecordingState) {
2825 TRACE("Recording... not performing anything\n");
2826 return WINED3D_OK;
2829 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2830 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2833 return WINED3D_OK;
2837 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2839 TRACE("(%p)\n", This);
2840 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2841 return WINED3D_OK;
2844 /*****
2845 * Get / Set Render States
2846 * TODO: Verify against dx9 definitions
2847 *****/
2848 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2851 DWORD oldValue = This->stateBlock->renderState[State];
2853 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2855 This->updateStateBlock->changed.renderState[State] = TRUE;
2856 This->updateStateBlock->set.renderState[State] = TRUE;
2857 This->updateStateBlock->renderState[State] = Value;
2859 /* Handle recording of state blocks */
2860 if (This->isRecordingState) {
2861 TRACE("Recording... not performing anything\n");
2862 return WINED3D_OK;
2865 /* Compared here and not before the assignment to allow proper stateblock recording */
2866 if(Value == oldValue) {
2867 TRACE("Application is setting the old value over, nothing to do\n");
2868 } else {
2869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2872 return WINED3D_OK;
2875 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2877 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2878 *pValue = This->stateBlock->renderState[State];
2879 return WINED3D_OK;
2882 /*****
2883 * Get / Set Sampler States
2884 * TODO: Verify against dx9 definitions
2885 *****/
2887 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 DWORD oldValue;
2891 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2892 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2894 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2895 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2899 * SetSampler is designed to allow for more than the standard up to 8 textures
2900 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2901 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2903 * http://developer.nvidia.com/object/General_FAQ.html#t6
2905 * There are two new settings for GForce
2906 * the sampler one:
2907 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2908 * and the texture one:
2909 * GL_MAX_TEXTURE_COORDS_ARB.
2910 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2911 ******************/
2913 oldValue = This->stateBlock->samplerState[Sampler][Type];
2914 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2915 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2916 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2918 /* Handle recording of state blocks */
2919 if (This->isRecordingState) {
2920 TRACE("Recording... not performing anything\n");
2921 return WINED3D_OK;
2924 if(oldValue == Value) {
2925 TRACE("Application is setting the old value over, nothing to do\n");
2926 return WINED3D_OK;
2929 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2931 return WINED3D_OK;
2934 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2937 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2938 This, Sampler, debug_d3dsamplerstate(Type), Type);
2940 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2941 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2944 *Value = This->stateBlock->samplerState[Sampler][Type];
2945 TRACE("(%p) : Returning %#x\n", This, *Value);
2947 return WINED3D_OK;
2950 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2953 This->updateStateBlock->set.scissorRect = TRUE;
2954 This->updateStateBlock->changed.scissorRect = TRUE;
2955 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2956 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2957 return WINED3D_OK;
2959 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2961 if(This->isRecordingState) {
2962 TRACE("Recording... not performing anything\n");
2963 return WINED3D_OK;
2966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2975 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2976 return WINED3D_OK;
2979 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2981 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2983 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2985 This->updateStateBlock->vertexDecl = pDecl;
2986 This->updateStateBlock->changed.vertexDecl = TRUE;
2987 This->updateStateBlock->set.vertexDecl = TRUE;
2989 if (This->isRecordingState) {
2990 TRACE("Recording... not performing anything\n");
2991 return WINED3D_OK;
2992 } else if(pDecl == oldDecl) {
2993 /* Checked after the assignment to allow proper stateblock recording */
2994 TRACE("Application is setting the old declaration over, nothing to do\n");
2995 return WINED3D_OK;
2998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2999 return WINED3D_OK;
3002 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3005 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3007 *ppDecl = This->stateBlock->vertexDecl;
3008 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3009 return WINED3D_OK;
3012 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3016 This->updateStateBlock->vertexShader = pShader;
3017 This->updateStateBlock->changed.vertexShader = TRUE;
3018 This->updateStateBlock->set.vertexShader = TRUE;
3020 if (This->isRecordingState) {
3021 TRACE("Recording... not performing anything\n");
3022 return WINED3D_OK;
3023 } else if(oldShader == pShader) {
3024 /* Checked here to allow proper stateblock recording */
3025 TRACE("App is setting the old shader over, nothing to do\n");
3026 return WINED3D_OK;
3029 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3033 return WINED3D_OK;
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 if (NULL == ppShader) {
3040 return WINED3DERR_INVALIDCALL;
3042 *ppShader = This->stateBlock->vertexShader;
3043 if( NULL != *ppShader)
3044 IWineD3DVertexShader_AddRef(*ppShader);
3046 TRACE("(%p) : returning %p\n", This, *ppShader);
3047 return WINED3D_OK;
3050 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3051 IWineD3DDevice *iface,
3052 UINT start,
3053 CONST BOOL *srcData,
3054 UINT count) {
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 int i, cnt = min(count, MAX_CONST_B - start);
3059 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3060 iface, srcData, start, count);
3062 if (srcData == NULL || cnt < 0)
3063 return WINED3DERR_INVALIDCALL;
3065 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3066 for (i = 0; i < cnt; i++)
3067 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3069 for (i = start; i < cnt + start; ++i) {
3070 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3071 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3076 return WINED3D_OK;
3079 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3080 IWineD3DDevice *iface,
3081 UINT start,
3082 BOOL *dstData,
3083 UINT count) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 int cnt = min(count, MAX_CONST_B - start);
3088 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3089 iface, dstData, start, count);
3091 if (dstData == NULL || cnt < 0)
3092 return WINED3DERR_INVALIDCALL;
3094 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3099 IWineD3DDevice *iface,
3100 UINT start,
3101 CONST int *srcData,
3102 UINT count) {
3104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3105 int i, cnt = min(count, MAX_CONST_I - start);
3107 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3108 iface, srcData, start, count);
3110 if (srcData == NULL || cnt < 0)
3111 return WINED3DERR_INVALIDCALL;
3113 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3114 for (i = 0; i < cnt; i++)
3115 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3116 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3118 for (i = start; i < cnt + start; ++i) {
3119 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3120 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3125 return WINED3D_OK;
3128 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3129 IWineD3DDevice *iface,
3130 UINT start,
3131 int *dstData,
3132 UINT count) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 int cnt = min(count, MAX_CONST_I - start);
3137 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3138 iface, dstData, start, count);
3140 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3141 return WINED3DERR_INVALIDCALL;
3143 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3144 return WINED3D_OK;
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3148 IWineD3DDevice *iface,
3149 UINT start,
3150 CONST float *srcData,
3151 UINT count) {
3153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 int i;
3156 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3157 iface, srcData, start, count);
3159 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3160 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3161 return WINED3DERR_INVALIDCALL;
3163 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3164 if(TRACE_ON(d3d)) {
3165 for (i = 0; i < count; i++)
3166 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3167 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3170 for (i = start; i < count + start; ++i) {
3171 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3172 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3173 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3174 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3175 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3177 ptr->idx[ptr->count++] = i;
3178 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3180 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3185 return WINED3D_OK;
3188 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3189 IWineD3DDevice *iface,
3190 UINT start,
3191 float *dstData,
3192 UINT count) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3195 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3197 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3198 iface, dstData, start, count);
3200 if (dstData == NULL || cnt < 0)
3201 return WINED3DERR_INVALIDCALL;
3203 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3204 return WINED3D_OK;
3207 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3208 DWORD i;
3209 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3214 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3215 int i = This->rev_tex_unit_map[unit];
3216 int j = This->texUnitMap[stage];
3218 This->texUnitMap[stage] = unit;
3219 if (i != -1 && i != stage) {
3220 This->texUnitMap[i] = -1;
3223 This->rev_tex_unit_map[unit] = stage;
3224 if (j != -1 && j != unit) {
3225 This->rev_tex_unit_map[j] = -1;
3229 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3230 int i;
3232 for (i = 0; i < MAX_TEXTURES; ++i) {
3233 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3234 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3235 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3236 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3237 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3238 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3239 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3240 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3242 if (color_op == WINED3DTOP_DISABLE) {
3243 /* Not used, and disable higher stages */
3244 while (i < MAX_TEXTURES) {
3245 This->fixed_function_usage_map[i] = FALSE;
3246 ++i;
3248 break;
3251 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3252 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3253 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3254 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3255 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3256 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3257 This->fixed_function_usage_map[i] = TRUE;
3258 } else {
3259 This->fixed_function_usage_map[i] = FALSE;
3262 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3263 This->fixed_function_usage_map[i+1] = TRUE;
3268 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3269 int i, tex;
3271 device_update_fixed_function_usage_map(This);
3273 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3274 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3275 if (!This->fixed_function_usage_map[i]) continue;
3277 if (This->texUnitMap[i] != i) {
3278 device_map_stage(This, i, i);
3279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3280 markTextureStagesDirty(This, i);
3283 return;
3286 /* Now work out the mapping */
3287 tex = 0;
3288 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3289 if (!This->fixed_function_usage_map[i]) continue;
3291 if (This->texUnitMap[i] != tex) {
3292 device_map_stage(This, i, tex);
3293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3294 markTextureStagesDirty(This, i);
3297 ++tex;
3301 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3302 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3303 int i;
3305 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3306 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3307 device_map_stage(This, i, i);
3308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3309 if (i < MAX_TEXTURES) {
3310 markTextureStagesDirty(This, i);
3316 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3317 int current_mapping = This->rev_tex_unit_map[unit];
3319 if (current_mapping == -1) {
3320 /* Not currently used */
3321 return TRUE;
3324 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3325 /* Used by a fragment sampler */
3327 if (!pshader_sampler_tokens) {
3328 /* No pixel shader, check fixed function */
3329 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3332 /* Pixel shader, check the shader's sampler map */
3333 return !pshader_sampler_tokens[current_mapping];
3336 /* Used by a vertex sampler */
3337 return !vshader_sampler_tokens[current_mapping];
3340 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3341 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3342 DWORD *pshader_sampler_tokens = NULL;
3343 int start = GL_LIMITS(combined_samplers) - 1;
3344 int i;
3346 if (ps) {
3347 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3349 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3350 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3351 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3354 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3355 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3356 if (vshader_sampler_tokens[i]) {
3357 if (This->texUnitMap[vsampler_idx] != -1) {
3358 /* Already mapped somewhere */
3359 continue;
3362 while (start >= 0) {
3363 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3364 device_map_stage(This, vsampler_idx, start);
3365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3367 --start;
3368 break;
3371 --start;
3377 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3378 BOOL vs = use_vs(This);
3379 BOOL ps = use_ps(This);
3381 * Rules are:
3382 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3383 * that would be really messy and require shader recompilation
3384 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3385 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3387 if (ps) {
3388 device_map_psamplers(This);
3389 } else {
3390 device_map_fixed_function_samplers(This);
3393 if (vs) {
3394 device_map_vsamplers(This, ps);
3398 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3401 This->updateStateBlock->pixelShader = pShader;
3402 This->updateStateBlock->changed.pixelShader = TRUE;
3403 This->updateStateBlock->set.pixelShader = TRUE;
3405 /* Handle recording of state blocks */
3406 if (This->isRecordingState) {
3407 TRACE("Recording... not performing anything\n");
3410 if (This->isRecordingState) {
3411 TRACE("Recording... not performing anything\n");
3412 return WINED3D_OK;
3415 if(pShader == oldShader) {
3416 TRACE("App is setting the old pixel shader over, nothing to do\n");
3417 return WINED3D_OK;
3420 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3429 if (NULL == ppShader) {
3430 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3431 return WINED3DERR_INVALIDCALL;
3434 *ppShader = This->stateBlock->pixelShader;
3435 if (NULL != *ppShader) {
3436 IWineD3DPixelShader_AddRef(*ppShader);
3438 TRACE("(%p) : returning %p\n", This, *ppShader);
3439 return WINED3D_OK;
3442 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3443 IWineD3DDevice *iface,
3444 UINT start,
3445 CONST BOOL *srcData,
3446 UINT count) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 int i, cnt = min(count, MAX_CONST_B - start);
3451 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3452 iface, srcData, start, count);
3454 if (srcData == NULL || cnt < 0)
3455 return WINED3DERR_INVALIDCALL;
3457 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3458 for (i = 0; i < cnt; i++)
3459 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3461 for (i = start; i < cnt + start; ++i) {
3462 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3463 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3468 return WINED3D_OK;
3471 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3472 IWineD3DDevice *iface,
3473 UINT start,
3474 BOOL *dstData,
3475 UINT count) {
3477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3478 int cnt = min(count, MAX_CONST_B - start);
3480 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3481 iface, dstData, start, count);
3483 if (dstData == NULL || cnt < 0)
3484 return WINED3DERR_INVALIDCALL;
3486 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3487 return WINED3D_OK;
3490 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3491 IWineD3DDevice *iface,
3492 UINT start,
3493 CONST int *srcData,
3494 UINT count) {
3496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3497 int i, cnt = min(count, MAX_CONST_I - start);
3499 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3500 iface, srcData, start, count);
3502 if (srcData == NULL || cnt < 0)
3503 return WINED3DERR_INVALIDCALL;
3505 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3506 for (i = 0; i < cnt; i++)
3507 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3508 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3510 for (i = start; i < cnt + start; ++i) {
3511 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3512 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3517 return WINED3D_OK;
3520 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3521 IWineD3DDevice *iface,
3522 UINT start,
3523 int *dstData,
3524 UINT count) {
3526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3527 int cnt = min(count, MAX_CONST_I - start);
3529 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3530 iface, dstData, start, count);
3532 if (dstData == NULL || cnt < 0)
3533 return WINED3DERR_INVALIDCALL;
3535 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3536 return WINED3D_OK;
3539 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3540 IWineD3DDevice *iface,
3541 UINT start,
3542 CONST float *srcData,
3543 UINT count) {
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 int i;
3548 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3549 iface, srcData, start, count);
3551 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3552 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3553 return WINED3DERR_INVALIDCALL;
3555 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3556 if(TRACE_ON(d3d)) {
3557 for (i = 0; i < count; i++)
3558 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3559 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3562 for (i = start; i < count + start; ++i) {
3563 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3564 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3565 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3566 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3567 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3569 ptr->idx[ptr->count++] = i;
3570 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3572 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3577 return WINED3D_OK;
3580 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3581 IWineD3DDevice *iface,
3582 UINT start,
3583 float *dstData,
3584 UINT count) {
3586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3587 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3589 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3590 iface, dstData, start, count);
3592 if (dstData == NULL || cnt < 0)
3593 return WINED3DERR_INVALIDCALL;
3595 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3596 return WINED3D_OK;
3599 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3600 static HRESULT
3601 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3602 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3603 unsigned int i;
3604 DWORD DestFVF = dest->fvf;
3605 WINED3DVIEWPORT vp;
3606 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3607 BOOL doClip;
3608 int numTextures;
3610 if (lpStrideData->u.s.normal.lpData) {
3611 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3614 if (lpStrideData->u.s.position.lpData == NULL) {
3615 ERR("Source has no position mask\n");
3616 return WINED3DERR_INVALIDCALL;
3619 /* We might access VBOs from this code, so hold the lock */
3620 ENTER_GL();
3622 if (dest->resource.allocatedMemory == NULL) {
3623 /* This may happen if we do direct locking into a vbo. Unlikely,
3624 * but theoretically possible(ddraw processvertices test)
3626 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3627 if(!dest->resource.allocatedMemory) {
3628 LEAVE_GL();
3629 ERR("Out of memory\n");
3630 return E_OUTOFMEMORY;
3632 if(dest->vbo) {
3633 void *src;
3634 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3635 checkGLcall("glBindBufferARB");
3636 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3637 if(src) {
3638 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3640 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3641 checkGLcall("glUnmapBufferARB");
3645 /* Get a pointer into the destination vbo(create one if none exists) and
3646 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3648 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3649 CreateVBO(dest);
3652 if(dest->vbo) {
3653 unsigned char extrabytes = 0;
3654 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3655 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3656 * this may write 4 extra bytes beyond the area that should be written
3658 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3659 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3660 if(!dest_conv_addr) {
3661 ERR("Out of memory\n");
3662 /* Continue without storing converted vertices */
3664 dest_conv = dest_conv_addr;
3667 /* Should I clip?
3668 * a) WINED3DRS_CLIPPING is enabled
3669 * b) WINED3DVOP_CLIP is passed
3671 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3672 static BOOL warned = FALSE;
3674 * The clipping code is not quite correct. Some things need
3675 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3676 * so disable clipping for now.
3677 * (The graphics in Half-Life are broken, and my processvertices
3678 * test crashes with IDirect3DDevice3)
3679 doClip = TRUE;
3681 doClip = FALSE;
3682 if(!warned) {
3683 warned = TRUE;
3684 FIXME("Clipping is broken and disabled for now\n");
3686 } else doClip = FALSE;
3687 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3689 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3690 WINED3DTS_VIEW,
3691 &view_mat);
3692 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3693 WINED3DTS_PROJECTION,
3694 &proj_mat);
3695 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3696 WINED3DTS_WORLDMATRIX(0),
3697 &world_mat);
3699 TRACE("View mat:\n");
3700 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);
3701 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);
3702 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);
3703 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);
3705 TRACE("Proj mat:\n");
3706 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);
3707 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);
3708 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);
3709 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);
3711 TRACE("World mat:\n");
3712 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);
3713 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);
3714 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);
3715 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);
3717 /* Get the viewport */
3718 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3719 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3720 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3722 multiply_matrix(&mat,&view_mat,&world_mat);
3723 multiply_matrix(&mat,&proj_mat,&mat);
3725 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3727 for (i = 0; i < dwCount; i+= 1) {
3728 unsigned int tex_index;
3730 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3731 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3732 /* The position first */
3733 float *p =
3734 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3735 float x, y, z, rhw;
3736 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3738 /* Multiplication with world, view and projection matrix */
3739 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);
3740 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);
3741 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);
3742 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);
3744 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3746 /* WARNING: The following things are taken from d3d7 and were not yet checked
3747 * against d3d8 or d3d9!
3750 /* Clipping conditions: From
3751 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3753 * A vertex is clipped if it does not match the following requirements
3754 * -rhw < x <= rhw
3755 * -rhw < y <= rhw
3756 * 0 < z <= rhw
3757 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3759 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3760 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3764 if( !doClip ||
3765 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3766 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3767 ( rhw > eps ) ) ) {
3769 /* "Normal" viewport transformation (not clipped)
3770 * 1) The values are divided by rhw
3771 * 2) The y axis is negative, so multiply it with -1
3772 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3773 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3774 * 4) Multiply x with Width/2 and add Width/2
3775 * 5) The same for the height
3776 * 6) Add the viewpoint X and Y to the 2D coordinates and
3777 * The minimum Z value to z
3778 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3780 * Well, basically it's simply a linear transformation into viewport
3781 * coordinates
3784 x /= rhw;
3785 y /= rhw;
3786 z /= rhw;
3788 y *= -1;
3790 x *= vp.Width / 2;
3791 y *= vp.Height / 2;
3792 z *= vp.MaxZ - vp.MinZ;
3794 x += vp.Width / 2 + vp.X;
3795 y += vp.Height / 2 + vp.Y;
3796 z += vp.MinZ;
3798 rhw = 1 / rhw;
3799 } else {
3800 /* That vertex got clipped
3801 * Contrary to OpenGL it is not dropped completely, it just
3802 * undergoes a different calculation.
3804 TRACE("Vertex got clipped\n");
3805 x += rhw;
3806 y += rhw;
3808 x /= 2;
3809 y /= 2;
3811 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3812 * outside of the main vertex buffer memory. That needs some more
3813 * investigation...
3817 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3820 ( (float *) dest_ptr)[0] = x;
3821 ( (float *) dest_ptr)[1] = y;
3822 ( (float *) dest_ptr)[2] = z;
3823 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3825 dest_ptr += 3 * sizeof(float);
3827 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3828 dest_ptr += sizeof(float);
3831 if(dest_conv) {
3832 float w = 1 / rhw;
3833 ( (float *) dest_conv)[0] = x * w;
3834 ( (float *) dest_conv)[1] = y * w;
3835 ( (float *) dest_conv)[2] = z * w;
3836 ( (float *) dest_conv)[3] = w;
3838 dest_conv += 3 * sizeof(float);
3840 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3841 dest_conv += sizeof(float);
3845 if (DestFVF & WINED3DFVF_PSIZE) {
3846 dest_ptr += sizeof(DWORD);
3847 if(dest_conv) dest_conv += sizeof(DWORD);
3849 if (DestFVF & WINED3DFVF_NORMAL) {
3850 float *normal =
3851 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3852 /* AFAIK this should go into the lighting information */
3853 FIXME("Didn't expect the destination to have a normal\n");
3854 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3855 if(dest_conv) {
3856 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3860 if (DestFVF & WINED3DFVF_DIFFUSE) {
3861 DWORD *color_d =
3862 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3863 if(!color_d) {
3864 static BOOL warned = FALSE;
3866 if(!warned) {
3867 ERR("No diffuse color in source, but destination has one\n");
3868 warned = TRUE;
3871 *( (DWORD *) dest_ptr) = 0xffffffff;
3872 dest_ptr += sizeof(DWORD);
3874 if(dest_conv) {
3875 *( (DWORD *) dest_conv) = 0xffffffff;
3876 dest_conv += sizeof(DWORD);
3879 else {
3880 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3881 if(dest_conv) {
3882 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3883 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3884 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3885 dest_conv += sizeof(DWORD);
3890 if (DestFVF & WINED3DFVF_SPECULAR) {
3891 /* What's the color value in the feedback buffer? */
3892 DWORD *color_s =
3893 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3894 if(!color_s) {
3895 static BOOL warned = FALSE;
3897 if(!warned) {
3898 ERR("No specular color in source, but destination has one\n");
3899 warned = TRUE;
3902 *( (DWORD *) dest_ptr) = 0xFF000000;
3903 dest_ptr += sizeof(DWORD);
3905 if(dest_conv) {
3906 *( (DWORD *) dest_conv) = 0xFF000000;
3907 dest_conv += sizeof(DWORD);
3910 else {
3911 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3912 if(dest_conv) {
3913 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3914 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3915 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3916 dest_conv += sizeof(DWORD);
3921 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3922 float *tex_coord =
3923 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3924 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3925 if(!tex_coord) {
3926 ERR("No source texture, but destination requests one\n");
3927 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3928 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3930 else {
3931 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3932 if(dest_conv) {
3933 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3939 if(dest_conv) {
3940 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3941 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3942 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3943 dwCount * get_flexible_vertex_size(DestFVF),
3944 dest_conv_addr));
3945 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3946 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3949 LEAVE_GL();
3951 return WINED3D_OK;
3953 #undef copy_and_next
3955 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3957 WineDirect3DVertexStridedData strided;
3958 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3959 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3961 if(pVertexDecl) {
3962 ERR("Output vertex declaration not implemented yet\n");
3965 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3966 * and this call is quite performance critical, so don't call needlessly
3968 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3969 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3972 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3973 * control the streamIsUP flag, thus restore it afterwards.
3975 This->stateBlock->streamIsUP = FALSE;
3976 memset(&strided, 0, sizeof(strided));
3977 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3978 This->stateBlock->streamIsUP = streamWasUP;
3980 if(vbo || SrcStartIndex) {
3981 unsigned int i;
3982 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3983 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3985 * Also get the start index in, but only loop over all elements if there's something to add at all.
3987 #define FIXSRC(type) \
3988 if(strided.u.s.type.VBO) { \
3989 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3990 strided.u.s.type.VBO = 0; \
3991 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3992 ENTER_GL(); \
3993 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3994 vb->vbo = 0; \
3995 LEAVE_GL(); \
3997 if(strided.u.s.type.lpData) { \
3998 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4000 FIXSRC(position);
4001 FIXSRC(blendWeights);
4002 FIXSRC(blendMatrixIndices);
4003 FIXSRC(normal);
4004 FIXSRC(pSize);
4005 FIXSRC(diffuse);
4006 FIXSRC(specular);
4007 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4008 FIXSRC(texCoords[i]);
4010 FIXSRC(position2);
4011 FIXSRC(normal2);
4012 FIXSRC(tangent);
4013 FIXSRC(binormal);
4014 FIXSRC(tessFactor);
4015 FIXSRC(fog);
4016 FIXSRC(depth);
4017 FIXSRC(sample);
4018 #undef FIXSRC
4021 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4024 /*****
4025 * Get / Set Texture Stage States
4026 * TODO: Verify against dx9 definitions
4027 *****/
4028 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4030 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4032 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
4034 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4036 if (Stage >= MAX_TEXTURES) {
4037 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4038 return WINED3D_OK;
4041 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4042 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
4043 This->updateStateBlock->textureState[Stage][Type] = Value;
4045 if (This->isRecordingState) {
4046 TRACE("Recording... not performing anything\n");
4047 return WINED3D_OK;
4050 /* Checked after the assignments to allow proper stateblock recording */
4051 if(oldValue == Value) {
4052 TRACE("App is setting the old value over, nothing to do\n");
4053 return WINED3D_OK;
4056 if(Stage > This->stateBlock->lowest_disabled_stage &&
4057 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4058 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4059 * Changes in other states are important on disabled stages too
4061 return WINED3D_OK;
4064 if(Type == WINED3DTSS_COLOROP) {
4065 int i;
4067 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4068 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4069 * they have to be disabled
4071 * The current stage is dirtified below.
4073 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4074 TRACE("Additionally dirtifying stage %d\n", i);
4075 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4077 This->stateBlock->lowest_disabled_stage = Stage;
4078 TRACE("New lowest disabled: %d\n", Stage);
4079 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4080 /* Previously disabled stage enabled. Stages above it may need enabling
4081 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4082 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4084 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4087 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4088 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4089 break;
4091 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4094 This->stateBlock->lowest_disabled_stage = i;
4095 TRACE("New lowest disabled: %d\n", i);
4097 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4098 /* TODO: Built a stage -> texture unit mapping for register combiners */
4102 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4104 return WINED3D_OK;
4107 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4110 *pValue = This->updateStateBlock->textureState[Stage][Type];
4111 return WINED3D_OK;
4114 /*****
4115 * Get / Set Texture
4116 *****/
4117 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4119 IWineD3DBaseTexture *oldTexture;
4121 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4123 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4124 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4127 oldTexture = This->updateStateBlock->textures[Stage];
4129 if(pTexture != NULL) {
4130 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4132 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4133 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4134 return WINED3DERR_INVALIDCALL;
4136 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4139 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4140 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4142 This->updateStateBlock->set.textures[Stage] = TRUE;
4143 This->updateStateBlock->changed.textures[Stage] = TRUE;
4144 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4145 This->updateStateBlock->textures[Stage] = pTexture;
4147 /* Handle recording of state blocks */
4148 if (This->isRecordingState) {
4149 TRACE("Recording... not performing anything\n");
4150 return WINED3D_OK;
4153 if(oldTexture == pTexture) {
4154 TRACE("App is setting the same texture again, nothing to do\n");
4155 return WINED3D_OK;
4158 /** NOTE: MSDN says that setTexture increases the reference count,
4159 * and the the application must set the texture back to null (or have a leaky application),
4160 * This means we should pass the refcount up to the parent
4161 *******************************/
4162 if (NULL != This->updateStateBlock->textures[Stage]) {
4163 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4164 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4166 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4167 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4168 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4169 * so the COLOROP and ALPHAOP have to be dirtified.
4171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4174 if(bindCount == 1) {
4175 new->baseTexture.sampler = Stage;
4177 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4181 if (NULL != oldTexture) {
4182 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4183 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4185 IWineD3DBaseTexture_Release(oldTexture);
4186 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4191 if(bindCount && old->baseTexture.sampler == Stage) {
4192 int i;
4193 /* Have to do a search for the other sampler(s) where the texture is bound to
4194 * Shouldn't happen as long as apps bind a texture only to one stage
4196 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4197 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4198 if(This->updateStateBlock->textures[i] == oldTexture) {
4199 old->baseTexture.sampler = i;
4200 break;
4206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4208 return WINED3D_OK;
4211 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4214 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4216 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4217 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4220 *ppTexture=This->stateBlock->textures[Stage];
4221 if (*ppTexture)
4222 IWineD3DBaseTexture_AddRef(*ppTexture);
4224 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4226 return WINED3D_OK;
4229 /*****
4230 * Get Back Buffer
4231 *****/
4232 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4233 IWineD3DSurface **ppBackBuffer) {
4234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4235 IWineD3DSwapChain *swapChain;
4236 HRESULT hr;
4238 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4240 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4241 if (hr == WINED3D_OK) {
4242 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4243 IWineD3DSwapChain_Release(swapChain);
4244 } else {
4245 *ppBackBuffer = NULL;
4247 return hr;
4250 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4252 WARN("(%p) : stub, calling idirect3d for now\n", This);
4253 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4256 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4258 IWineD3DSwapChain *swapChain;
4259 HRESULT hr;
4261 if(iSwapChain > 0) {
4262 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4263 if (hr == WINED3D_OK) {
4264 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4265 IWineD3DSwapChain_Release(swapChain);
4266 } else {
4267 FIXME("(%p) Error getting display mode\n", This);
4269 } else {
4270 /* Don't read the real display mode,
4271 but return the stored mode instead. X11 can't change the color
4272 depth, and some apps are pretty angry if they SetDisplayMode from
4273 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4275 Also don't relay to the swapchain because with ddraw it's possible
4276 that there isn't a swapchain at all */
4277 pMode->Width = This->ddraw_width;
4278 pMode->Height = This->ddraw_height;
4279 pMode->Format = This->ddraw_format;
4280 pMode->RefreshRate = 0;
4281 hr = WINED3D_OK;
4284 return hr;
4287 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4289 TRACE("(%p)->(%p)\n", This, hWnd);
4291 if(This->ddraw_fullscreen) {
4292 if(This->ddraw_window && This->ddraw_window != hWnd) {
4293 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4295 if(hWnd && This->ddraw_window != hWnd) {
4296 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4300 This->ddraw_window = hWnd;
4301 return WINED3D_OK;
4304 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4306 TRACE("(%p)->(%p)\n", This, hWnd);
4308 *hWnd = This->ddraw_window;
4309 return WINED3D_OK;
4312 /*****
4313 * Stateblock related functions
4314 *****/
4316 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4318 IWineD3DStateBlockImpl *object;
4319 HRESULT temp_result;
4320 int i;
4322 TRACE("(%p)\n", This);
4324 if (This->isRecordingState) {
4325 return WINED3DERR_INVALIDCALL;
4328 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4329 if (NULL == object ) {
4330 FIXME("(%p)Error allocating memory for stateblock\n", This);
4331 return E_OUTOFMEMORY;
4333 TRACE("(%p) created object %p\n", This, object);
4334 object->wineD3DDevice= This;
4335 /** FIXME: object->parent = parent; **/
4336 object->parent = NULL;
4337 object->blockType = WINED3DSBT_ALL;
4338 object->ref = 1;
4339 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4341 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4342 list_init(&object->lightMap[i]);
4345 temp_result = allocate_shader_constants(object);
4346 if (WINED3D_OK != temp_result)
4347 return temp_result;
4349 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4350 This->updateStateBlock = object;
4351 This->isRecordingState = TRUE;
4353 TRACE("(%p) recording stateblock %p\n",This , object);
4354 return WINED3D_OK;
4357 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4360 if (!This->isRecordingState) {
4361 FIXME("(%p) not recording! returning error\n", This);
4362 *ppStateBlock = NULL;
4363 return WINED3DERR_INVALIDCALL;
4366 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4367 This->isRecordingState = FALSE;
4368 This->updateStateBlock = This->stateBlock;
4369 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4370 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4371 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4372 return WINED3D_OK;
4375 /*****
4376 * Scene related functions
4377 *****/
4378 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4379 /* At the moment we have no need for any functionality at the beginning
4380 of a scene */
4381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4382 TRACE("(%p)\n", This);
4384 if(This->inScene) {
4385 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4386 return WINED3DERR_INVALIDCALL;
4388 This->inScene = TRUE;
4389 return WINED3D_OK;
4392 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4394 TRACE("(%p)\n", This);
4396 if(!This->inScene) {
4397 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4398 return WINED3DERR_INVALIDCALL;
4401 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4402 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4404 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4405 ENTER_GL();
4406 glFlush();
4407 checkGLcall("glFlush");
4408 LEAVE_GL();
4410 This->inScene = FALSE;
4411 return WINED3D_OK;
4414 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4415 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4416 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4418 IWineD3DSwapChain *swapChain = NULL;
4419 int i;
4420 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4422 TRACE("(%p) Presenting the frame\n", This);
4424 for(i = 0 ; i < swapchains ; i ++) {
4426 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4427 TRACE("presentinng chain %d, %p\n", i, swapChain);
4428 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4429 IWineD3DSwapChain_Release(swapChain);
4432 return WINED3D_OK;
4435 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4436 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4438 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4440 GLbitfield glMask = 0;
4441 unsigned int i;
4442 CONST WINED3DRECT* curRect;
4444 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4445 Count, pRects, Flags, Color, Z, Stencil);
4447 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4448 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4449 /* TODO: What about depth stencil buffers without stencil bits? */
4450 return WINED3DERR_INVALIDCALL;
4453 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4454 * and not the last active one.
4457 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4458 ENTER_GL();
4459 apply_fbo_state(iface);
4460 LEAVE_GL();
4463 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4464 ENTER_GL();
4466 if (Count > 0 && pRects) {
4467 curRect = pRects;
4468 } else {
4469 curRect = NULL;
4472 /* Only set the values up once, as they are not changing */
4473 if (Flags & WINED3DCLEAR_STENCIL) {
4474 glClearStencil(Stencil);
4475 checkGLcall("glClearStencil");
4476 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4477 glStencilMask(0xFFFFFFFF);
4480 if (Flags & WINED3DCLEAR_ZBUFFER) {
4481 glDepthMask(GL_TRUE);
4482 glClearDepth(Z);
4483 checkGLcall("glClearDepth");
4484 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4488 if (Flags & WINED3DCLEAR_TARGET) {
4489 TRACE("Clearing screen with glClear to color %x\n", Color);
4490 glClearColor(D3DCOLOR_R(Color),
4491 D3DCOLOR_G(Color),
4492 D3DCOLOR_B(Color),
4493 D3DCOLOR_A(Color));
4494 checkGLcall("glClearColor");
4496 /* Clear ALL colors! */
4497 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4498 glMask = glMask | GL_COLOR_BUFFER_BIT;
4501 if (!curRect) {
4502 /* In drawable flag is set below */
4504 if (This->render_offscreen) {
4505 glScissor(This->stateBlock->viewport.X,
4506 This->stateBlock->viewport.Y,
4507 This->stateBlock->viewport.Width,
4508 This->stateBlock->viewport.Height);
4509 } else {
4510 glScissor(This->stateBlock->viewport.X,
4511 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4512 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4513 This->stateBlock->viewport.Width,
4514 This->stateBlock->viewport.Height);
4516 checkGLcall("glScissor");
4517 glClear(glMask);
4518 checkGLcall("glClear");
4519 } else {
4520 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4521 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4523 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4524 curRect[0].x2 < target->currentDesc.Width ||
4525 curRect[0].y2 < target->currentDesc.Height) {
4526 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4527 blt_to_drawable(This, target);
4531 /* Now process each rect in turn */
4532 for (i = 0; i < Count; i++) {
4533 /* Note gl uses lower left, width/height */
4534 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4535 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4536 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4537 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4539 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4540 * The rectangle is not cleared, no error is returned, but further rectanlges are
4541 * still cleared if they are valid
4543 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4544 TRACE("Rectangle with negative dimensions, ignoring\n");
4545 continue;
4548 if(This->render_offscreen) {
4549 glScissor(curRect[i].x1, curRect[i].y1,
4550 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4551 } else {
4552 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4553 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4555 checkGLcall("glScissor");
4557 glClear(glMask);
4558 checkGLcall("glClear");
4562 /* Restore the old values (why..?) */
4563 if (Flags & WINED3DCLEAR_STENCIL) {
4564 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4566 if (Flags & WINED3DCLEAR_TARGET) {
4567 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4568 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4569 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4570 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4571 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4574 LEAVE_GL();
4576 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4577 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4579 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4580 target->Flags |= SFLAG_INTEXTURE;
4581 target->Flags &= ~SFLAG_INSYSMEM;
4582 } else {
4583 target->Flags |= SFLAG_INDRAWABLE;
4584 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4586 return WINED3D_OK;
4589 /*****
4590 * Drawing functions
4591 *****/
4592 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4593 UINT PrimitiveCount) {
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4597 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4598 debug_d3dprimitivetype(PrimitiveType),
4599 StartVertex, PrimitiveCount);
4601 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4602 if(This->stateBlock->streamIsUP) {
4603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4604 This->stateBlock->streamIsUP = FALSE;
4607 if(This->stateBlock->loadBaseVertexIndex != 0) {
4608 This->stateBlock->loadBaseVertexIndex = 0;
4609 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4611 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4612 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4613 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4614 return WINED3D_OK;
4617 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4618 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4619 WINED3DPRIMITIVETYPE PrimitiveType,
4620 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 UINT idxStride = 2;
4624 IWineD3DIndexBuffer *pIB;
4625 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4626 GLuint vbo;
4628 pIB = This->stateBlock->pIndexData;
4629 if (!pIB) {
4630 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4631 * without an index buffer set. (The first time at least...)
4632 * D3D8 simply dies, but I doubt it can do much harm to return
4633 * D3DERR_INVALIDCALL there as well. */
4634 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4635 return WINED3DERR_INVALIDCALL;
4638 if(This->stateBlock->streamIsUP) {
4639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4640 This->stateBlock->streamIsUP = FALSE;
4642 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4644 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4645 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4646 minIndex, NumVertices, startIndex, primCount);
4648 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4649 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4650 idxStride = 2;
4651 } else {
4652 idxStride = 4;
4655 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4656 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4660 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4661 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4663 return WINED3D_OK;
4666 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4667 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4668 UINT VertexStreamZeroStride) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4671 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4672 debug_d3dprimitivetype(PrimitiveType),
4673 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4675 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4676 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4677 This->stateBlock->streamOffset[0] = 0;
4678 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4679 This->stateBlock->streamIsUP = TRUE;
4680 This->stateBlock->loadBaseVertexIndex = 0;
4682 /* TODO: Only mark dirty if drawing from a different UP address */
4683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4685 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4686 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4688 /* MSDN specifies stream zero settings must be set to NULL */
4689 This->stateBlock->streamStride[0] = 0;
4690 This->stateBlock->streamSource[0] = NULL;
4692 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4693 * the new stream sources or use UP drawing again
4695 return WINED3D_OK;
4698 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4699 UINT MinVertexIndex, UINT NumVertices,
4700 UINT PrimitiveCount, CONST void* pIndexData,
4701 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4702 UINT VertexStreamZeroStride) {
4703 int idxStride;
4704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4707 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4708 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4709 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4711 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4712 idxStride = 2;
4713 } else {
4714 idxStride = 4;
4717 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4718 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4719 This->stateBlock->streamIsUP = TRUE;
4720 This->stateBlock->streamOffset[0] = 0;
4721 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4723 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4724 This->stateBlock->baseVertexIndex = 0;
4725 This->stateBlock->loadBaseVertexIndex = 0;
4726 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4730 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4732 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4733 This->stateBlock->streamSource[0] = NULL;
4734 This->stateBlock->streamStride[0] = 0;
4735 This->stateBlock->pIndexData = NULL;
4736 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4737 * SetStreamSource to specify a vertex buffer
4740 return WINED3D_OK;
4743 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4746 /* Mark the state dirty until we have nicer tracking
4747 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4748 * that value.
4750 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4752 This->stateBlock->baseVertexIndex = 0;
4753 This->up_strided = DrawPrimStrideData;
4754 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4755 This->up_strided = NULL;
4756 return WINED3D_OK;
4758 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4759 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4761 HRESULT hr = WINED3D_OK;
4762 WINED3DRESOURCETYPE sourceType;
4763 WINED3DRESOURCETYPE destinationType;
4764 int i ,levels;
4766 /* TODO: think about moving the code into IWineD3DBaseTexture */
4768 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4770 /* verify that the source and destination textures aren't NULL */
4771 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4772 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4773 This, pSourceTexture, pDestinationTexture);
4774 hr = WINED3DERR_INVALIDCALL;
4777 if (pSourceTexture == pDestinationTexture) {
4778 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4779 This, pSourceTexture, pDestinationTexture);
4780 hr = WINED3DERR_INVALIDCALL;
4782 /* Verify that the source and destination textures are the same type */
4783 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4784 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4786 if (sourceType != destinationType) {
4787 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4788 This);
4789 hr = WINED3DERR_INVALIDCALL;
4792 /* check that both textures have the identical numbers of levels */
4793 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4794 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4795 hr = WINED3DERR_INVALIDCALL;
4798 if (WINED3D_OK == hr) {
4800 /* Make sure that the destination texture is loaded */
4801 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4803 /* Update every surface level of the texture */
4804 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4806 switch (sourceType) {
4807 case WINED3DRTYPE_TEXTURE:
4809 IWineD3DSurface *srcSurface;
4810 IWineD3DSurface *destSurface;
4812 for (i = 0 ; i < levels ; ++i) {
4813 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4814 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4815 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4816 IWineD3DSurface_Release(srcSurface);
4817 IWineD3DSurface_Release(destSurface);
4818 if (WINED3D_OK != hr) {
4819 WARN("(%p) : Call to update surface failed\n", This);
4820 return hr;
4824 break;
4825 case WINED3DRTYPE_CUBETEXTURE:
4827 IWineD3DSurface *srcSurface;
4828 IWineD3DSurface *destSurface;
4829 WINED3DCUBEMAP_FACES faceType;
4831 for (i = 0 ; i < levels ; ++i) {
4832 /* Update each cube face */
4833 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4834 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4835 if (WINED3D_OK != hr) {
4836 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4837 } else {
4838 TRACE("Got srcSurface %p\n", srcSurface);
4840 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4841 if (WINED3D_OK != hr) {
4842 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4843 } else {
4844 TRACE("Got desrSurface %p\n", destSurface);
4846 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4847 IWineD3DSurface_Release(srcSurface);
4848 IWineD3DSurface_Release(destSurface);
4849 if (WINED3D_OK != hr) {
4850 WARN("(%p) : Call to update surface failed\n", This);
4851 return hr;
4856 break;
4857 #if 0 /* TODO: Add support for volume textures */
4858 case WINED3DRTYPE_VOLUMETEXTURE:
4860 IWineD3DVolume srcVolume = NULL;
4861 IWineD3DSurface destVolume = NULL;
4863 for (i = 0 ; i < levels ; ++i) {
4864 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4865 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4866 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4867 IWineD3DVolume_Release(srcSurface);
4868 IWineD3DVolume_Release(destSurface);
4869 if (WINED3D_OK != hr) {
4870 WARN("(%p) : Call to update volume failed\n", This);
4871 return hr;
4875 break;
4876 #endif
4877 default:
4878 FIXME("(%p) : Unsupported source and destination type\n", This);
4879 hr = WINED3DERR_INVALIDCALL;
4883 return hr;
4886 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4887 IWineD3DSwapChain *swapChain;
4888 HRESULT hr;
4889 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4890 if(hr == WINED3D_OK) {
4891 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4892 IWineD3DSwapChain_Release(swapChain);
4894 return hr;
4897 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 /* return a sensible default */
4900 *pNumPasses = 1;
4901 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4902 FIXME("(%p) : stub\n", This);
4903 return WINED3D_OK;
4906 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4908 int j;
4909 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4910 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4911 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4912 return WINED3DERR_INVALIDCALL;
4914 for (j = 0; j < 256; ++j) {
4915 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4916 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4917 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4918 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4920 TRACE("(%p) : returning\n", This);
4921 return WINED3D_OK;
4924 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4926 int j;
4927 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4928 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4929 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4930 return WINED3DERR_INVALIDCALL;
4932 for (j = 0; j < 256; ++j) {
4933 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4934 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4935 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4936 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4938 TRACE("(%p) : returning\n", This);
4939 return WINED3D_OK;
4942 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4944 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4945 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4946 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4947 return WINED3DERR_INVALIDCALL;
4949 /*TODO: stateblocks */
4950 This->currentPalette = PaletteNumber;
4951 TRACE("(%p) : returning\n", This);
4952 return WINED3D_OK;
4955 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4957 if (PaletteNumber == NULL) {
4958 WARN("(%p) : returning Invalid Call\n", This);
4959 return WINED3DERR_INVALIDCALL;
4961 /*TODO: stateblocks */
4962 *PaletteNumber = This->currentPalette;
4963 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4964 return WINED3D_OK;
4967 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4969 static BOOL showFixmes = TRUE;
4970 if (showFixmes) {
4971 FIXME("(%p) : stub\n", This);
4972 showFixmes = FALSE;
4975 This->softwareVertexProcessing = bSoftware;
4976 return WINED3D_OK;
4980 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 static BOOL showFixmes = TRUE;
4983 if (showFixmes) {
4984 FIXME("(%p) : stub\n", This);
4985 showFixmes = FALSE;
4987 return This->softwareVertexProcessing;
4991 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4993 IWineD3DSwapChain *swapChain;
4994 HRESULT hr;
4996 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4998 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4999 if(hr == WINED3D_OK){
5000 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5001 IWineD3DSwapChain_Release(swapChain);
5002 }else{
5003 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5005 return hr;
5009 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5011 static BOOL showfixmes = TRUE;
5012 if(nSegments != 0.0f) {
5013 if( showfixmes) {
5014 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5015 showfixmes = FALSE;
5018 return WINED3D_OK;
5021 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5023 static BOOL showfixmes = TRUE;
5024 if( showfixmes) {
5025 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5026 showfixmes = FALSE;
5028 return 0.0f;
5031 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5033 /** TODO: remove casts to IWineD3DSurfaceImpl
5034 * NOTE: move code to surface to accomplish this
5035 ****************************************/
5036 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5037 int srcWidth, srcHeight;
5038 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5039 WINED3DFORMAT destFormat, srcFormat;
5040 UINT destSize;
5041 int srcLeft, destLeft, destTop;
5042 WINED3DPOOL srcPool, destPool;
5043 int offset = 0;
5044 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5045 glDescriptor *glDescription = NULL;
5047 WINED3DSURFACE_DESC winedesc;
5049 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5050 memset(&winedesc, 0, sizeof(winedesc));
5051 winedesc.Width = &srcSurfaceWidth;
5052 winedesc.Height = &srcSurfaceHeight;
5053 winedesc.Pool = &srcPool;
5054 winedesc.Format = &srcFormat;
5056 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5058 winedesc.Width = &destSurfaceWidth;
5059 winedesc.Height = &destSurfaceHeight;
5060 winedesc.Pool = &destPool;
5061 winedesc.Format = &destFormat;
5062 winedesc.Size = &destSize;
5064 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5066 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5067 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5068 return WINED3DERR_INVALIDCALL;
5071 if (destFormat == WINED3DFMT_UNKNOWN) {
5072 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5073 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5075 /* Get the update surface description */
5076 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5079 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5081 ENTER_GL();
5083 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5084 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5085 checkGLcall("glActiveTextureARB");
5088 /* Make sure the surface is loaded and up to date */
5089 IWineD3DSurface_PreLoad(pDestinationSurface);
5091 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5093 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5094 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5095 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5096 srcLeft = pSourceRect ? pSourceRect->left : 0;
5097 destLeft = pDestPoint ? pDestPoint->x : 0;
5098 destTop = pDestPoint ? pDestPoint->y : 0;
5101 /* This function doesn't support compressed textures
5102 the pitch is just bytesPerPixel * width */
5103 if(srcWidth != srcSurfaceWidth || srcLeft ){
5104 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5105 offset += srcLeft * pSrcSurface->bytesPerPixel;
5106 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5108 /* TODO DXT formats */
5110 if(pSourceRect != NULL && pSourceRect->top != 0){
5111 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5113 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5114 ,This
5115 ,glDescription->level
5116 ,destLeft
5117 ,destTop
5118 ,srcWidth
5119 ,srcHeight
5120 ,glDescription->glFormat
5121 ,glDescription->glType
5122 ,IWineD3DSurface_GetData(pSourceSurface)
5125 /* Sanity check */
5126 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5128 /* need to lock the surface to get the data */
5129 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5132 /* TODO: Cube and volume support */
5133 if(rowoffset != 0){
5134 /* not a whole row so we have to do it a line at a time */
5135 int j;
5137 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5138 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5140 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5142 glTexSubImage2D(glDescription->target
5143 ,glDescription->level
5144 ,destLeft
5146 ,srcWidth
5148 ,glDescription->glFormat
5149 ,glDescription->glType
5150 ,data /* could be quicker using */
5152 data += rowoffset;
5155 } else { /* Full width, so just write out the whole texture */
5157 if (WINED3DFMT_DXT1 == destFormat ||
5158 WINED3DFMT_DXT2 == destFormat ||
5159 WINED3DFMT_DXT3 == destFormat ||
5160 WINED3DFMT_DXT4 == destFormat ||
5161 WINED3DFMT_DXT5 == destFormat) {
5162 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5163 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5164 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5165 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5166 } if (destFormat != srcFormat) {
5167 FIXME("Updating mixed format compressed texture is not curretly support\n");
5168 } else {
5169 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5170 glDescription->level,
5171 glDescription->glFormatInternal,
5172 srcWidth,
5173 srcHeight,
5175 destSize,
5176 IWineD3DSurface_GetData(pSourceSurface));
5178 } else {
5179 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5183 } else {
5184 glTexSubImage2D(glDescription->target
5185 ,glDescription->level
5186 ,destLeft
5187 ,destTop
5188 ,srcWidth
5189 ,srcHeight
5190 ,glDescription->glFormat
5191 ,glDescription->glType
5192 ,IWineD3DSurface_GetData(pSourceSurface)
5196 checkGLcall("glTexSubImage2D");
5198 LEAVE_GL();
5200 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5201 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5204 return WINED3D_OK;
5207 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5209 struct WineD3DRectPatch *patch;
5210 unsigned int i;
5211 struct list *e;
5212 BOOL found;
5213 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5215 if(!(Handle || pRectPatchInfo)) {
5216 /* TODO: Write a test for the return value, thus the FIXME */
5217 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5218 return WINED3DERR_INVALIDCALL;
5221 if(Handle) {
5222 i = PATCHMAP_HASHFUNC(Handle);
5223 found = FALSE;
5224 LIST_FOR_EACH(e, &This->patches[i]) {
5225 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5226 if(patch->Handle == Handle) {
5227 found = TRUE;
5228 break;
5232 if(!found) {
5233 TRACE("Patch does not exist. Creating a new one\n");
5234 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5235 patch->Handle = Handle;
5236 list_add_head(&This->patches[i], &patch->entry);
5237 } else {
5238 TRACE("Found existing patch %p\n", patch);
5240 } else {
5241 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5242 * attributes we have to tesselate, read back, and draw. This needs a patch
5243 * management structure instance. Create one.
5245 * A possible improvement is to check if a vertex shader is used, and if not directly
5246 * draw the patch.
5248 FIXME("Drawing an uncached patch. This is slow\n");
5249 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5252 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5253 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5254 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5255 HRESULT hr;
5256 TRACE("Tesselation density or patch info changed, retesselating\n");
5258 if(pRectPatchInfo) {
5259 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5261 patch->numSegs[0] = pNumSegs[0];
5262 patch->numSegs[1] = pNumSegs[1];
5263 patch->numSegs[2] = pNumSegs[2];
5264 patch->numSegs[3] = pNumSegs[3];
5266 hr = tesselate_rectpatch(This, patch);
5267 if(FAILED(hr)) {
5268 WARN("Patch tesselation failed\n");
5270 /* Do not release the handle to store the params of the patch */
5271 if(!Handle) {
5272 HeapFree(GetProcessHeap(), 0, patch);
5274 return hr;
5278 This->currentPatch = patch;
5279 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5280 This->currentPatch = NULL;
5282 /* Destroy uncached patches */
5283 if(!Handle) {
5284 HeapFree(GetProcessHeap(), 0, patch->mem);
5285 HeapFree(GetProcessHeap(), 0, patch);
5287 return WINED3D_OK;
5290 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5291 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5293 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5294 FIXME("(%p) : Stub\n", This);
5295 return WINED3D_OK;
5298 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5300 int i;
5301 struct WineD3DRectPatch *patch;
5302 struct list *e;
5303 TRACE("(%p) Handle(%d)\n", This, Handle);
5305 i = PATCHMAP_HASHFUNC(Handle);
5306 LIST_FOR_EACH(e, &This->patches[i]) {
5307 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5308 if(patch->Handle == Handle) {
5309 TRACE("Deleting patch %p\n", patch);
5310 list_remove(&patch->entry);
5311 HeapFree(GetProcessHeap(), 0, patch->mem);
5312 HeapFree(GetProcessHeap(), 0, patch);
5313 return WINED3D_OK;
5317 /* TODO: Write a test for the return value */
5318 FIXME("Attempt to destroy nonexistant patch\n");
5319 return WINED3DERR_INVALIDCALL;
5322 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5323 HRESULT hr;
5324 IWineD3DSwapChain *swapchain;
5326 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5327 if (SUCCEEDED(hr)) {
5328 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5329 return swapchain;
5332 return NULL;
5335 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 if (!*fbo) {
5339 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5340 checkGLcall("glGenFramebuffersEXT()");
5342 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5343 checkGLcall("glBindFramebuffer()");
5346 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5347 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5348 IWineD3DBaseTextureImpl *texture_impl;
5349 GLenum texttarget, target;
5350 GLint old_binding;
5352 texttarget = surface_impl->glDescription.target;
5353 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5354 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5356 IWineD3DSurface_PreLoad(surface);
5358 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5359 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5360 glBindTexture(target, old_binding);
5362 /* Update base texture states array */
5363 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5364 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5365 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5366 if (texture_impl->baseTexture.bindCount) {
5367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5370 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5373 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5375 checkGLcall("attach_surface_fbo");
5378 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5380 IWineD3DSwapChain *swapchain;
5382 swapchain = get_swapchain(surface);
5383 if (swapchain) {
5384 GLenum buffer;
5386 TRACE("Surface %p is onscreen\n", surface);
5388 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5389 buffer = surface_get_gl_buffer(surface, swapchain);
5390 glDrawBuffer(buffer);
5391 checkGLcall("glDrawBuffer()");
5392 } else {
5393 TRACE("Surface %p is offscreen\n", surface);
5394 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5395 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5398 if (rect) {
5399 glEnable(GL_SCISSOR_TEST);
5400 if(!swapchain) {
5401 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5402 } else {
5403 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5404 rect->x2 - rect->x1, rect->y2 - rect->y1);
5406 checkGLcall("glScissor");
5407 } else {
5408 glDisable(GL_SCISSOR_TEST);
5410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5412 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5415 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5416 glClear(GL_COLOR_BUFFER_BIT);
5417 checkGLcall("glClear");
5419 if (This->render_offscreen) {
5420 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5421 } else {
5422 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5423 checkGLcall("glBindFramebuffer()");
5426 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5427 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5428 glDrawBuffer(GL_BACK);
5429 checkGLcall("glDrawBuffer()");
5433 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5435 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5436 WINEDDBLTFX BltFx;
5437 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5439 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5440 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5441 return WINED3DERR_INVALIDCALL;
5444 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5445 color_fill_fbo(iface, pSurface, pRect, color);
5446 return WINED3D_OK;
5447 } else {
5448 /* Just forward this to the DirectDraw blitting engine */
5449 memset(&BltFx, 0, sizeof(BltFx));
5450 BltFx.dwSize = sizeof(BltFx);
5451 BltFx.u5.dwFillColor = color;
5452 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5456 /* rendertarget and deptth stencil functions */
5457 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5460 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5461 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5462 return WINED3DERR_INVALIDCALL;
5465 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5466 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5467 /* Note inc ref on returned surface */
5468 if(*ppRenderTarget != NULL)
5469 IWineD3DSurface_AddRef(*ppRenderTarget);
5470 return WINED3D_OK;
5473 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5475 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5476 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5477 IWineD3DSwapChainImpl *Swapchain;
5478 HRESULT hr;
5480 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5482 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5483 if(hr != WINED3D_OK) {
5484 ERR("Can't get the swapchain\n");
5485 return hr;
5488 /* Make sure to release the swapchain */
5489 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5491 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5492 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5493 return WINED3DERR_INVALIDCALL;
5495 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5496 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5497 return WINED3DERR_INVALIDCALL;
5500 if(Swapchain->frontBuffer != Front) {
5501 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5503 if(Swapchain->frontBuffer)
5504 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5505 Swapchain->frontBuffer = Front;
5507 if(Swapchain->frontBuffer) {
5508 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5512 if(Back && !Swapchain->backBuffer) {
5513 /* We need memory for the back buffer array - only one back buffer this way */
5514 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5515 if(!Swapchain->backBuffer) {
5516 ERR("Out of memory\n");
5517 return E_OUTOFMEMORY;
5521 if(Swapchain->backBuffer[0] != Back) {
5522 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5524 /* What to do about the context here in the case of multithreading? Not sure.
5525 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5527 ENTER_GL();
5528 if(!Swapchain->backBuffer[0]) {
5529 /* GL was told to draw to the front buffer at creation,
5530 * undo that
5532 glDrawBuffer(GL_BACK);
5533 checkGLcall("glDrawBuffer(GL_BACK)");
5534 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5535 Swapchain->presentParms.BackBufferCount = 1;
5536 } else if (!Back) {
5537 /* That makes problems - disable for now */
5538 /* glDrawBuffer(GL_FRONT); */
5539 checkGLcall("glDrawBuffer(GL_FRONT)");
5540 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5541 Swapchain->presentParms.BackBufferCount = 0;
5543 LEAVE_GL();
5545 if(Swapchain->backBuffer[0])
5546 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5547 Swapchain->backBuffer[0] = Back;
5549 if(Swapchain->backBuffer[0]) {
5550 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5551 } else {
5552 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5557 return WINED3D_OK;
5560 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5562 *ppZStencilSurface = This->depthStencilBuffer;
5563 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5565 if(*ppZStencilSurface != NULL) {
5566 /* Note inc ref on returned surface */
5567 IWineD3DSurface_AddRef(*ppZStencilSurface);
5569 return WINED3D_OK;
5572 /* TODO: Handle stencil attachments */
5573 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5575 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5577 TRACE("Set depth stencil to %p\n", depth_stencil);
5579 if (depth_stencil_impl) {
5580 if (depth_stencil_impl->current_renderbuffer) {
5581 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5582 checkGLcall("glFramebufferRenderbufferEXT()");
5583 } else {
5584 IWineD3DBaseTextureImpl *texture_impl;
5585 GLenum texttarget, target;
5586 GLint old_binding = 0;
5588 texttarget = depth_stencil_impl->glDescription.target;
5589 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5590 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5592 IWineD3DSurface_PreLoad(depth_stencil);
5594 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5595 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5596 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5597 glBindTexture(target, old_binding);
5599 /* Update base texture states array */
5600 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5601 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5602 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5603 if (texture_impl->baseTexture.bindCount) {
5604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5607 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5610 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5611 checkGLcall("glFramebufferTexture2DEXT()");
5613 } else {
5614 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5615 checkGLcall("glFramebufferTexture2DEXT()");
5619 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5621 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5623 TRACE("Set render target %u to %p\n", idx, render_target);
5625 if (rtimpl) {
5626 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5627 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5628 } else {
5629 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5630 checkGLcall("glFramebufferTexture2DEXT()");
5632 This->draw_buffers[idx] = GL_NONE;
5636 static void check_fbo_status(IWineD3DDevice *iface) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5638 GLenum status;
5640 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5641 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5642 TRACE("FBO complete\n");
5643 } else {
5644 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5646 /* Dump the FBO attachments */
5647 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5648 IWineD3DSurfaceImpl *attachment;
5649 int i;
5651 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5652 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5653 if (attachment) {
5654 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5655 attachment->pow2Width, attachment->pow2Height);
5658 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5659 if (attachment) {
5660 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5661 attachment->pow2Width, attachment->pow2Height);
5667 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5669 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5670 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5672 if (!ds_impl) return FALSE;
5674 if (ds_impl->current_renderbuffer) {
5675 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5676 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5679 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5680 rt_impl->pow2Height != ds_impl->pow2Height);
5683 void apply_fbo_state(IWineD3DDevice *iface) {
5684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5685 unsigned int i;
5687 if (This->render_offscreen) {
5688 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5690 /* Apply render targets */
5691 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5692 IWineD3DSurface *render_target = This->render_targets[i];
5693 if (This->fbo_color_attachments[i] != render_target) {
5694 set_render_target_fbo(iface, i, render_target);
5695 This->fbo_color_attachments[i] = render_target;
5699 /* Apply depth targets */
5700 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5701 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5702 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5704 if (This->stencilBufferTarget) {
5705 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5707 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5708 This->fbo_depth_attachment = This->stencilBufferTarget;
5711 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5712 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5713 checkGLcall("glDrawBuffers()");
5714 } else {
5715 glDrawBuffer(This->draw_buffers[0]);
5716 checkGLcall("glDrawBuffer()");
5718 } else {
5719 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5722 check_fbo_status(iface);
5725 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5726 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5729 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5730 GLenum gl_filter;
5732 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5733 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5734 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5735 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5737 switch (filter) {
5738 case WINED3DTEXF_LINEAR:
5739 gl_filter = GL_LINEAR;
5740 break;
5742 default:
5743 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5744 case WINED3DTEXF_NONE:
5745 case WINED3DTEXF_POINT:
5746 gl_filter = GL_NEAREST;
5747 break;
5750 /* Attach src surface to src fbo */
5751 src_swapchain = get_swapchain(src_surface);
5752 if (src_swapchain) {
5753 GLenum buffer;
5755 TRACE("Source surface %p is onscreen\n", src_surface);
5756 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5758 ENTER_GL();
5759 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5760 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5761 glReadBuffer(buffer);
5762 checkGLcall("glReadBuffer()");
5764 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5765 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5766 } else {
5767 TRACE("Source surface %p is offscreen\n", src_surface);
5768 ENTER_GL();
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()");
5774 LEAVE_GL();
5776 /* Attach dst surface to dst fbo */
5777 dst_swapchain = get_swapchain(dst_surface);
5778 if (dst_swapchain) {
5779 GLenum buffer;
5781 TRACE("Destination surface %p is onscreen\n", dst_surface);
5782 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5784 ENTER_GL();
5785 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5786 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5787 glDrawBuffer(buffer);
5788 checkGLcall("glDrawBuffer()");
5790 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5791 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5792 } else {
5793 TRACE("Destination surface %p is offscreen\n", dst_surface);
5795 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5796 if(!src_swapchain) {
5797 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5800 ENTER_GL();
5801 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5802 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5803 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5804 checkGLcall("glDrawBuffer()");
5806 glDisable(GL_SCISSOR_TEST);
5807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5809 if (flip) {
5810 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5811 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5812 checkGLcall("glBlitFramebuffer()");
5813 } else {
5814 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5815 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5816 checkGLcall("glBlitFramebuffer()");
5819 if (This->render_offscreen) {
5820 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5821 } else {
5822 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5823 checkGLcall("glBindFramebuffer()");
5826 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5827 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5828 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5829 glDrawBuffer(GL_BACK);
5830 checkGLcall("glDrawBuffer()");
5832 LEAVE_GL();
5835 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5837 WINED3DVIEWPORT viewport;
5839 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5841 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5842 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5843 return WINED3DERR_INVALIDCALL;
5846 /* MSDN says that null disables the render target
5847 but a device must always be associated with a render target
5848 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5850 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5851 for more details
5853 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5854 FIXME("Trying to set render target 0 to NULL\n");
5855 return WINED3DERR_INVALIDCALL;
5857 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5858 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);
5859 return WINED3DERR_INVALIDCALL;
5862 /* If we are trying to set what we already have, don't bother */
5863 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5864 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5865 return WINED3D_OK;
5867 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5868 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5869 This->render_targets[RenderTargetIndex] = pRenderTarget;
5871 /* Render target 0 is special */
5872 if(RenderTargetIndex == 0) {
5873 /* Finally, reset the viewport as the MSDN states. */
5874 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5875 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5876 viewport.X = 0;
5877 viewport.Y = 0;
5878 viewport.MaxZ = 1.0f;
5879 viewport.MinZ = 0.0f;
5880 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5881 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5882 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5886 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5887 * ctx properly.
5888 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5889 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5891 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5893 return WINED3D_OK;
5896 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5898 HRESULT hr = WINED3D_OK;
5899 IWineD3DSurface *tmp;
5901 TRACE("(%p) Swapping z-buffer\n",This);
5903 if (pNewZStencil == This->stencilBufferTarget) {
5904 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5905 } else {
5906 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5907 * depending on the renter target implementation being used.
5908 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5909 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5910 * stencil buffer and incure an extra memory overhead
5911 ******************************************************/
5913 tmp = This->stencilBufferTarget;
5914 This->stencilBufferTarget = pNewZStencil;
5915 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5916 /* should we be calling the parent or the wined3d surface? */
5917 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5918 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5919 hr = WINED3D_OK;
5921 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5922 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5925 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5929 return hr;
5932 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5933 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5935 /* TODO: the use of Impl is deprecated. */
5936 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5937 WINED3DLOCKED_RECT lockedRect;
5939 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5941 /* some basic validation checks */
5942 if(This->cursorTexture) {
5943 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5944 ENTER_GL();
5945 glDeleteTextures(1, &This->cursorTexture);
5946 LEAVE_GL();
5947 This->cursorTexture = 0;
5950 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5951 This->haveHardwareCursor = TRUE;
5952 else
5953 This->haveHardwareCursor = FALSE;
5955 if(pCursorBitmap) {
5956 WINED3DLOCKED_RECT rect;
5958 /* MSDN: Cursor must be A8R8G8B8 */
5959 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5960 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5961 return WINED3DERR_INVALIDCALL;
5964 /* MSDN: Cursor must be smaller than the display mode */
5965 if(pSur->currentDesc.Width > This->ddraw_width ||
5966 pSur->currentDesc.Height > This->ddraw_height) {
5967 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);
5968 return WINED3DERR_INVALIDCALL;
5971 if (!This->haveHardwareCursor) {
5972 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5974 /* Do not store the surface's pointer because the application may
5975 * release it after setting the cursor image. Windows doesn't
5976 * addref the set surface, so we can't do this either without
5977 * creating circular refcount dependencies. Copy out the gl texture
5978 * instead.
5980 This->cursorWidth = pSur->currentDesc.Width;
5981 This->cursorHeight = pSur->currentDesc.Height;
5982 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5984 const GlPixelFormatDesc *glDesc;
5985 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
5986 char *mem, *bits = (char *)rect.pBits;
5987 GLint intfmt = glDesc->glInternal;
5988 GLint format = glDesc->glFormat;
5989 GLint type = glDesc->glType;
5990 INT height = This->cursorHeight;
5991 INT width = This->cursorWidth;
5992 INT bpp = tableEntry->bpp;
5993 INT i;
5995 /* Reformat the texture memory (pitch and width can be
5996 * different) */
5997 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5998 for(i = 0; i < height; i++)
5999 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6000 IWineD3DSurface_UnlockRect(pCursorBitmap);
6001 ENTER_GL();
6003 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6004 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6005 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6008 /* Make sure that a proper texture unit is selected */
6009 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6010 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6011 checkGLcall("glActiveTextureARB");
6013 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6014 /* Create a new cursor texture */
6015 glGenTextures(1, &This->cursorTexture);
6016 checkGLcall("glGenTextures");
6017 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6018 checkGLcall("glBindTexture");
6019 /* Copy the bitmap memory into the cursor texture */
6020 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6021 HeapFree(GetProcessHeap(), 0, mem);
6022 checkGLcall("glTexImage2D");
6024 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6025 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6026 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6029 LEAVE_GL();
6031 else
6033 FIXME("A cursor texture was not returned.\n");
6034 This->cursorTexture = 0;
6037 else
6039 /* Draw a hardware cursor */
6040 ICONINFO cursorInfo;
6041 HCURSOR cursor;
6042 /* Create and clear maskBits because it is not needed for
6043 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6044 * chunks. */
6045 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6046 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6047 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6048 WINED3DLOCK_NO_DIRTY_UPDATE |
6049 WINED3DLOCK_READONLY
6051 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6052 pSur->currentDesc.Height);
6054 cursorInfo.fIcon = FALSE;
6055 cursorInfo.xHotspot = XHotSpot;
6056 cursorInfo.yHotspot = YHotSpot;
6057 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6058 pSur->currentDesc.Height, 1,
6059 1, &maskBits);
6060 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6061 pSur->currentDesc.Height, 1,
6062 32, lockedRect.pBits);
6063 IWineD3DSurface_UnlockRect(pCursorBitmap);
6064 /* Create our cursor and clean up. */
6065 cursor = CreateIconIndirect(&cursorInfo);
6066 SetCursor(cursor);
6067 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6068 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6069 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6070 This->hardwareCursor = cursor;
6071 HeapFree(GetProcessHeap(), 0, maskBits);
6075 This->xHotSpot = XHotSpot;
6076 This->yHotSpot = YHotSpot;
6077 return WINED3D_OK;
6080 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6082 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6084 This->xScreenSpace = XScreenSpace;
6085 This->yScreenSpace = YScreenSpace;
6087 return;
6091 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6093 BOOL oldVisible = This->bCursorVisible;
6094 POINT pt;
6096 TRACE("(%p) : visible(%d)\n", This, bShow);
6099 * When ShowCursor is first called it should make the cursor appear at the OS's last
6100 * known cursor position. Because of this, some applications just repetitively call
6101 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6103 GetCursorPos(&pt);
6104 This->xScreenSpace = pt.x;
6105 This->yScreenSpace = pt.y;
6107 if (This->haveHardwareCursor) {
6108 This->bCursorVisible = bShow;
6109 if (bShow)
6110 SetCursor(This->hardwareCursor);
6111 else
6112 SetCursor(NULL);
6114 else
6116 if (This->cursorTexture)
6117 This->bCursorVisible = bShow;
6120 return oldVisible;
6123 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6125 TRACE("(%p) : state (%u)\n", This, This->state);
6126 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6127 switch (This->state) {
6128 case WINED3D_OK:
6129 return WINED3D_OK;
6130 case WINED3DERR_DEVICELOST:
6132 ResourceList *resourceList = This->resources;
6133 while (NULL != resourceList) {
6134 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6135 return WINED3DERR_DEVICENOTRESET;
6136 resourceList = resourceList->next;
6138 return WINED3DERR_DEVICELOST;
6140 case WINED3DERR_DRIVERINTERNALERROR:
6141 return WINED3DERR_DRIVERINTERNALERROR;
6144 /* Unknown state */
6145 return WINED3DERR_DRIVERINTERNALERROR;
6149 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6151 /** FIXME: Resource tracking needs to be done,
6152 * The closes we can do to this is set the priorities of all managed textures low
6153 * and then reset them.
6154 ***********************************************************/
6155 FIXME("(%p) : stub\n", This);
6156 return WINED3D_OK;
6159 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6160 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6162 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6163 if(surface->Flags & SFLAG_DIBSECTION) {
6164 /* Release the DC */
6165 SelectObject(surface->hDC, surface->dib.holdbitmap);
6166 DeleteDC(surface->hDC);
6167 /* Release the DIB section */
6168 DeleteObject(surface->dib.DIBsection);
6169 surface->dib.bitmap_data = NULL;
6170 surface->resource.allocatedMemory = NULL;
6171 surface->Flags &= ~SFLAG_DIBSECTION;
6173 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6174 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6175 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6176 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6177 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6178 } else {
6179 surface->pow2Width = surface->pow2Height = 1;
6180 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6181 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6183 if(surface->glDescription.textureName) {
6184 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6185 ENTER_GL();
6186 glDeleteTextures(1, &surface->glDescription.textureName);
6187 LEAVE_GL();
6188 surface->glDescription.textureName = 0;
6189 surface->Flags &= ~SFLAG_CLIENT;
6191 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6192 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6193 surface->Flags |= SFLAG_NONPOW2;
6194 } else {
6195 surface->Flags &= ~SFLAG_NONPOW2;
6197 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6198 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6201 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6203 IWineD3DSwapChainImpl *swapchain;
6204 HRESULT hr;
6205 BOOL DisplayModeChanged = FALSE;
6206 WINED3DDISPLAYMODE mode;
6207 TRACE("(%p)\n", This);
6209 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6210 if(FAILED(hr)) {
6211 ERR("Failed to get the first implicit swapchain\n");
6212 return hr;
6215 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6216 * on an existing gl context, so there's no real need for recreation.
6218 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6220 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6222 TRACE("New params:\n");
6223 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6224 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6225 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6226 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6227 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6228 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6229 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6230 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6231 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6232 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6233 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6234 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6235 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6237 /* No special treatment of these parameters. Just store them */
6238 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6239 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6240 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6241 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6243 /* What to do about these? */
6244 if(pPresentationParameters->BackBufferCount != 0 &&
6245 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6246 ERR("Cannot change the back buffer count yet\n");
6248 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6249 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6250 ERR("Cannot change the back buffer format yet\n");
6252 if(pPresentationParameters->hDeviceWindow != NULL &&
6253 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6254 ERR("Cannot change the device window yet\n");
6256 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6257 ERR("What do do about a changed auto depth stencil parameter?\n");
6260 if(pPresentationParameters->Windowed) {
6261 mode.Width = swapchain->orig_width;
6262 mode.Height = swapchain->orig_height;
6263 mode.RefreshRate = 0;
6264 mode.Format = swapchain->presentParms.BackBufferFormat;
6265 } else {
6266 mode.Width = pPresentationParameters->BackBufferWidth;
6267 mode.Height = pPresentationParameters->BackBufferHeight;
6268 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6269 mode.Format = swapchain->presentParms.BackBufferFormat;
6272 /* Should Width == 800 && Height == 0 set 800x600? */
6273 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6274 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6275 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6277 WINED3DVIEWPORT vp;
6278 int i;
6280 vp.X = 0;
6281 vp.Y = 0;
6282 vp.Width = pPresentationParameters->BackBufferWidth;
6283 vp.Height = pPresentationParameters->BackBufferHeight;
6284 vp.MinZ = 0;
6285 vp.MaxZ = 1;
6287 if(!pPresentationParameters->Windowed) {
6288 DisplayModeChanged = TRUE;
6290 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6291 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6293 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6294 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6295 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6298 /* Now set the new viewport */
6299 IWineD3DDevice_SetViewport(iface, &vp);
6302 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6303 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6304 DisplayModeChanged) {
6306 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6307 if(!pPresentationParameters->Windowed) {
6308 IWineD3DDevice_SetFullscreen(iface, TRUE);
6311 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6313 /* Switching out of fullscreen mode? First set the original res, then change the window */
6314 if(pPresentationParameters->Windowed) {
6315 IWineD3DDevice_SetFullscreen(iface, FALSE);
6317 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6320 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6321 return WINED3D_OK;
6324 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6326 /** FIXME: always true at the moment **/
6327 if(!bEnableDialogs) {
6328 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6330 return WINED3D_OK;
6334 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6336 TRACE("(%p) : pParameters %p\n", This, pParameters);
6338 *pParameters = This->createParms;
6339 return WINED3D_OK;
6342 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6343 IWineD3DSwapChain *swapchain;
6344 HRESULT hrc = WINED3D_OK;
6346 TRACE("Relaying to swapchain\n");
6348 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6349 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6350 IWineD3DSwapChain_Release(swapchain);
6352 return;
6355 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6356 IWineD3DSwapChain *swapchain;
6357 HRESULT hrc = WINED3D_OK;
6359 TRACE("Relaying to swapchain\n");
6361 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6362 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6363 IWineD3DSwapChain_Release(swapchain);
6365 return;
6369 /** ********************************************************
6370 * Notification functions
6371 ** ********************************************************/
6372 /** This function must be called in the release of a resource when ref == 0,
6373 * the contents of resource must still be correct,
6374 * any handels to other resource held by the caller must be closed
6375 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6376 *****************************************************/
6377 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6379 ResourceList* resourceList;
6381 TRACE("(%p) : resource %p\n", This, resource);
6382 /* add a new texture to the frot of the linked list */
6383 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6384 resourceList->resource = resource;
6386 /* Get the old head */
6387 resourceList->next = This->resources;
6389 This->resources = resourceList;
6390 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6392 return;
6395 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6397 ResourceList* resourceList = NULL;
6398 ResourceList* previousResourceList = NULL;
6400 TRACE("(%p) : resource %p\n", This, resource);
6402 resourceList = This->resources;
6404 while (resourceList != NULL) {
6405 if(resourceList->resource == resource) break;
6406 previousResourceList = resourceList;
6407 resourceList = resourceList->next;
6410 if (resourceList == NULL) {
6411 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6412 return;
6413 } else {
6414 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6416 /* make sure we don't leave a hole in the list */
6417 if (previousResourceList != NULL) {
6418 previousResourceList->next = resourceList->next;
6419 } else {
6420 This->resources = resourceList->next;
6423 return;
6427 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6429 int counter;
6431 TRACE("(%p) : resource %p\n", This, resource);
6432 switch(IWineD3DResource_GetType(resource)){
6433 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6434 case WINED3DRTYPE_SURFACE: {
6435 unsigned int i;
6437 /* Cleanup any FBO attachments if d3d is enabled */
6438 if(This->d3d_initialized) {
6439 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6440 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6441 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6442 set_render_target_fbo(iface, i, NULL);
6443 This->fbo_color_attachments[i] = NULL;
6446 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6447 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6448 set_depth_stencil_fbo(iface, NULL);
6449 This->fbo_depth_attachment = NULL;
6453 break;
6455 case WINED3DRTYPE_TEXTURE:
6456 case WINED3DRTYPE_CUBETEXTURE:
6457 case WINED3DRTYPE_VOLUMETEXTURE:
6458 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6459 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6460 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6461 This->stateBlock->textures[counter] = NULL;
6463 if (This->updateStateBlock != This->stateBlock ){
6464 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6465 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6466 This->updateStateBlock->textures[counter] = NULL;
6470 break;
6471 case WINED3DRTYPE_VOLUME:
6472 /* TODO: nothing really? */
6473 break;
6474 case WINED3DRTYPE_VERTEXBUFFER:
6475 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6477 int streamNumber;
6478 TRACE("Cleaning up stream pointers\n");
6480 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6481 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6482 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6484 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6485 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6486 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6487 This->updateStateBlock->streamSource[streamNumber] = 0;
6488 /* Set changed flag? */
6491 if (This->stateBlock != NULL ) { /* only happens if there is an error in the application, or on reset/release (because we don't manage internal tracking properly) */
6492 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6493 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6494 This->stateBlock->streamSource[streamNumber] = 0;
6497 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6498 else { /* This shouldn't happen */
6499 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6501 #endif
6505 break;
6506 case WINED3DRTYPE_INDEXBUFFER:
6507 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6508 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6509 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6510 This->updateStateBlock->pIndexData = NULL;
6513 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6514 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6515 This->stateBlock->pIndexData = NULL;
6519 break;
6520 default:
6521 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6522 break;
6526 /* Remove the resoruce from the resourceStore */
6527 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6529 TRACE("Resource released\n");
6533 /**********************************************************
6534 * IWineD3DDevice VTbl follows
6535 **********************************************************/
6537 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6539 /*** IUnknown methods ***/
6540 IWineD3DDeviceImpl_QueryInterface,
6541 IWineD3DDeviceImpl_AddRef,
6542 IWineD3DDeviceImpl_Release,
6543 /*** IWineD3DDevice methods ***/
6544 IWineD3DDeviceImpl_GetParent,
6545 /*** Creation methods**/
6546 IWineD3DDeviceImpl_CreateVertexBuffer,
6547 IWineD3DDeviceImpl_CreateIndexBuffer,
6548 IWineD3DDeviceImpl_CreateStateBlock,
6549 IWineD3DDeviceImpl_CreateSurface,
6550 IWineD3DDeviceImpl_CreateTexture,
6551 IWineD3DDeviceImpl_CreateVolumeTexture,
6552 IWineD3DDeviceImpl_CreateVolume,
6553 IWineD3DDeviceImpl_CreateCubeTexture,
6554 IWineD3DDeviceImpl_CreateQuery,
6555 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6556 IWineD3DDeviceImpl_CreateVertexDeclaration,
6557 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6558 IWineD3DDeviceImpl_CreateVertexShader,
6559 IWineD3DDeviceImpl_CreatePixelShader,
6560 IWineD3DDeviceImpl_CreatePalette,
6561 /*** Odd functions **/
6562 IWineD3DDeviceImpl_Init3D,
6563 IWineD3DDeviceImpl_Uninit3D,
6564 IWineD3DDeviceImpl_SetFullscreen,
6565 IWineD3DDeviceImpl_SetMultithreaded,
6566 IWineD3DDeviceImpl_EvictManagedResources,
6567 IWineD3DDeviceImpl_GetAvailableTextureMem,
6568 IWineD3DDeviceImpl_GetBackBuffer,
6569 IWineD3DDeviceImpl_GetCreationParameters,
6570 IWineD3DDeviceImpl_GetDeviceCaps,
6571 IWineD3DDeviceImpl_GetDirect3D,
6572 IWineD3DDeviceImpl_GetDisplayMode,
6573 IWineD3DDeviceImpl_SetDisplayMode,
6574 IWineD3DDeviceImpl_GetHWND,
6575 IWineD3DDeviceImpl_SetHWND,
6576 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6577 IWineD3DDeviceImpl_GetRasterStatus,
6578 IWineD3DDeviceImpl_GetSwapChain,
6579 IWineD3DDeviceImpl_Reset,
6580 IWineD3DDeviceImpl_SetDialogBoxMode,
6581 IWineD3DDeviceImpl_SetCursorProperties,
6582 IWineD3DDeviceImpl_SetCursorPosition,
6583 IWineD3DDeviceImpl_ShowCursor,
6584 IWineD3DDeviceImpl_TestCooperativeLevel,
6585 /*** Getters and setters **/
6586 IWineD3DDeviceImpl_SetClipPlane,
6587 IWineD3DDeviceImpl_GetClipPlane,
6588 IWineD3DDeviceImpl_SetClipStatus,
6589 IWineD3DDeviceImpl_GetClipStatus,
6590 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6591 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6592 IWineD3DDeviceImpl_SetDepthStencilSurface,
6593 IWineD3DDeviceImpl_GetDepthStencilSurface,
6594 IWineD3DDeviceImpl_SetFVF,
6595 IWineD3DDeviceImpl_GetFVF,
6596 IWineD3DDeviceImpl_SetGammaRamp,
6597 IWineD3DDeviceImpl_GetGammaRamp,
6598 IWineD3DDeviceImpl_SetIndices,
6599 IWineD3DDeviceImpl_GetIndices,
6600 IWineD3DDeviceImpl_SetBaseVertexIndex,
6601 IWineD3DDeviceImpl_GetBaseVertexIndex,
6602 IWineD3DDeviceImpl_SetLight,
6603 IWineD3DDeviceImpl_GetLight,
6604 IWineD3DDeviceImpl_SetLightEnable,
6605 IWineD3DDeviceImpl_GetLightEnable,
6606 IWineD3DDeviceImpl_SetMaterial,
6607 IWineD3DDeviceImpl_GetMaterial,
6608 IWineD3DDeviceImpl_SetNPatchMode,
6609 IWineD3DDeviceImpl_GetNPatchMode,
6610 IWineD3DDeviceImpl_SetPaletteEntries,
6611 IWineD3DDeviceImpl_GetPaletteEntries,
6612 IWineD3DDeviceImpl_SetPixelShader,
6613 IWineD3DDeviceImpl_GetPixelShader,
6614 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6615 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6616 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6617 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6618 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6619 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6620 IWineD3DDeviceImpl_SetRenderState,
6621 IWineD3DDeviceImpl_GetRenderState,
6622 IWineD3DDeviceImpl_SetRenderTarget,
6623 IWineD3DDeviceImpl_GetRenderTarget,
6624 IWineD3DDeviceImpl_SetFrontBackBuffers,
6625 IWineD3DDeviceImpl_SetSamplerState,
6626 IWineD3DDeviceImpl_GetSamplerState,
6627 IWineD3DDeviceImpl_SetScissorRect,
6628 IWineD3DDeviceImpl_GetScissorRect,
6629 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6630 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6631 IWineD3DDeviceImpl_SetStreamSource,
6632 IWineD3DDeviceImpl_GetStreamSource,
6633 IWineD3DDeviceImpl_SetStreamSourceFreq,
6634 IWineD3DDeviceImpl_GetStreamSourceFreq,
6635 IWineD3DDeviceImpl_SetTexture,
6636 IWineD3DDeviceImpl_GetTexture,
6637 IWineD3DDeviceImpl_SetTextureStageState,
6638 IWineD3DDeviceImpl_GetTextureStageState,
6639 IWineD3DDeviceImpl_SetTransform,
6640 IWineD3DDeviceImpl_GetTransform,
6641 IWineD3DDeviceImpl_SetVertexDeclaration,
6642 IWineD3DDeviceImpl_GetVertexDeclaration,
6643 IWineD3DDeviceImpl_SetVertexShader,
6644 IWineD3DDeviceImpl_GetVertexShader,
6645 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6646 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6647 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6648 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6649 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6650 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6651 IWineD3DDeviceImpl_SetViewport,
6652 IWineD3DDeviceImpl_GetViewport,
6653 IWineD3DDeviceImpl_MultiplyTransform,
6654 IWineD3DDeviceImpl_ValidateDevice,
6655 IWineD3DDeviceImpl_ProcessVertices,
6656 /*** State block ***/
6657 IWineD3DDeviceImpl_BeginStateBlock,
6658 IWineD3DDeviceImpl_EndStateBlock,
6659 /*** Scene management ***/
6660 IWineD3DDeviceImpl_BeginScene,
6661 IWineD3DDeviceImpl_EndScene,
6662 IWineD3DDeviceImpl_Present,
6663 IWineD3DDeviceImpl_Clear,
6664 /*** Drawing ***/
6665 IWineD3DDeviceImpl_DrawPrimitive,
6666 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6667 IWineD3DDeviceImpl_DrawPrimitiveUP,
6668 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6669 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6670 IWineD3DDeviceImpl_DrawRectPatch,
6671 IWineD3DDeviceImpl_DrawTriPatch,
6672 IWineD3DDeviceImpl_DeletePatch,
6673 IWineD3DDeviceImpl_ColorFill,
6674 IWineD3DDeviceImpl_UpdateTexture,
6675 IWineD3DDeviceImpl_UpdateSurface,
6676 IWineD3DDeviceImpl_GetFrontBufferData,
6677 /*** object tracking ***/
6678 IWineD3DDeviceImpl_ResourceReleased
6682 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6683 WINED3DRS_ALPHABLENDENABLE ,
6684 WINED3DRS_ALPHAFUNC ,
6685 WINED3DRS_ALPHAREF ,
6686 WINED3DRS_ALPHATESTENABLE ,
6687 WINED3DRS_BLENDOP ,
6688 WINED3DRS_COLORWRITEENABLE ,
6689 WINED3DRS_DESTBLEND ,
6690 WINED3DRS_DITHERENABLE ,
6691 WINED3DRS_FILLMODE ,
6692 WINED3DRS_FOGDENSITY ,
6693 WINED3DRS_FOGEND ,
6694 WINED3DRS_FOGSTART ,
6695 WINED3DRS_LASTPIXEL ,
6696 WINED3DRS_SHADEMODE ,
6697 WINED3DRS_SRCBLEND ,
6698 WINED3DRS_STENCILENABLE ,
6699 WINED3DRS_STENCILFAIL ,
6700 WINED3DRS_STENCILFUNC ,
6701 WINED3DRS_STENCILMASK ,
6702 WINED3DRS_STENCILPASS ,
6703 WINED3DRS_STENCILREF ,
6704 WINED3DRS_STENCILWRITEMASK ,
6705 WINED3DRS_STENCILZFAIL ,
6706 WINED3DRS_TEXTUREFACTOR ,
6707 WINED3DRS_WRAP0 ,
6708 WINED3DRS_WRAP1 ,
6709 WINED3DRS_WRAP2 ,
6710 WINED3DRS_WRAP3 ,
6711 WINED3DRS_WRAP4 ,
6712 WINED3DRS_WRAP5 ,
6713 WINED3DRS_WRAP6 ,
6714 WINED3DRS_WRAP7 ,
6715 WINED3DRS_ZENABLE ,
6716 WINED3DRS_ZFUNC ,
6717 WINED3DRS_ZWRITEENABLE
6720 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6721 WINED3DTSS_ADDRESSW ,
6722 WINED3DTSS_ALPHAARG0 ,
6723 WINED3DTSS_ALPHAARG1 ,
6724 WINED3DTSS_ALPHAARG2 ,
6725 WINED3DTSS_ALPHAOP ,
6726 WINED3DTSS_BUMPENVLOFFSET ,
6727 WINED3DTSS_BUMPENVLSCALE ,
6728 WINED3DTSS_BUMPENVMAT00 ,
6729 WINED3DTSS_BUMPENVMAT01 ,
6730 WINED3DTSS_BUMPENVMAT10 ,
6731 WINED3DTSS_BUMPENVMAT11 ,
6732 WINED3DTSS_COLORARG0 ,
6733 WINED3DTSS_COLORARG1 ,
6734 WINED3DTSS_COLORARG2 ,
6735 WINED3DTSS_COLOROP ,
6736 WINED3DTSS_RESULTARG ,
6737 WINED3DTSS_TEXCOORDINDEX ,
6738 WINED3DTSS_TEXTURETRANSFORMFLAGS
6741 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6742 WINED3DSAMP_ADDRESSU ,
6743 WINED3DSAMP_ADDRESSV ,
6744 WINED3DSAMP_ADDRESSW ,
6745 WINED3DSAMP_BORDERCOLOR ,
6746 WINED3DSAMP_MAGFILTER ,
6747 WINED3DSAMP_MINFILTER ,
6748 WINED3DSAMP_MIPFILTER ,
6749 WINED3DSAMP_MIPMAPLODBIAS ,
6750 WINED3DSAMP_MAXMIPLEVEL ,
6751 WINED3DSAMP_MAXANISOTROPY ,
6752 WINED3DSAMP_SRGBTEXTURE ,
6753 WINED3DSAMP_ELEMENTINDEX
6756 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6757 WINED3DRS_AMBIENT ,
6758 WINED3DRS_AMBIENTMATERIALSOURCE ,
6759 WINED3DRS_CLIPPING ,
6760 WINED3DRS_CLIPPLANEENABLE ,
6761 WINED3DRS_COLORVERTEX ,
6762 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6763 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6764 WINED3DRS_FOGDENSITY ,
6765 WINED3DRS_FOGEND ,
6766 WINED3DRS_FOGSTART ,
6767 WINED3DRS_FOGTABLEMODE ,
6768 WINED3DRS_FOGVERTEXMODE ,
6769 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6770 WINED3DRS_LIGHTING ,
6771 WINED3DRS_LOCALVIEWER ,
6772 WINED3DRS_MULTISAMPLEANTIALIAS ,
6773 WINED3DRS_MULTISAMPLEMASK ,
6774 WINED3DRS_NORMALIZENORMALS ,
6775 WINED3DRS_PATCHEDGESTYLE ,
6776 WINED3DRS_POINTSCALE_A ,
6777 WINED3DRS_POINTSCALE_B ,
6778 WINED3DRS_POINTSCALE_C ,
6779 WINED3DRS_POINTSCALEENABLE ,
6780 WINED3DRS_POINTSIZE ,
6781 WINED3DRS_POINTSIZE_MAX ,
6782 WINED3DRS_POINTSIZE_MIN ,
6783 WINED3DRS_POINTSPRITEENABLE ,
6784 WINED3DRS_RANGEFOGENABLE ,
6785 WINED3DRS_SPECULARMATERIALSOURCE ,
6786 WINED3DRS_TWEENFACTOR ,
6787 WINED3DRS_VERTEXBLEND
6790 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6791 WINED3DTSS_TEXCOORDINDEX ,
6792 WINED3DTSS_TEXTURETRANSFORMFLAGS
6795 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6796 WINED3DSAMP_DMAPOFFSET
6799 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6800 DWORD rep = StateTable[state].representative;
6801 DWORD idx;
6802 BYTE shift;
6803 UINT i;
6804 WineD3DContext *context;
6806 if(!rep) return;
6807 for(i = 0; i < This->numContexts; i++) {
6808 context = This->contexts[i];
6809 if(isStateDirty(context, rep)) continue;
6811 context->dirtyArray[context->numDirtyEntries++] = rep;
6812 idx = rep >> 5;
6813 shift = rep & 0x1f;
6814 context->isStateDirty[idx] |= (1 << shift);