wined3d: Split of the mapping of fixed function samplers from IWineD3DDeviceImpl_Find...
[wine/dibdrv.git] / dlls / wined3d / device.c
blobdc5343bbe4a1465054c9e19db63438cef7cffaff
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 static inline Display *get_display( HDC hdc )
66 Display *display;
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
71 return display;
74 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
77 /* helper macros */
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
86 object->ref = 1; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
95 object->ref = 1; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
141 _basetexture.is_srgb = FALSE; \
142 _basetexture.srgb_mode_change_count = 0; \
145 /**********************************************************
146 * Global variable / Constants follow
147 **********************************************************/
148 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
150 /**********************************************************
151 * IUnknown parts follows
152 **********************************************************/
154 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
158 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
159 if (IsEqualGUID(riid, &IID_IUnknown)
160 || IsEqualGUID(riid, &IID_IWineD3DBase)
161 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
162 IUnknown_AddRef(iface);
163 *ppobj = This;
164 return S_OK;
166 *ppobj = NULL;
167 return E_NOINTERFACE;
170 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
172 ULONG refCount = InterlockedIncrement(&This->ref);
174 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
175 return refCount;
178 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
180 ULONG refCount = InterlockedDecrement(&This->ref);
182 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
184 if (!refCount) {
185 if (This->fbo) {
186 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
188 if (This->src_fbo) {
189 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
191 if (This->dst_fbo) {
192 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
195 HeapFree(GetProcessHeap(), 0, This->render_targets);
196 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
197 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
199 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
201 /* TODO: Clean up all the surfaces and textures! */
202 /* NOTE: You must release the parent if the object was created via a callback
203 ** ***************************/
205 /* Release the update stateblock */
206 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
207 if(This->updateStateBlock != This->stateBlock)
208 FIXME("(%p) Something's still holding the Update stateblock\n",This);
210 This->updateStateBlock = NULL;
211 { /* because were not doing proper internal refcounts releasing the primary state block
212 causes recursion with the extra checks in ResourceReleased, to avoid this we have
213 to set this->stateBlock = NULL; first */
214 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
215 This->stateBlock = NULL;
217 /* Release the stateblock */
218 if(IWineD3DStateBlock_Release(stateBlock) > 0){
219 FIXME("(%p) Something's still holding the Update stateblock\n",This);
223 if (This->resources != NULL ) {
224 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
225 dumpResources(This->resources);
228 if(This->contexts) ERR("Context array not freed!\n");
229 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
230 This->haveHardwareCursor = FALSE;
232 IWineD3D_Release(This->wineD3D);
233 This->wineD3D = NULL;
234 HeapFree(GetProcessHeap(), 0, This);
235 TRACE("Freed device %p\n", This);
236 This = NULL;
238 return refCount;
241 /**********************************************************
242 * IWineD3DDevice implementation follows
243 **********************************************************/
244 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
246 *pParent = This->parent;
247 IUnknown_AddRef(This->parent);
248 return WINED3D_OK;
251 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
252 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
253 GLenum error, glUsage;
254 DWORD vboUsage = object->resource.usage;
255 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
256 WARN("Creating a vbo failed once, not trying again\n");
257 return;
260 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
262 ENTER_GL();
263 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
264 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
266 /* Make sure that the gl error is cleared. Do not use checkGLcall
267 * here because checkGLcall just prints a fixme and continues. However,
268 * if an error during VBO creation occurs we can fall back to non-vbo operation
269 * with full functionality(but performance loss)
271 while(glGetError() != GL_NO_ERROR);
273 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
274 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
275 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
276 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
277 * to check if the rhw and color values are in the correct format.
280 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
281 error = glGetError();
282 if(object->vbo == 0 || error != GL_NO_ERROR) {
283 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
284 goto error;
287 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
288 error = glGetError();
289 if(error != GL_NO_ERROR) {
290 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
291 goto error;
294 /* Don't use static, because dx apps tend to update the buffer
295 * quite often even if they specify 0 usage. Because we always keep the local copy
296 * we never read from the vbo and can create a write only opengl buffer.
298 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
299 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
300 case WINED3DUSAGE_DYNAMIC:
301 TRACE("Gl usage = GL_STREAM_DRAW\n");
302 glUsage = GL_STREAM_DRAW_ARB;
303 break;
304 case WINED3DUSAGE_WRITEONLY:
305 default:
306 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
307 glUsage = GL_DYNAMIC_DRAW_ARB;
308 break;
311 /* Reserve memory for the buffer. The amount of data won't change
312 * so we are safe with calling glBufferData once with a NULL ptr and
313 * calling glBufferSubData on updates
315 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
316 error = glGetError();
317 if(error != GL_NO_ERROR) {
318 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
319 goto error;
322 LEAVE_GL();
324 return;
325 error:
326 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
327 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
328 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
329 object->vbo = 0;
330 object->Flags |= VBFLAG_VBOCREATEFAIL;
331 LEAVE_GL();
332 return;
335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
336 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
337 IUnknown *parent) {
338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
339 IWineD3DVertexBufferImpl *object;
340 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
341 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
342 BOOL conv;
344 if(Size == 0) {
345 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
346 *ppVertexBuffer = NULL;
347 return WINED3DERR_INVALIDCALL;
350 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
352 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
353 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
355 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
356 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
358 object->fvf = FVF;
360 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
361 * drawStridedFast (half-life 2).
363 * Basically converting the vertices in the buffer is quite expensive, and observations
364 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
365 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
367 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
368 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
369 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
370 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
371 * dx7 apps.
372 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
373 * more. In this call we can convert dx7 buffers too.
375 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
376 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
377 (dxVersion > 7 || !conv) ) {
378 CreateVBO(object);
380 return WINED3D_OK;
383 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
384 GLenum error, glUsage;
385 TRACE("Creating VBO for Index Buffer %p\n", object);
387 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
388 * restored on the next draw
390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
392 ENTER_GL();
393 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
394 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
396 while(glGetError());
398 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
399 error = glGetError();
400 if(error != GL_NO_ERROR || object->vbo == 0) {
401 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
402 goto out;
405 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
406 error = glGetError();
407 if(error != GL_NO_ERROR) {
408 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
409 goto out;
412 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
413 * copy no readback will be needed
415 glUsage = GL_STATIC_DRAW_ARB;
416 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
417 error = glGetError();
418 if(error != GL_NO_ERROR) {
419 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
420 goto out;
422 LEAVE_GL();
423 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
424 return;
426 out:
427 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
428 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
429 LEAVE_GL();
430 object->vbo = 0;
433 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
434 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
435 HANDLE *sharedHandle, IUnknown *parent) {
436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
437 IWineD3DIndexBufferImpl *object;
438 TRACE("(%p) Creating index buffer\n", This);
440 /* Allocate the storage for the device */
441 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
443 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
444 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
447 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
448 CreateIndexBufferVBO(This, object);
451 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
452 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
453 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
455 return WINED3D_OK;
458 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
461 IWineD3DStateBlockImpl *object;
462 int i, j;
463 HRESULT temp_result;
465 D3DCREATEOBJECTINSTANCE(object, StateBlock)
466 object->blockType = Type;
468 for(i = 0; i < LIGHTMAP_SIZE; i++) {
469 list_init(&object->lightMap[i]);
472 /* Special case - Used during initialization to produce a placeholder stateblock
473 so other functions called can update a state block */
474 if (Type == WINED3DSBT_INIT) {
475 /* Don't bother increasing the reference count otherwise a device will never
476 be freed due to circular dependencies */
477 return WINED3D_OK;
480 temp_result = allocate_shader_constants(object);
481 if (WINED3D_OK != temp_result)
482 return temp_result;
484 /* Otherwise, might as well set the whole state block to the appropriate values */
485 if (This->stateBlock != NULL)
486 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
487 else
488 memset(object->streamFreq, 1, sizeof(object->streamFreq));
490 /* Reset the ref and type after kludging it */
491 object->wineD3DDevice = This;
492 object->ref = 1;
493 object->blockType = Type;
495 TRACE("Updating changed flags appropriate for type %d\n", Type);
497 if (Type == WINED3DSBT_ALL) {
499 TRACE("ALL => Pretend everything has changed\n");
500 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
502 /* Lights are not part of the changed / set structure */
503 for(j = 0; j < LIGHTMAP_SIZE; j++) {
504 struct list *e;
505 LIST_FOR_EACH(e, &object->lightMap[j]) {
506 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
507 light->changed = TRUE;
508 light->enabledChanged = TRUE;
511 } else if (Type == WINED3DSBT_PIXELSTATE) {
513 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
514 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
516 object->changed.pixelShader = TRUE;
518 /* Pixel Shader Constants */
519 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
520 object->changed.pixelShaderConstantsF[i] = TRUE;
521 for (i = 0; i < MAX_CONST_B; ++i)
522 object->changed.pixelShaderConstantsB[i] = TRUE;
523 for (i = 0; i < MAX_CONST_I; ++i)
524 object->changed.pixelShaderConstantsI[i] = TRUE;
526 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
527 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
529 for (j = 0; j < MAX_TEXTURES; j++) {
530 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
531 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
534 for (j = 0 ; j < 16; j++) {
535 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
537 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
541 } else if (Type == WINED3DSBT_VERTEXSTATE) {
543 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
544 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
546 object->changed.vertexShader = TRUE;
548 /* Vertex Shader Constants */
549 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
550 object->changed.vertexShaderConstantsF[i] = TRUE;
551 for (i = 0; i < MAX_CONST_B; ++i)
552 object->changed.vertexShaderConstantsB[i] = TRUE;
553 for (i = 0; i < MAX_CONST_I; ++i)
554 object->changed.vertexShaderConstantsI[i] = TRUE;
556 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
557 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
559 for (j = 0; j < MAX_TEXTURES; j++) {
560 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
561 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
564 for (j = 0 ; j < 16; j++){
565 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
566 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
570 for(j = 0; j < LIGHTMAP_SIZE; j++) {
571 struct list *e;
572 LIST_FOR_EACH(e, &object->lightMap[j]) {
573 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
574 light->changed = TRUE;
575 light->enabledChanged = TRUE;
578 } else {
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
583 return WINED3D_OK;
586 /* ************************************
587 MSDN:
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
590 Discard
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 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) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int pow2Width, pow2Height;
601 unsigned int Size = 1;
602 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
603 TRACE("(%p) Create surface\n",This);
605 /** FIXME: Check ranges on the inputs are valid
606 * MSDN
607 * MultisampleQuality
608 * [in] Quality level. The valid range is between zero and one less than the level
609 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
610 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
611 * values of paired render targets, depth stencil surfaces, and the MultiSample type
612 * must all match.
613 *******************************/
617 * TODO: Discard MSDN
618 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
620 * If this flag is set, the contents of the depth stencil buffer will be
621 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
622 * with a different depth surface.
624 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
625 ***************************/
627 if(MultisampleQuality < 0) {
628 FIXME("Invalid multisample level %d\n", MultisampleQuality);
629 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
632 if(MultisampleQuality > 0) {
633 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
634 MultisampleQuality=0;
637 /** FIXME: Check that the format is supported
638 * by the device.
639 *******************************/
641 /* Non-power2 support */
642 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
643 pow2Width = Width;
644 pow2Height = Height;
645 } else {
646 /* Find the nearest pow2 match */
647 pow2Width = pow2Height = 1;
648 while (pow2Width < Width) pow2Width <<= 1;
649 while (pow2Height < Height) pow2Height <<= 1;
652 if (pow2Width > Width || pow2Height > Height) {
653 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
654 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
655 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
656 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
657 This, Width, Height);
658 return WINED3DERR_NOTAVAILABLE;
662 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
663 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
664 * space!
665 *********************************/
666 if (WINED3DFMT_UNKNOWN == Format) {
667 Size = 0;
668 } else if (Format == WINED3DFMT_DXT1) {
669 /* DXT1 is half byte per pixel */
670 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
672 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
673 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
674 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
675 } else {
676 /* The pitch is a multiple of 4 bytes */
677 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
678 Size *= Height;
681 /** Create and initialise the surface resource **/
682 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
683 /* "Standalone" surface */
684 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
686 object->currentDesc.Width = Width;
687 object->currentDesc.Height = Height;
688 object->currentDesc.MultiSampleType = MultiSample;
689 object->currentDesc.MultiSampleQuality = MultisampleQuality;
691 /* Setup some glformat defaults */
692 object->glDescription.glFormat = tableEntry->glFormat;
693 object->glDescription.glFormatInternal = tableEntry->glInternal;
694 object->glDescription.glType = tableEntry->glType;
696 object->glDescription.textureName = 0;
697 object->glDescription.level = Level;
698 object->glDescription.target = GL_TEXTURE_2D;
700 /* Internal data */
701 object->pow2Width = pow2Width;
702 object->pow2Height = pow2Height;
704 /* Flags */
705 object->Flags = 0;
706 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
707 object->Flags |= Discard ? SFLAG_DISCARD : 0;
708 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
709 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
712 if (WINED3DFMT_UNKNOWN != Format) {
713 object->bytesPerPixel = tableEntry->bpp;
714 } else {
715 object->bytesPerPixel = 0;
718 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
720 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
722 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
723 * this function is too deep to need to care about things like this.
724 * Levels need to be checked too, and possibly Type since they all affect what can be done.
725 * ****************************************/
726 switch(Pool) {
727 case WINED3DPOOL_SCRATCH:
728 if(!Lockable)
729 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
730 "which are mutually exclusive, setting lockable to TRUE\n");
731 Lockable = TRUE;
732 break;
733 case WINED3DPOOL_SYSTEMMEM:
734 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
735 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
736 case WINED3DPOOL_MANAGED:
737 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
738 "Usage of DYNAMIC which are mutually exclusive, not doing "
739 "anything just telling you.\n");
740 break;
741 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
742 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
743 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
744 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
745 break;
746 default:
747 FIXME("(%p) Unknown pool %d\n", This, Pool);
748 break;
751 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
752 FIXME("Trying to create a render target that isn't in the default pool\n");
755 /* mark the texture as dirty so that it gets loaded first time around*/
756 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
757 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
758 This, Width, Height, Format, debug_d3dformat(Format),
759 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
761 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
762 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
763 This->ddraw_primary = (IWineD3DSurface *) object;
765 /* Look at the implementation and set the correct Vtable */
766 switch(Impl) {
767 case SURFACE_OPENGL:
768 /* Nothing to do, it's set already */
769 break;
771 case SURFACE_GDI:
772 object->lpVtbl = &IWineGDISurface_Vtbl;
773 break;
775 default:
776 /* To be sure to catch this */
777 ERR("Unknown requested surface implementation %d!\n", Impl);
778 IWineD3DSurface_Release((IWineD3DSurface *) object);
779 return WINED3DERR_INVALIDCALL;
782 list_init(&object->renderbuffers);
784 /* Call the private setup routine */
785 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
789 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
790 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
791 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
792 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
795 IWineD3DTextureImpl *object;
796 unsigned int i;
797 UINT tmpW;
798 UINT tmpH;
799 HRESULT hr;
800 unsigned int pow2Width;
801 unsigned int pow2Height;
804 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
805 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
806 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
808 /* TODO: It should only be possible to create textures for formats
809 that are reported as supported */
810 if (WINED3DFMT_UNKNOWN >= Format) {
811 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
812 return WINED3DERR_INVALIDCALL;
815 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
816 D3DINITIALIZEBASETEXTURE(object->baseTexture);
817 object->width = Width;
818 object->height = Height;
820 /** Non-power2 support **/
821 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
822 pow2Width = Width;
823 pow2Height = Height;
824 } else {
825 /* Find the nearest pow2 match */
826 pow2Width = pow2Height = 1;
827 while (pow2Width < Width) pow2Width <<= 1;
828 while (pow2Height < Height) pow2Height <<= 1;
831 /** FIXME: add support for real non-power-two if it's provided by the video card **/
832 /* Precalculated scaling for 'faked' non power of two texture coords */
833 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
834 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
835 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
837 /* Calculate levels for mip mapping */
838 if (Levels == 0) {
839 TRACE("calculating levels %d\n", object->baseTexture.levels);
840 object->baseTexture.levels++;
841 tmpW = Width;
842 tmpH = Height;
843 while (tmpW > 1 || tmpH > 1) {
844 tmpW = max(1, tmpW >> 1);
845 tmpH = max(1, tmpH >> 1);
846 object->baseTexture.levels++;
848 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
851 /* Generate all the surfaces */
852 tmpW = Width;
853 tmpH = Height;
854 for (i = 0; i < object->baseTexture.levels; i++)
856 /* use the callback to create the texture surface */
857 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
858 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
859 FIXME("Failed to create surface %p\n", object);
860 /* clean up */
861 object->surfaces[i] = NULL;
862 IWineD3DTexture_Release((IWineD3DTexture *)object);
864 *ppTexture = NULL;
865 return hr;
868 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
869 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
870 /* calculate the next mipmap level */
871 tmpW = max(1, tmpW >> 1);
872 tmpH = max(1, tmpH >> 1);
875 TRACE("(%p) : Created texture %p\n", This, object);
876 return WINED3D_OK;
879 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
880 UINT Width, UINT Height, UINT Depth,
881 UINT Levels, DWORD Usage,
882 WINED3DFORMAT Format, WINED3DPOOL Pool,
883 IWineD3DVolumeTexture **ppVolumeTexture,
884 HANDLE *pSharedHandle, IUnknown *parent,
885 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
888 IWineD3DVolumeTextureImpl *object;
889 unsigned int i;
890 UINT tmpW;
891 UINT tmpH;
892 UINT tmpD;
894 /* TODO: It should only be possible to create textures for formats
895 that are reported as supported */
896 if (WINED3DFMT_UNKNOWN >= Format) {
897 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
898 return WINED3DERR_INVALIDCALL;
901 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
902 D3DINITIALIZEBASETEXTURE(object->baseTexture);
904 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
905 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
907 object->width = Width;
908 object->height = Height;
909 object->depth = Depth;
911 /* Calculate levels for mip mapping */
912 if (Levels == 0) {
913 object->baseTexture.levels++;
914 tmpW = Width;
915 tmpH = Height;
916 tmpD = Depth;
917 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
918 tmpW = max(1, tmpW >> 1);
919 tmpH = max(1, tmpH >> 1);
920 tmpD = max(1, tmpD >> 1);
921 object->baseTexture.levels++;
923 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
926 /* Generate all the surfaces */
927 tmpW = Width;
928 tmpH = Height;
929 tmpD = Depth;
931 for (i = 0; i < object->baseTexture.levels; i++)
933 HRESULT hr;
934 /* Create the volume */
935 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
936 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
938 if(FAILED(hr)) {
939 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
940 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
941 *ppVolumeTexture = NULL;
942 return hr;
945 /* Set its container to this object */
946 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
948 /* calcualte the next mipmap level */
949 tmpW = max(1, tmpW >> 1);
950 tmpH = max(1, tmpH >> 1);
951 tmpD = max(1, tmpD >> 1);
954 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
955 TRACE("(%p) : Created volume texture %p\n", This, object);
956 return WINED3D_OK;
959 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
960 UINT Width, UINT Height, UINT Depth,
961 DWORD Usage,
962 WINED3DFORMAT Format, WINED3DPOOL Pool,
963 IWineD3DVolume** ppVolume,
964 HANDLE* pSharedHandle, IUnknown *parent) {
966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
967 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
968 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
970 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
972 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
973 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
975 object->currentDesc.Width = Width;
976 object->currentDesc.Height = Height;
977 object->currentDesc.Depth = Depth;
978 object->bytesPerPixel = formatDesc->bpp;
980 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
981 object->lockable = TRUE;
982 object->locked = FALSE;
983 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
984 object->dirty = TRUE;
986 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
989 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
990 UINT Levels, DWORD Usage,
991 WINED3DFORMAT Format, WINED3DPOOL Pool,
992 IWineD3DCubeTexture **ppCubeTexture,
993 HANDLE *pSharedHandle, IUnknown *parent,
994 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
997 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
998 unsigned int i, j;
999 UINT tmpW;
1000 HRESULT hr;
1001 unsigned int pow2EdgeLength = EdgeLength;
1003 /* TODO: It should only be possible to create textures for formats
1004 that are reported as supported */
1005 if (WINED3DFMT_UNKNOWN >= Format) {
1006 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1007 return WINED3DERR_INVALIDCALL;
1010 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1011 WARN("(%p) : Tried to create not supported cube texture\n", This);
1012 return WINED3DERR_INVALIDCALL;
1015 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1016 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1018 TRACE("(%p) Create Cube Texture\n", This);
1020 /** Non-power2 support **/
1022 /* Find the nearest pow2 match */
1023 pow2EdgeLength = 1;
1024 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1026 object->edgeLength = EdgeLength;
1027 /* TODO: support for native non-power 2 */
1028 /* Precalculated scaling for 'faked' non power of two texture coords */
1029 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1031 /* Calculate levels for mip mapping */
1032 if (Levels == 0) {
1033 object->baseTexture.levels++;
1034 tmpW = EdgeLength;
1035 while (tmpW > 1) {
1036 tmpW = max(1, tmpW >> 1);
1037 object->baseTexture.levels++;
1039 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1042 /* Generate all the surfaces */
1043 tmpW = EdgeLength;
1044 for (i = 0; i < object->baseTexture.levels; i++) {
1046 /* Create the 6 faces */
1047 for (j = 0; j < 6; j++) {
1049 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1050 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1052 if(hr!= WINED3D_OK) {
1053 /* clean up */
1054 int k;
1055 int l;
1056 for (l = 0; l < j; l++) {
1057 IWineD3DSurface_Release(object->surfaces[j][i]);
1059 for (k = 0; k < i; k++) {
1060 for (l = 0; l < 6; l++) {
1061 IWineD3DSurface_Release(object->surfaces[l][j]);
1065 FIXME("(%p) Failed to create surface\n",object);
1066 HeapFree(GetProcessHeap(),0,object);
1067 *ppCubeTexture = NULL;
1068 return hr;
1070 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1071 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1073 tmpW = max(1, tmpW >> 1);
1076 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1077 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1078 return WINED3D_OK;
1081 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1083 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1084 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1086 /* Just a check to see if we support this type of query */
1087 switch(Type) {
1088 case WINED3DQUERYTYPE_OCCLUSION:
1089 TRACE("(%p) occlusion query\n", This);
1090 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1091 hr = WINED3D_OK;
1092 else
1093 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1094 break;
1096 case WINED3DQUERYTYPE_EVENT:
1097 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1098 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1099 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1101 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1103 hr = WINED3D_OK;
1104 break;
1106 case WINED3DQUERYTYPE_VCACHE:
1107 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1108 case WINED3DQUERYTYPE_VERTEXSTATS:
1109 case WINED3DQUERYTYPE_TIMESTAMP:
1110 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1111 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1112 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1113 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1114 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1115 case WINED3DQUERYTYPE_PIXELTIMINGS:
1116 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1117 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1118 default:
1119 FIXME("(%p) Unhandled query type %d\n", This, Type);
1121 if(NULL == ppQuery || hr != WINED3D_OK) {
1122 return hr;
1125 D3DCREATEOBJECTINSTANCE(object, Query)
1126 object->type = Type;
1127 /* allocated the 'extended' data based on the type of query requested */
1128 switch(Type){
1129 case WINED3DQUERYTYPE_OCCLUSION:
1130 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1131 TRACE("(%p) Allocating data for an occlusion query\n", This);
1132 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1133 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1134 break;
1136 case WINED3DQUERYTYPE_EVENT:
1137 /* TODO: GL_APPLE_fence */
1138 if(GL_SUPPORT(APPLE_FENCE)) {
1139 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1140 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1141 checkGLcall("glGenFencesAPPLE");
1142 } else if(GL_SUPPORT(NV_FENCE)) {
1143 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1144 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1145 checkGLcall("glGenFencesNV");
1147 break;
1149 case WINED3DQUERYTYPE_VCACHE:
1150 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1151 case WINED3DQUERYTYPE_VERTEXSTATS:
1152 case WINED3DQUERYTYPE_TIMESTAMP:
1153 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1154 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1155 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1156 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1157 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1158 case WINED3DQUERYTYPE_PIXELTIMINGS:
1159 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1160 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1161 default:
1162 object->extendedData = 0;
1163 FIXME("(%p) Unhandled query type %d\n",This , Type);
1165 TRACE("(%p) : Created Query %p\n", This, object);
1166 return WINED3D_OK;
1169 /*****************************************************************************
1170 * IWineD3DDeviceImpl_SetupFullscreenWindow
1172 * Helper function that modifies a HWND's Style and ExStyle for proper
1173 * fullscreen use.
1175 * Params:
1176 * iface: Pointer to the IWineD3DDevice interface
1177 * window: Window to setup
1179 *****************************************************************************/
1180 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1183 LONG style, exStyle;
1184 /* Don't do anything if an original style is stored.
1185 * That shouldn't happen
1187 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1188 if (This->style || This->exStyle) {
1189 ERR("(%p): Want to change the window parameters of HWND %p, but "
1190 "another style is stored for restoration afterwards\n", This, window);
1193 /* Get the parameters and save them */
1194 style = GetWindowLongW(window, GWL_STYLE);
1195 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1196 This->style = style;
1197 This->exStyle = exStyle;
1199 /* Filter out window decorations */
1200 style &= ~WS_CAPTION;
1201 style &= ~WS_THICKFRAME;
1202 exStyle &= ~WS_EX_WINDOWEDGE;
1203 exStyle &= ~WS_EX_CLIENTEDGE;
1205 /* Make sure the window is managed, otherwise we won't get keyboard input */
1206 style |= WS_POPUP | WS_SYSMENU;
1208 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1209 This->style, This->exStyle, style, exStyle);
1211 SetWindowLongW(window, GWL_STYLE, style);
1212 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1214 /* Inform the window about the update. */
1215 SetWindowPos(window, HWND_TOP, 0, 0,
1216 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1217 ShowWindow(window, SW_NORMAL);
1220 /*****************************************************************************
1221 * IWineD3DDeviceImpl_RestoreWindow
1223 * Helper function that restores a windows' properties when taking it out
1224 * of fullscreen mode
1226 * Params:
1227 * iface: Pointer to the IWineD3DDevice interface
1228 * window: Window to setup
1230 *****************************************************************************/
1231 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1234 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1235 * switch, do nothing
1237 if (!This->style && !This->exStyle) return;
1239 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1240 This, window, This->style, This->exStyle);
1242 SetWindowLongW(window, GWL_STYLE, This->style);
1243 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1245 /* Delete the old values */
1246 This->style = 0;
1247 This->exStyle = 0;
1249 /* Inform the window about the update */
1250 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1251 0, 0, 0, 0, /* Pos, Size, ignored */
1252 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1255 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1256 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1257 IUnknown* parent,
1258 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1259 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1262 HDC hDc;
1263 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1264 HRESULT hr = WINED3D_OK;
1265 IUnknown *bufferParent;
1266 Display *display;
1268 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1270 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1271 * does a device hold a reference to a swap chain giving them a lifetime of the device
1272 * or does the swap chain notify the device of its destruction.
1273 *******************************/
1275 /* Check the params */
1276 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1277 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1278 return WINED3DERR_INVALIDCALL;
1279 } else if (pPresentationParameters->BackBufferCount > 1) {
1280 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");
1283 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1285 /*********************
1286 * Lookup the window Handle and the relating X window handle
1287 ********************/
1289 /* Setup hwnd we are using, plus which display this equates to */
1290 object->win_handle = pPresentationParameters->hDeviceWindow;
1291 if (!object->win_handle) {
1292 object->win_handle = This->createParms.hFocusWindow;
1295 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1296 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1297 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1298 return WINED3DERR_NOTAVAILABLE;
1300 hDc = GetDC(object->win_handle);
1301 display = get_display(hDc);
1302 ReleaseDC(object->win_handle, hDc);
1303 TRACE("Using a display of %p %p\n", display, hDc);
1305 if (NULL == display || NULL == hDc) {
1306 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1307 return WINED3DERR_NOTAVAILABLE;
1310 if (object->win == 0) {
1311 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1312 return WINED3DERR_NOTAVAILABLE;
1315 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1316 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1317 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1319 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1320 * then the corresponding dimension of the client area of the hDeviceWindow
1321 * (or the focus window, if hDeviceWindow is NULL) is taken.
1322 **********************/
1324 if (pPresentationParameters->Windowed &&
1325 ((pPresentationParameters->BackBufferWidth == 0) ||
1326 (pPresentationParameters->BackBufferHeight == 0))) {
1328 RECT Rect;
1329 GetClientRect(object->win_handle, &Rect);
1331 if (pPresentationParameters->BackBufferWidth == 0) {
1332 pPresentationParameters->BackBufferWidth = Rect.right;
1333 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1335 if (pPresentationParameters->BackBufferHeight == 0) {
1336 pPresentationParameters->BackBufferHeight = Rect.bottom;
1337 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1341 /* Put the correct figures in the presentation parameters */
1342 TRACE("Copying across presentation parameters\n");
1343 object->presentParms = *pPresentationParameters;
1345 TRACE("calling rendertarget CB\n");
1346 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1347 parent,
1348 object->presentParms.BackBufferWidth,
1349 object->presentParms.BackBufferHeight,
1350 object->presentParms.BackBufferFormat,
1351 object->presentParms.MultiSampleType,
1352 object->presentParms.MultiSampleQuality,
1353 TRUE /* Lockable */,
1354 &object->frontBuffer,
1355 NULL /* pShared (always null)*/);
1356 if (object->frontBuffer != NULL) {
1357 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1358 } else {
1359 ERR("Failed to create the front buffer\n");
1360 goto error;
1364 * Create an opengl context for the display visual
1365 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1366 * use different properties after that point in time. FIXME: How to handle when requested format
1367 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1368 * it chooses is identical to the one already being used!
1369 **********************************/
1370 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1372 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1373 if(!object->context)
1374 return E_OUTOFMEMORY;
1375 object->num_contexts = 1;
1377 ENTER_GL();
1378 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1379 LEAVE_GL();
1381 if (!object->context[0]) {
1382 ERR("Failed to create a new context\n");
1383 hr = WINED3DERR_NOTAVAILABLE;
1384 goto error;
1385 } else {
1386 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1387 object->win_handle, object->context[0]->glCtx, object->win);
1390 /*********************
1391 * Windowed / Fullscreen
1392 *******************/
1395 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1396 * so we should really check to see if there is a fullscreen swapchain already
1397 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1398 **************************************/
1400 if (!pPresentationParameters->Windowed) {
1402 DEVMODEW devmode;
1403 HDC hdc;
1404 int bpp = 0;
1405 RECT clip_rc;
1407 /* Get info on the current display setup */
1408 hdc = GetDC(0);
1409 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1410 ReleaseDC(0, hdc);
1412 /* Change the display settings */
1413 memset(&devmode, 0, sizeof(DEVMODEW));
1414 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1415 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1416 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1417 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1418 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1419 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1421 /* For GetDisplayMode */
1422 This->ddraw_width = devmode.dmPelsWidth;
1423 This->ddraw_height = devmode.dmPelsHeight;
1424 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1426 IWineD3DDevice_SetFullscreen(iface, TRUE);
1428 /* And finally clip mouse to our screen */
1429 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1430 ClipCursor(&clip_rc);
1433 /*********************
1434 * Create the back, front and stencil buffers
1435 *******************/
1436 if(object->presentParms.BackBufferCount > 0) {
1437 int i;
1439 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1440 if(!object->backBuffer) {
1441 ERR("Out of memory\n");
1442 hr = E_OUTOFMEMORY;
1443 goto error;
1446 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1447 TRACE("calling rendertarget CB\n");
1448 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1449 parent,
1450 object->presentParms.BackBufferWidth,
1451 object->presentParms.BackBufferHeight,
1452 object->presentParms.BackBufferFormat,
1453 object->presentParms.MultiSampleType,
1454 object->presentParms.MultiSampleQuality,
1455 TRUE /* Lockable */,
1456 &object->backBuffer[i],
1457 NULL /* pShared (always null)*/);
1458 if(hr == WINED3D_OK && object->backBuffer[i]) {
1459 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1460 } else {
1461 ERR("Cannot create new back buffer\n");
1462 goto error;
1464 ENTER_GL();
1465 glDrawBuffer(GL_BACK);
1466 checkGLcall("glDrawBuffer(GL_BACK)");
1467 LEAVE_GL();
1469 } else {
1470 object->backBuffer = NULL;
1472 /* Single buffering - draw to front buffer */
1473 ENTER_GL();
1474 glDrawBuffer(GL_FRONT);
1475 checkGLcall("glDrawBuffer(GL_FRONT)");
1476 LEAVE_GL();
1479 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1480 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1481 TRACE("Creating depth stencil buffer\n");
1482 if (This->depthStencilBuffer == NULL ) {
1483 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1484 parent,
1485 object->presentParms.BackBufferWidth,
1486 object->presentParms.BackBufferHeight,
1487 object->presentParms.AutoDepthStencilFormat,
1488 object->presentParms.MultiSampleType,
1489 object->presentParms.MultiSampleQuality,
1490 FALSE /* FIXME: Discard */,
1491 &This->depthStencilBuffer,
1492 NULL /* pShared (always null)*/ );
1493 if (This->depthStencilBuffer != NULL)
1494 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1497 /** TODO: A check on width, height and multisample types
1498 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1499 ****************************/
1500 object->wantsDepthStencilBuffer = TRUE;
1501 } else {
1502 object->wantsDepthStencilBuffer = FALSE;
1505 TRACE("Created swapchain %p\n", object);
1506 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1507 return WINED3D_OK;
1509 error:
1510 if (object->backBuffer) {
1511 int i;
1512 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1513 if(object->backBuffer[i]) {
1514 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1515 IUnknown_Release(bufferParent); /* once for the get parent */
1516 if (IUnknown_Release(bufferParent) > 0) {
1517 FIXME("(%p) Something's still holding the back buffer\n",This);
1521 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1522 object->backBuffer = NULL;
1524 if(object->context[0])
1525 DestroyContext(This, object->context[0]);
1526 if(object->frontBuffer) {
1527 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1528 IUnknown_Release(bufferParent); /* once for the get parent */
1529 if (IUnknown_Release(bufferParent) > 0) {
1530 FIXME("(%p) Something's still holding the front buffer\n",This);
1533 HeapFree(GetProcessHeap(), 0, object);
1534 return hr;
1537 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1538 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 TRACE("(%p)\n", This);
1542 return This->NumberOfSwapChains;
1545 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1549 if(iSwapChain < This->NumberOfSwapChains) {
1550 *pSwapChain = This->swapchains[iSwapChain];
1551 IWineD3DSwapChain_AddRef(*pSwapChain);
1552 TRACE("(%p) returning %p\n", This, *pSwapChain);
1553 return WINED3D_OK;
1554 } else {
1555 TRACE("Swapchain out of range\n");
1556 *pSwapChain = NULL;
1557 return WINED3DERR_INVALIDCALL;
1561 /*****
1562 * Vertex Declaration
1563 *****/
1564 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1565 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1567 IWineD3DVertexDeclarationImpl *object = NULL;
1568 HRESULT hr = WINED3D_OK;
1570 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1571 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1573 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1575 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1577 return hr;
1580 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1582 unsigned int idx, idx2;
1583 unsigned int offset;
1584 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1585 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1586 BOOL has_blend_idx = has_blend &&
1587 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1588 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1589 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1590 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1591 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1592 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1593 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1595 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1596 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1598 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1599 WINED3DVERTEXELEMENT *elements = NULL;
1601 unsigned int size;
1602 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1603 if (has_blend_idx) num_blends--;
1605 /* Compute declaration size */
1606 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1607 has_psize + has_diffuse + has_specular + num_textures + 1;
1609 /* convert the declaration */
1610 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1611 if (!elements)
1612 return 0;
1614 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1615 idx = 0;
1616 if (has_pos) {
1617 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1618 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1619 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1621 else {
1622 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1623 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1625 elements[idx].UsageIndex = 0;
1626 idx++;
1628 if (has_blend && (num_blends > 0)) {
1629 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1630 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1631 else
1632 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1633 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1634 elements[idx].UsageIndex = 0;
1635 idx++;
1637 if (has_blend_idx) {
1638 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1639 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1640 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1641 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1642 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1643 else
1644 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1645 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1646 elements[idx].UsageIndex = 0;
1647 idx++;
1649 if (has_normal) {
1650 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1651 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1652 elements[idx].UsageIndex = 0;
1653 idx++;
1655 if (has_psize) {
1656 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1657 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1658 elements[idx].UsageIndex = 0;
1659 idx++;
1661 if (has_diffuse) {
1662 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1663 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1664 elements[idx].UsageIndex = 0;
1665 idx++;
1667 if (has_specular) {
1668 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1669 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1670 elements[idx].UsageIndex = 1;
1671 idx++;
1673 for (idx2 = 0; idx2 < num_textures; idx2++) {
1674 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1675 switch (numcoords) {
1676 case WINED3DFVF_TEXTUREFORMAT1:
1677 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1678 break;
1679 case WINED3DFVF_TEXTUREFORMAT2:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1681 break;
1682 case WINED3DFVF_TEXTUREFORMAT3:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1684 break;
1685 case WINED3DFVF_TEXTUREFORMAT4:
1686 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1687 break;
1689 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1690 elements[idx].UsageIndex = idx2;
1691 idx++;
1694 /* Now compute offsets, and initialize the rest of the fields */
1695 for (idx = 0, offset = 0; idx < size-1; idx++) {
1696 elements[idx].Stream = 0;
1697 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1698 elements[idx].Offset = offset;
1699 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1702 *ppVertexElements = elements;
1703 return size;
1706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1707 WINED3DVERTEXELEMENT* elements = NULL;
1708 size_t size;
1709 DWORD hr;
1711 size = ConvertFvfToDeclaration(Fvf, &elements);
1712 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1714 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1715 HeapFree(GetProcessHeap(), 0, elements);
1716 if (hr != S_OK) return hr;
1718 return WINED3D_OK;
1721 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1722 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1724 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1725 HRESULT hr = WINED3D_OK;
1726 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1727 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1729 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1731 if (vertex_declaration) {
1732 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1735 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1737 if (WINED3D_OK != hr) {
1738 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1739 IWineD3DVertexShader_Release(*ppVertexShader);
1740 return WINED3DERR_INVALIDCALL;
1743 return WINED3D_OK;
1746 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1748 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1749 HRESULT hr = WINED3D_OK;
1751 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1752 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1753 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1754 if (WINED3D_OK == hr) {
1755 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1756 } else {
1757 WARN("(%p) : Failed to create pixel shader\n", This);
1760 return hr;
1763 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1765 IWineD3DPaletteImpl *object;
1766 HRESULT hr;
1767 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1769 /* Create the new object */
1770 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1771 if(!object) {
1772 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1773 return E_OUTOFMEMORY;
1776 object->lpVtbl = &IWineD3DPalette_Vtbl;
1777 object->ref = 1;
1778 object->Flags = Flags;
1779 object->parent = Parent;
1780 object->wineD3DDevice = This;
1781 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1783 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1785 if(!object->hpal) {
1786 HeapFree( GetProcessHeap(), 0, object);
1787 return E_OUTOFMEMORY;
1790 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1791 if(FAILED(hr)) {
1792 IWineD3DPalette_Release((IWineD3DPalette *) object);
1793 return hr;
1796 *Palette = (IWineD3DPalette *) object;
1798 return WINED3D_OK;
1801 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1803 IWineD3DSwapChainImpl *swapchain;
1804 HRESULT hr;
1805 DWORD state;
1807 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1808 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1810 /* TODO: Test if OpenGL is compiled in and loaded */
1812 /* Initialize the texture unit mapping to a 1:1 mapping */
1813 for(state = 0; state < MAX_SAMPLERS; state++) {
1814 if (state < GL_LIMITS(samplers)) {
1815 This->texUnitMap[state] = state;
1816 This->rev_tex_unit_map[state] = state;
1817 } else {
1818 This->texUnitMap[state] = -1;
1819 This->rev_tex_unit_map[state] = -1;
1822 This->oneToOneTexUnitMap = TRUE;
1824 /* Setup the implicit swapchain */
1825 TRACE("Creating implicit swapchain\n");
1826 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1827 if (FAILED(hr) || !swapchain) {
1828 WARN("Failed to create implicit swapchain\n");
1829 return hr;
1832 This->NumberOfSwapChains = 1;
1833 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1834 if(!This->swapchains) {
1835 ERR("Out of memory!\n");
1836 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1837 return E_OUTOFMEMORY;
1839 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1841 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1843 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1844 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1845 This->render_targets[0] = swapchain->backBuffer[0];
1846 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1848 else {
1849 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1850 This->render_targets[0] = swapchain->frontBuffer;
1851 This->lastActiveRenderTarget = swapchain->frontBuffer;
1853 IWineD3DSurface_AddRef(This->render_targets[0]);
1854 This->activeContext = swapchain->context[0];
1856 /* Depth Stencil support */
1857 This->stencilBufferTarget = This->depthStencilBuffer;
1858 if (NULL != This->stencilBufferTarget) {
1859 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1862 /* Set up some starting GL setup */
1863 ENTER_GL();
1865 /* Setup all the devices defaults */
1866 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1867 #if 0
1868 IWineD3DImpl_CheckGraphicsMemory();
1869 #endif
1871 { /* Set a default viewport */
1872 WINED3DVIEWPORT vp;
1873 vp.X = 0;
1874 vp.Y = 0;
1875 vp.Width = pPresentationParameters->BackBufferWidth;
1876 vp.Height = pPresentationParameters->BackBufferHeight;
1877 vp.MinZ = 0.0f;
1878 vp.MaxZ = 1.0f;
1879 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1882 /* Initialize the current view state */
1883 This->view_ident = 1;
1884 This->contexts[0]->last_was_rhw = 0;
1885 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1886 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1888 switch(wined3d_settings.offscreen_rendering_mode) {
1889 case ORM_FBO:
1890 case ORM_PBUFFER:
1891 This->offscreenBuffer = GL_BACK;
1892 break;
1894 case ORM_BACKBUFFER:
1896 if(GL_LIMITS(aux_buffers) > 0) {
1897 TRACE("Using auxilliary buffer for offscreen rendering\n");
1898 This->offscreenBuffer = GL_AUX0;
1899 } else {
1900 TRACE("Using back buffer for offscreen rendering\n");
1901 This->offscreenBuffer = GL_BACK;
1906 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1907 LEAVE_GL();
1909 /* Clear the screen */
1910 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1911 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1912 0x00, 1.0, 0);
1914 This->d3d_initialized = TRUE;
1915 return WINED3D_OK;
1918 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1920 int sampler;
1921 uint i;
1922 TRACE("(%p)\n", This);
1924 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1926 ENTER_GL();
1927 /* I don't think that the interface guarants that the device is destroyed from the same thread
1928 * it was created. Thus make sure a context is active for the glDelete* calls
1930 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1931 LEAVE_GL();
1933 /* Delete the pbuffer context if there is any */
1934 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1936 /* Delete the mouse cursor texture */
1937 if(This->cursorTexture) {
1938 ENTER_GL();
1939 glDeleteTextures(1, &This->cursorTexture);
1940 LEAVE_GL();
1941 This->cursorTexture = 0;
1944 for (sampler = 0; sampler < MAX_SAMPLERS; ++sampler) {
1945 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1948 /* Release the buffers (with sanity checks)*/
1949 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1950 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1951 if(This->depthStencilBuffer != This->stencilBufferTarget)
1952 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1954 This->stencilBufferTarget = NULL;
1956 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1957 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1958 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1960 TRACE("Setting rendertarget to NULL\n");
1961 This->render_targets[0] = NULL;
1963 if (This->depthStencilBuffer) {
1964 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1965 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1967 This->depthStencilBuffer = NULL;
1970 for(i=0; i < This->NumberOfSwapChains; i++) {
1971 TRACE("Releasing the implicit swapchain %d\n", i);
1972 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1973 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1977 HeapFree(GetProcessHeap(), 0, This->swapchains);
1978 This->swapchains = NULL;
1979 This->NumberOfSwapChains = 0;
1981 This->d3d_initialized = FALSE;
1982 return WINED3D_OK;
1985 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1987 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1989 /* Setup the window for fullscreen mode */
1990 if(fullscreen && !This->ddraw_fullscreen) {
1991 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1992 } else if(!fullscreen && This->ddraw_fullscreen) {
1993 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1996 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1997 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1998 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1999 * separately.
2001 This->ddraw_fullscreen = fullscreen;
2004 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2005 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2006 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2008 * There is no way to deactivate thread safety once it is enabled
2010 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2012 FIXME("No thread safety in wined3d yet\n");
2014 /*For now just store the flag(needed in case of ddraw) */
2015 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2017 return;
2020 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2021 DEVMODEW devmode;
2022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2023 LONG ret;
2024 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2025 RECT clip_rc;
2027 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2029 /* Resize the screen even without a window:
2030 * The app could have unset it with SetCooperativeLevel, but not called
2031 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2032 * but we don't have any hwnd
2035 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2036 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2037 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2038 devmode.dmPelsWidth = pMode->Width;
2039 devmode.dmPelsHeight = pMode->Height;
2041 devmode.dmDisplayFrequency = pMode->RefreshRate;
2042 if (pMode->RefreshRate != 0) {
2043 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2046 /* Only change the mode if necessary */
2047 if( (This->ddraw_width == pMode->Width) &&
2048 (This->ddraw_height == pMode->Height) &&
2049 (This->ddraw_format == pMode->Format) &&
2050 (pMode->RefreshRate == 0) ) {
2051 return WINED3D_OK;
2054 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2055 if (ret != DISP_CHANGE_SUCCESSFUL) {
2056 if(devmode.dmDisplayFrequency != 0) {
2057 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2058 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2059 devmode.dmDisplayFrequency = 0;
2060 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2062 if(ret != DISP_CHANGE_SUCCESSFUL) {
2063 return WINED3DERR_NOTAVAILABLE;
2067 /* Store the new values */
2068 This->ddraw_width = pMode->Width;
2069 This->ddraw_height = pMode->Height;
2070 This->ddraw_format = pMode->Format;
2072 /* Only do this with a window of course */
2073 if(This->ddraw_window)
2074 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2076 /* And finally clip mouse to our screen */
2077 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2078 ClipCursor(&clip_rc);
2080 return WINED3D_OK;
2083 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2085 *ppD3D= This->wineD3D;
2086 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2087 IWineD3D_AddRef(*ppD3D);
2088 return WINED3D_OK;
2091 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2092 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2093 * into the video ram as possible and seeing how many fit
2094 * you can also get the correct initial value from nvidia and ATI's driver via X
2095 * texture memory is video memory + AGP memory
2096 *******************/
2097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2098 static BOOL showfixmes = TRUE;
2099 if (showfixmes) {
2100 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2101 (wined3d_settings.emulated_textureram/(1024*1024)),
2102 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2103 showfixmes = FALSE;
2105 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2106 (wined3d_settings.emulated_textureram/(1024*1024)),
2107 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2108 /* return simulated texture memory left */
2109 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2114 /*****
2115 * Get / Set FVF
2116 *****/
2117 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2120 /* Update the current state block */
2121 This->updateStateBlock->changed.fvf = TRUE;
2122 This->updateStateBlock->set.fvf = TRUE;
2124 if(This->updateStateBlock->fvf == fvf) {
2125 TRACE("Application is setting the old fvf over, nothing to do\n");
2126 return WINED3D_OK;
2129 This->updateStateBlock->fvf = fvf;
2130 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2132 return WINED3D_OK;
2136 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2138 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2139 *pfvf = This->stateBlock->fvf;
2140 return WINED3D_OK;
2143 /*****
2144 * Get / Set Stream Source
2145 *****/
2146 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2148 IWineD3DVertexBuffer *oldSrc;
2150 if (StreamNumber >= MAX_STREAMS) {
2151 WARN("Stream out of range %d\n", StreamNumber);
2152 return WINED3DERR_INVALIDCALL;
2155 oldSrc = This->stateBlock->streamSource[StreamNumber];
2156 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2158 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2159 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2161 if(oldSrc == pStreamData &&
2162 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2163 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2164 TRACE("Application is setting the old values over, nothing to do\n");
2165 return WINED3D_OK;
2168 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2169 if (pStreamData) {
2170 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2171 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2174 /* Handle recording of state blocks */
2175 if (This->isRecordingState) {
2176 TRACE("Recording... not performing anything\n");
2177 return WINED3D_OK;
2180 /* Need to do a getParent and pass the reffs up */
2181 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2182 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2183 so for now, just count internally */
2184 if (pStreamData != NULL) {
2185 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2186 InterlockedIncrement(&vbImpl->bindCount);
2188 if (oldSrc != NULL) {
2189 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2194 return WINED3D_OK;
2197 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2200 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2201 This->stateBlock->streamSource[StreamNumber],
2202 This->stateBlock->streamOffset[StreamNumber],
2203 This->stateBlock->streamStride[StreamNumber]);
2205 if (StreamNumber >= MAX_STREAMS) {
2206 WARN("Stream out of range %d\n", StreamNumber);
2207 return WINED3DERR_INVALIDCALL;
2209 *pStream = This->stateBlock->streamSource[StreamNumber];
2210 *pStride = This->stateBlock->streamStride[StreamNumber];
2211 if (pOffset) {
2212 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2215 if (*pStream != NULL) {
2216 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2218 return WINED3D_OK;
2221 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2223 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2224 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2226 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2227 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2229 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2230 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2231 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2233 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2234 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2238 return WINED3D_OK;
2241 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2244 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2245 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2247 TRACE("(%p) : returning %d\n", This, *Divider);
2249 return WINED3D_OK;
2252 /*****
2253 * Get / Set & Multiply Transform
2254 *****/
2255 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2258 /* Most of this routine, comments included copied from ddraw tree initially: */
2259 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2261 /* Handle recording of state blocks */
2262 if (This->isRecordingState) {
2263 TRACE("Recording... not performing anything\n");
2264 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2265 This->updateStateBlock->set.transform[d3dts] = TRUE;
2266 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2267 return WINED3D_OK;
2271 * If the new matrix is the same as the current one,
2272 * we cut off any further processing. this seems to be a reasonable
2273 * optimization because as was noticed, some apps (warcraft3 for example)
2274 * tend towards setting the same matrix repeatedly for some reason.
2276 * From here on we assume that the new matrix is different, wherever it matters.
2278 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2279 TRACE("The app is setting the same matrix over again\n");
2280 return WINED3D_OK;
2281 } else {
2282 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2286 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2287 where ViewMat = Camera space, WorldMat = world space.
2289 In OpenGL, camera and world space is combined into GL_MODELVIEW
2290 matrix. The Projection matrix stay projection matrix.
2293 /* Capture the times we can just ignore the change for now */
2294 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2295 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2296 /* Handled by the state manager */
2299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2300 return WINED3D_OK;
2303 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2305 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2306 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2307 return WINED3D_OK;
2310 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2311 WINED3DMATRIX *mat = NULL;
2312 WINED3DMATRIX temp;
2314 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2315 * below means it will be recorded in a state block change, but it
2316 * works regardless where it is recorded.
2317 * If this is found to be wrong, change to StateBlock.
2319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2320 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2322 if (State < HIGHEST_TRANSFORMSTATE)
2324 mat = &This->updateStateBlock->transforms[State];
2325 } else {
2326 FIXME("Unhandled transform state!!\n");
2329 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2331 /* Apply change via set transform - will reapply to eg. lights this way */
2332 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2335 /*****
2336 * Get / Set Light
2337 *****/
2338 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2339 you can reference any indexes you want as long as that number max are enabled at any
2340 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2341 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2342 but when recording, just build a chain pretty much of commands to be replayed. */
2344 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2345 float rho;
2346 PLIGHTINFOEL *object = NULL;
2347 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2348 struct list *e;
2350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2351 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2353 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2354 * the gl driver.
2356 if(!pLight) {
2357 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2358 return WINED3DERR_INVALIDCALL;
2361 switch(pLight->Type) {
2362 case WINED3DLIGHT_POINT:
2363 case WINED3DLIGHT_SPOT:
2364 case WINED3DLIGHT_PARALLELPOINT:
2365 case WINED3DLIGHT_GLSPOT:
2366 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2367 * most wanted
2369 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2370 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2371 return WINED3DERR_INVALIDCALL;
2373 break;
2375 case WINED3DLIGHT_DIRECTIONAL:
2376 /* Ignores attenuation */
2377 break;
2379 default:
2380 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2381 return WINED3DERR_INVALIDCALL;
2384 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2385 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2386 if(object->OriginalIndex == Index) break;
2387 object = NULL;
2390 if(!object) {
2391 TRACE("Adding new light\n");
2392 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2393 if(!object) {
2394 ERR("Out of memory error when allocating a light\n");
2395 return E_OUTOFMEMORY;
2397 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2398 object->glIndex = -1;
2399 object->OriginalIndex = Index;
2400 object->changed = TRUE;
2403 /* Initialize the object */
2404 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,
2405 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2406 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2407 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2408 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2409 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2410 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2412 /* Save away the information */
2413 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2415 switch (pLight->Type) {
2416 case WINED3DLIGHT_POINT:
2417 /* Position */
2418 object->lightPosn[0] = pLight->Position.x;
2419 object->lightPosn[1] = pLight->Position.y;
2420 object->lightPosn[2] = pLight->Position.z;
2421 object->lightPosn[3] = 1.0f;
2422 object->cutoff = 180.0f;
2423 /* FIXME: Range */
2424 break;
2426 case WINED3DLIGHT_DIRECTIONAL:
2427 /* Direction */
2428 object->lightPosn[0] = -pLight->Direction.x;
2429 object->lightPosn[1] = -pLight->Direction.y;
2430 object->lightPosn[2] = -pLight->Direction.z;
2431 object->lightPosn[3] = 0.0;
2432 object->exponent = 0.0f;
2433 object->cutoff = 180.0f;
2434 break;
2436 case WINED3DLIGHT_SPOT:
2437 /* Position */
2438 object->lightPosn[0] = pLight->Position.x;
2439 object->lightPosn[1] = pLight->Position.y;
2440 object->lightPosn[2] = pLight->Position.z;
2441 object->lightPosn[3] = 1.0;
2443 /* Direction */
2444 object->lightDirn[0] = pLight->Direction.x;
2445 object->lightDirn[1] = pLight->Direction.y;
2446 object->lightDirn[2] = pLight->Direction.z;
2447 object->lightDirn[3] = 1.0;
2450 * opengl-ish and d3d-ish spot lights use too different models for the
2451 * light "intensity" as a function of the angle towards the main light direction,
2452 * so we only can approximate very roughly.
2453 * however spot lights are rather rarely used in games (if ever used at all).
2454 * furthermore if still used, probably nobody pays attention to such details.
2456 if (pLight->Falloff == 0) {
2457 rho = 6.28f;
2458 } else {
2459 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2461 if (rho < 0.0001) rho = 0.0001f;
2462 object->exponent = -0.3/log(cos(rho/2));
2463 if (object->exponent > 128.0) {
2464 object->exponent = 128.0;
2466 object->cutoff = pLight->Phi*90/M_PI;
2468 /* FIXME: Range */
2469 break;
2471 default:
2472 FIXME("Unrecognized light type %d\n", pLight->Type);
2475 /* Update the live definitions if the light is currently assigned a glIndex */
2476 if (object->glIndex != -1 && !This->isRecordingState) {
2477 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2479 return WINED3D_OK;
2482 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2483 PLIGHTINFOEL *lightInfo = NULL;
2484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2485 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2486 struct list *e;
2487 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2489 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2490 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2491 if(lightInfo->OriginalIndex == Index) break;
2492 lightInfo = NULL;
2495 if (lightInfo == NULL) {
2496 TRACE("Light information requested but light not defined\n");
2497 return WINED3DERR_INVALIDCALL;
2500 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2501 return WINED3D_OK;
2504 /*****
2505 * Get / Set Light Enable
2506 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2507 *****/
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2509 PLIGHTINFOEL *lightInfo = NULL;
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2512 struct list *e;
2513 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2515 /* Tests show true = 128...not clear why */
2516 Enable = Enable? 128: 0;
2518 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2519 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2520 if(lightInfo->OriginalIndex == Index) break;
2521 lightInfo = NULL;
2523 TRACE("Found light: %p\n", lightInfo);
2525 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2526 if (lightInfo == NULL) {
2528 TRACE("Light enabled requested but light not defined, so defining one!\n");
2529 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2531 /* Search for it again! Should be fairly quick as near head of list */
2532 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2533 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2534 if(lightInfo->OriginalIndex == Index) break;
2535 lightInfo = NULL;
2537 if (lightInfo == NULL) {
2538 FIXME("Adding default lights has failed dismally\n");
2539 return WINED3DERR_INVALIDCALL;
2543 lightInfo->enabledChanged = TRUE;
2544 if(!Enable) {
2545 if(lightInfo->glIndex != -1) {
2546 if(!This->isRecordingState) {
2547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2550 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2551 lightInfo->glIndex = -1;
2552 } else {
2553 TRACE("Light already disabled, nothing to do\n");
2555 } else {
2556 if (lightInfo->glIndex != -1) {
2557 /* nop */
2558 TRACE("Nothing to do as light was enabled\n");
2559 } else {
2560 int i;
2561 /* Find a free gl light */
2562 for(i = 0; i < This->maxConcurrentLights; i++) {
2563 if(This->stateBlock->activeLights[i] == NULL) {
2564 This->stateBlock->activeLights[i] = lightInfo;
2565 lightInfo->glIndex = i;
2566 break;
2569 if(lightInfo->glIndex == -1) {
2570 ERR("Too many concurrently active lights\n");
2571 return WINED3DERR_INVALIDCALL;
2574 /* i == lightInfo->glIndex */
2575 if(!This->isRecordingState) {
2576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2581 return WINED3D_OK;
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2586 PLIGHTINFOEL *lightInfo = NULL;
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 struct list *e;
2589 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2590 TRACE("(%p) : for idx(%d)\n", This, Index);
2592 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2593 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2594 if(lightInfo->OriginalIndex == Index) break;
2595 lightInfo = NULL;
2598 if (lightInfo == NULL) {
2599 TRACE("Light enabled state requested but light not defined\n");
2600 return WINED3DERR_INVALIDCALL;
2602 /* true is 128 according to SetLightEnable */
2603 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2604 return WINED3D_OK;
2607 /*****
2608 * Get / Set Clip Planes
2609 *****/
2610 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2612 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2614 /* Validate Index */
2615 if (Index >= GL_LIMITS(clipplanes)) {
2616 TRACE("Application has requested clipplane this device doesn't support\n");
2617 return WINED3DERR_INVALIDCALL;
2620 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2621 This->updateStateBlock->set.clipplane[Index] = TRUE;
2623 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2624 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2625 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2626 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2627 TRACE("Application is setting old values over, nothing to do\n");
2628 return WINED3D_OK;
2631 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2632 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2633 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2634 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2636 /* Handle recording of state blocks */
2637 if (This->isRecordingState) {
2638 TRACE("Recording... not performing anything\n");
2639 return WINED3D_OK;
2642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2644 return WINED3D_OK;
2647 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2649 TRACE("(%p) : for idx %d\n", This, Index);
2651 /* Validate Index */
2652 if (Index >= GL_LIMITS(clipplanes)) {
2653 TRACE("Application has requested clipplane this device doesn't support\n");
2654 return WINED3DERR_INVALIDCALL;
2657 pPlane[0] = This->stateBlock->clipplane[Index][0];
2658 pPlane[1] = This->stateBlock->clipplane[Index][1];
2659 pPlane[2] = This->stateBlock->clipplane[Index][2];
2660 pPlane[3] = This->stateBlock->clipplane[Index][3];
2661 return WINED3D_OK;
2664 /*****
2665 * Get / Set Clip Plane Status
2666 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2667 *****/
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 FIXME("(%p) : stub\n", This);
2671 if (NULL == pClipStatus) {
2672 return WINED3DERR_INVALIDCALL;
2674 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2675 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2676 return WINED3D_OK;
2679 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2681 FIXME("(%p) : stub\n", This);
2682 if (NULL == pClipStatus) {
2683 return WINED3DERR_INVALIDCALL;
2685 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2686 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2687 return WINED3D_OK;
2690 /*****
2691 * Get / Set Material
2692 *****/
2693 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2696 This->updateStateBlock->changed.material = TRUE;
2697 This->updateStateBlock->set.material = TRUE;
2698 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2700 /* Handle recording of state blocks */
2701 if (This->isRecordingState) {
2702 TRACE("Recording... not performing anything\n");
2703 return WINED3D_OK;
2706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2707 return WINED3D_OK;
2710 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2713 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2714 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2715 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2716 pMaterial->Ambient.b, pMaterial->Ambient.a);
2717 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2718 pMaterial->Specular.b, pMaterial->Specular.a);
2719 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2720 pMaterial->Emissive.b, pMaterial->Emissive.a);
2721 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2723 return WINED3D_OK;
2726 /*****
2727 * Get / Set Indices
2728 *****/
2729 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 IWineD3DIndexBuffer *oldIdxs;
2733 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2734 oldIdxs = This->updateStateBlock->pIndexData;
2736 This->updateStateBlock->changed.indices = TRUE;
2737 This->updateStateBlock->set.indices = TRUE;
2738 This->updateStateBlock->pIndexData = pIndexData;
2740 /* Handle recording of state blocks */
2741 if (This->isRecordingState) {
2742 TRACE("Recording... not performing anything\n");
2743 return WINED3D_OK;
2746 if(oldIdxs != pIndexData) {
2747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2749 return WINED3D_OK;
2752 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 *ppIndexData = This->stateBlock->pIndexData;
2757 /* up ref count on ppindexdata */
2758 if (*ppIndexData) {
2759 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2760 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2761 }else{
2762 TRACE("(%p) No index data set\n", This);
2764 TRACE("Returning %p\n", *ppIndexData);
2766 return WINED3D_OK;
2769 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2770 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2772 TRACE("(%p)->(%d)\n", This, BaseIndex);
2774 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2775 TRACE("Application is setting the old value over, nothing to do\n");
2776 return WINED3D_OK;
2779 This->updateStateBlock->baseVertexIndex = BaseIndex;
2781 if (This->isRecordingState) {
2782 TRACE("Recording... not performing anything\n");
2783 return WINED3D_OK;
2785 /* The base vertex index affects the stream sources */
2786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2787 return WINED3D_OK;
2790 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2792 TRACE("(%p) : base_index %p\n", This, base_index);
2794 *base_index = This->stateBlock->baseVertexIndex;
2796 TRACE("Returning %u\n", *base_index);
2798 return WINED3D_OK;
2801 /*****
2802 * Get / Set Viewports
2803 *****/
2804 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2807 TRACE("(%p)\n", This);
2808 This->updateStateBlock->changed.viewport = TRUE;
2809 This->updateStateBlock->set.viewport = TRUE;
2810 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2812 /* Handle recording of state blocks */
2813 if (This->isRecordingState) {
2814 TRACE("Recording... not performing anything\n");
2815 return WINED3D_OK;
2818 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2819 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2821 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2822 return WINED3D_OK;
2826 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 TRACE("(%p)\n", This);
2829 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2830 return WINED3D_OK;
2833 /*****
2834 * Get / Set Render States
2835 * TODO: Verify against dx9 definitions
2836 *****/
2837 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2840 DWORD oldValue = This->stateBlock->renderState[State];
2842 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2844 This->updateStateBlock->changed.renderState[State] = TRUE;
2845 This->updateStateBlock->set.renderState[State] = TRUE;
2846 This->updateStateBlock->renderState[State] = Value;
2848 /* Handle recording of state blocks */
2849 if (This->isRecordingState) {
2850 TRACE("Recording... not performing anything\n");
2851 return WINED3D_OK;
2854 /* Compared here and not before the assignment to allow proper stateblock recording */
2855 if(Value == oldValue) {
2856 TRACE("Application is setting the old value over, nothing to do\n");
2857 } else {
2858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2861 return WINED3D_OK;
2864 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2866 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2867 *pValue = This->stateBlock->renderState[State];
2868 return WINED3D_OK;
2871 /*****
2872 * Get / Set Sampler States
2873 * TODO: Verify against dx9 definitions
2874 *****/
2876 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2878 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2881 * SetSampler is designed to allow for more than the standard up to 8 textures
2882 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2883 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2885 * http://developer.nvidia.com/object/General_FAQ.html#t6
2887 * There are two new settings for GForce
2888 * the sampler one:
2889 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2890 * and the texture one:
2891 * GL_MAX_TEXTURE_COORDS_ARB.
2892 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2893 ******************/
2895 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2896 debug_d3dsamplerstate(Type), Type, Value);
2897 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2898 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2899 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2901 /* Handle recording of state blocks */
2902 if (This->isRecordingState) {
2903 TRACE("Recording... not performing anything\n");
2904 return WINED3D_OK;
2907 if(oldValue == Value) {
2908 TRACE("Application is setting the old value over, nothing to do\n");
2909 return WINED3D_OK;
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2914 return WINED3D_OK;
2917 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2919 *Value = This->stateBlock->samplerState[Sampler][Type];
2920 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2922 return WINED3D_OK;
2925 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 This->updateStateBlock->set.scissorRect = TRUE;
2929 This->updateStateBlock->changed.scissorRect = TRUE;
2930 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2931 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2932 return WINED3D_OK;
2934 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2936 if(This->isRecordingState) {
2937 TRACE("Recording... not performing anything\n");
2938 return WINED3D_OK;
2941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2943 return WINED3D_OK;
2946 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2949 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2950 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2951 return WINED3D_OK;
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2956 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2958 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2960 This->updateStateBlock->vertexDecl = pDecl;
2961 This->updateStateBlock->changed.vertexDecl = TRUE;
2962 This->updateStateBlock->set.vertexDecl = TRUE;
2964 if (This->isRecordingState) {
2965 TRACE("Recording... not performing anything\n");
2966 return WINED3D_OK;
2967 } else if(pDecl == oldDecl) {
2968 /* Checked after the assignment to allow proper stateblock recording */
2969 TRACE("Application is setting the old declaration over, nothing to do\n");
2970 return WINED3D_OK;
2973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2982 *ppDecl = This->stateBlock->vertexDecl;
2983 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2984 return WINED3D_OK;
2987 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2991 This->updateStateBlock->vertexShader = pShader;
2992 This->updateStateBlock->changed.vertexShader = TRUE;
2993 This->updateStateBlock->set.vertexShader = TRUE;
2995 if (This->isRecordingState) {
2996 TRACE("Recording... not performing anything\n");
2997 return WINED3D_OK;
2998 } else if(oldShader == pShader) {
2999 /* Checked here to allow proper stateblock recording */
3000 TRACE("App is setting the old shader over, nothing to do\n");
3001 return WINED3D_OK;
3004 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3008 return WINED3D_OK;
3011 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3014 if (NULL == ppShader) {
3015 return WINED3DERR_INVALIDCALL;
3017 *ppShader = This->stateBlock->vertexShader;
3018 if( NULL != *ppShader)
3019 IWineD3DVertexShader_AddRef(*ppShader);
3021 TRACE("(%p) : returning %p\n", This, *ppShader);
3022 return WINED3D_OK;
3025 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3026 IWineD3DDevice *iface,
3027 UINT start,
3028 CONST BOOL *srcData,
3029 UINT count) {
3031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3032 int i, cnt = min(count, MAX_CONST_B - start);
3034 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3035 iface, srcData, start, count);
3037 if (srcData == NULL || cnt < 0)
3038 return WINED3DERR_INVALIDCALL;
3040 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3041 for (i = 0; i < cnt; i++)
3042 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3044 for (i = start; i < cnt + start; ++i) {
3045 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3046 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3049 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3051 return WINED3D_OK;
3054 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3055 IWineD3DDevice *iface,
3056 UINT start,
3057 BOOL *dstData,
3058 UINT count) {
3060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3061 int cnt = min(count, MAX_CONST_B - start);
3063 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3064 iface, dstData, start, count);
3066 if (dstData == NULL || cnt < 0)
3067 return WINED3DERR_INVALIDCALL;
3069 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3070 return WINED3D_OK;
3073 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3074 IWineD3DDevice *iface,
3075 UINT start,
3076 CONST int *srcData,
3077 UINT count) {
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 int i, cnt = min(count, MAX_CONST_I - start);
3082 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3083 iface, srcData, start, count);
3085 if (srcData == NULL || cnt < 0)
3086 return WINED3DERR_INVALIDCALL;
3088 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3089 for (i = 0; i < cnt; i++)
3090 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3091 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3093 for (i = start; i < cnt + start; ++i) {
3094 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3095 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3100 return WINED3D_OK;
3103 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3104 IWineD3DDevice *iface,
3105 UINT start,
3106 int *dstData,
3107 UINT count) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 int cnt = min(count, MAX_CONST_I - start);
3112 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3113 iface, dstData, start, count);
3115 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3116 return WINED3DERR_INVALIDCALL;
3118 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3119 return WINED3D_OK;
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3123 IWineD3DDevice *iface,
3124 UINT start,
3125 CONST float *srcData,
3126 UINT count) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 int i;
3131 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3132 iface, srcData, start, count);
3134 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3135 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3136 return WINED3DERR_INVALIDCALL;
3138 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3139 if(TRACE_ON(d3d)) {
3140 for (i = 0; i < count; i++)
3141 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3142 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3145 for (i = start; i < count + start; ++i) {
3146 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3147 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3148 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3149 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3150 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3152 ptr->idx[ptr->count++] = i;
3153 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3155 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3160 return WINED3D_OK;
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3164 IWineD3DDevice *iface,
3165 UINT start,
3166 float *dstData,
3167 UINT count) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3172 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3173 iface, dstData, start, count);
3175 if (dstData == NULL || cnt < 0)
3176 return WINED3DERR_INVALIDCALL;
3178 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3179 return WINED3D_OK;
3182 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3183 DWORD i;
3184 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3189 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3190 int i = This->rev_tex_unit_map[unit];
3191 int j = This->texUnitMap[stage];
3193 This->texUnitMap[stage] = unit;
3194 if (i != -1 && i != stage) {
3195 This->texUnitMap[i] = -1;
3198 This->rev_tex_unit_map[unit] = stage;
3199 if (j != -1 && j != unit) {
3200 This->rev_tex_unit_map[j] = -1;
3204 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3205 int i;
3207 for (i = 0; i < MAX_TEXTURES; ++i) {
3208 This->fixed_function_usage_map[i] = This->stateBlock->textures[i] ? TRUE : FALSE;
3212 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3213 int i, tex;
3215 device_update_fixed_function_usage_map(This);
3217 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3218 * First, see if we can succeed at all
3220 tex = 0;
3221 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3222 if (!This->fixed_function_usage_map[i]) ++tex;
3225 if (GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3226 FIXME("Too many bound textures to support the combiner settings\n");
3227 return;
3230 /* Now work out the mapping */
3231 tex = 0;
3232 This->oneToOneTexUnitMap = FALSE;
3233 WARN("Non 1:1 mapping UNTESTED!\n");
3234 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3235 /* Skip NULL textures */
3236 if (!This->fixed_function_usage_map[i]) {
3237 /* Map to -1, so the check below doesn't fail if a non-NULL
3238 * texture is set on this stage */
3239 TRACE("Mapping texture stage %d to -1\n", i);
3240 device_map_stage(This, i, -1);
3242 continue;
3245 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3246 if (This->texUnitMap[i] != tex) {
3247 device_map_stage(This, i, tex);
3248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3249 markTextureStagesDirty(This, i);
3252 ++tex;
3256 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3257 DWORD i;
3258 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3259 * it is never called.
3261 * Rules are:
3262 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3263 * that would be really messy and require shader recompilation
3264 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3265 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3266 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3267 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3269 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3270 if(This->oneToOneTexUnitMap) {
3271 TRACE("Not touching 1:1 map\n");
3272 return;
3274 TRACE("Restoring 1:1 texture unit mapping\n");
3275 /* Restore a 1:1 mapping */
3276 for(i = 0; i < MAX_SAMPLERS; i++) {
3277 if(This->texUnitMap[i] != i) {
3278 device_map_stage(This, i, i);
3279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3280 if (i < MAX_TEXTURES) {
3281 markTextureStagesDirty(This, i);
3285 This->oneToOneTexUnitMap = TRUE;
3286 return;
3287 } else {
3288 device_map_fixed_function_samplers(This);
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3295 This->updateStateBlock->pixelShader = pShader;
3296 This->updateStateBlock->changed.pixelShader = TRUE;
3297 This->updateStateBlock->set.pixelShader = TRUE;
3299 /* Handle recording of state blocks */
3300 if (This->isRecordingState) {
3301 TRACE("Recording... not performing anything\n");
3304 if (This->isRecordingState) {
3305 TRACE("Recording... not performing anything\n");
3306 return WINED3D_OK;
3309 if(pShader == oldShader) {
3310 TRACE("App is setting the old pixel shader over, nothing to do\n");
3311 return WINED3D_OK;
3314 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3317 return WINED3D_OK;
3320 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 if (NULL == ppShader) {
3324 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3325 return WINED3DERR_INVALIDCALL;
3328 *ppShader = This->stateBlock->pixelShader;
3329 if (NULL != *ppShader) {
3330 IWineD3DPixelShader_AddRef(*ppShader);
3332 TRACE("(%p) : returning %p\n", This, *ppShader);
3333 return WINED3D_OK;
3336 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3337 IWineD3DDevice *iface,
3338 UINT start,
3339 CONST BOOL *srcData,
3340 UINT count) {
3342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3343 int i, cnt = min(count, MAX_CONST_B - start);
3345 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3346 iface, srcData, start, count);
3348 if (srcData == NULL || cnt < 0)
3349 return WINED3DERR_INVALIDCALL;
3351 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3352 for (i = 0; i < cnt; i++)
3353 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3355 for (i = start; i < cnt + start; ++i) {
3356 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3357 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3362 return WINED3D_OK;
3365 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3366 IWineD3DDevice *iface,
3367 UINT start,
3368 BOOL *dstData,
3369 UINT count) {
3371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3372 int cnt = min(count, MAX_CONST_B - start);
3374 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3375 iface, dstData, start, count);
3377 if (dstData == NULL || cnt < 0)
3378 return WINED3DERR_INVALIDCALL;
3380 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3381 return WINED3D_OK;
3384 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3385 IWineD3DDevice *iface,
3386 UINT start,
3387 CONST int *srcData,
3388 UINT count) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3391 int i, cnt = min(count, MAX_CONST_I - start);
3393 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3394 iface, srcData, start, count);
3396 if (srcData == NULL || cnt < 0)
3397 return WINED3DERR_INVALIDCALL;
3399 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3400 for (i = 0; i < cnt; i++)
3401 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3402 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3404 for (i = start; i < cnt + start; ++i) {
3405 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3406 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3411 return WINED3D_OK;
3414 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3415 IWineD3DDevice *iface,
3416 UINT start,
3417 int *dstData,
3418 UINT count) {
3420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3421 int cnt = min(count, MAX_CONST_I - start);
3423 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3424 iface, dstData, start, count);
3426 if (dstData == NULL || cnt < 0)
3427 return WINED3DERR_INVALIDCALL;
3429 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3430 return WINED3D_OK;
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3434 IWineD3DDevice *iface,
3435 UINT start,
3436 CONST float *srcData,
3437 UINT count) {
3439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3440 int i;
3442 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3443 iface, srcData, start, count);
3445 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3446 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3447 return WINED3DERR_INVALIDCALL;
3449 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3450 if(TRACE_ON(d3d)) {
3451 for (i = 0; i < count; i++)
3452 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3453 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3456 for (i = start; i < count + start; ++i) {
3457 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3458 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3459 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3460 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3461 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3463 ptr->idx[ptr->count++] = i;
3464 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3466 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3471 return WINED3D_OK;
3474 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3475 IWineD3DDevice *iface,
3476 UINT start,
3477 float *dstData,
3478 UINT count) {
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3483 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3484 iface, dstData, start, count);
3486 if (dstData == NULL || cnt < 0)
3487 return WINED3DERR_INVALIDCALL;
3489 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3490 return WINED3D_OK;
3493 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3494 static HRESULT
3495 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3496 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3497 unsigned int i;
3498 DWORD DestFVF = dest->fvf;
3499 WINED3DVIEWPORT vp;
3500 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3501 BOOL doClip;
3502 int numTextures;
3504 if (lpStrideData->u.s.normal.lpData) {
3505 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3508 if (lpStrideData->u.s.position.lpData == NULL) {
3509 ERR("Source has no position mask\n");
3510 return WINED3DERR_INVALIDCALL;
3513 /* We might access VBOs from this code, so hold the lock */
3514 ENTER_GL();
3516 if (dest->resource.allocatedMemory == NULL) {
3517 /* This may happen if we do direct locking into a vbo. Unlikely,
3518 * but theoretically possible(ddraw processvertices test)
3520 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3521 if(!dest->resource.allocatedMemory) {
3522 LEAVE_GL();
3523 ERR("Out of memory\n");
3524 return E_OUTOFMEMORY;
3526 if(dest->vbo) {
3527 void *src;
3528 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3529 checkGLcall("glBindBufferARB");
3530 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3531 if(src) {
3532 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3534 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3535 checkGLcall("glUnmapBufferARB");
3539 /* Get a pointer into the destination vbo(create one if none exists) and
3540 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3542 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3543 CreateVBO(dest);
3546 if(dest->vbo) {
3547 unsigned char extrabytes = 0;
3548 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3549 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3550 * this may write 4 extra bytes beyond the area that should be written
3552 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3553 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3554 if(!dest_conv_addr) {
3555 ERR("Out of memory\n");
3556 /* Continue without storing converted vertices */
3558 dest_conv = dest_conv_addr;
3561 /* Should I clip?
3562 * a) WINED3DRS_CLIPPING is enabled
3563 * b) WINED3DVOP_CLIP is passed
3565 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3566 static BOOL warned = FALSE;
3568 * The clipping code is not quite correct. Some things need
3569 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3570 * so disable clipping for now.
3571 * (The graphics in Half-Life are broken, and my processvertices
3572 * test crashes with IDirect3DDevice3)
3573 doClip = TRUE;
3575 doClip = FALSE;
3576 if(!warned) {
3577 warned = TRUE;
3578 FIXME("Clipping is broken and disabled for now\n");
3580 } else doClip = FALSE;
3581 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3583 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3584 WINED3DTS_VIEW,
3585 &view_mat);
3586 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3587 WINED3DTS_PROJECTION,
3588 &proj_mat);
3589 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3590 WINED3DTS_WORLDMATRIX(0),
3591 &world_mat);
3593 TRACE("View mat:\n");
3594 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);
3595 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);
3596 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);
3597 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);
3599 TRACE("Proj mat:\n");
3600 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);
3601 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);
3602 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);
3603 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);
3605 TRACE("World mat:\n");
3606 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);
3607 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);
3608 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);
3609 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);
3611 /* Get the viewport */
3612 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3613 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3614 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3616 multiply_matrix(&mat,&view_mat,&world_mat);
3617 multiply_matrix(&mat,&proj_mat,&mat);
3619 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3621 for (i = 0; i < dwCount; i+= 1) {
3622 unsigned int tex_index;
3624 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3625 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3626 /* The position first */
3627 float *p =
3628 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3629 float x, y, z, rhw;
3630 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3632 /* Multiplication with world, view and projection matrix */
3633 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);
3634 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);
3635 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);
3636 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);
3638 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3640 /* WARNING: The following things are taken from d3d7 and were not yet checked
3641 * against d3d8 or d3d9!
3644 /* Clipping conditions: From
3645 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3647 * A vertex is clipped if it does not match the following requirements
3648 * -rhw < x <= rhw
3649 * -rhw < y <= rhw
3650 * 0 < z <= rhw
3651 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3653 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3654 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3658 if( !doClip ||
3659 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3660 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3661 ( rhw > eps ) ) ) {
3663 /* "Normal" viewport transformation (not clipped)
3664 * 1) The values are divided by rhw
3665 * 2) The y axis is negative, so multiply it with -1
3666 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3667 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3668 * 4) Multiply x with Width/2 and add Width/2
3669 * 5) The same for the height
3670 * 6) Add the viewpoint X and Y to the 2D coordinates and
3671 * The minimum Z value to z
3672 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3674 * Well, basically it's simply a linear transformation into viewport
3675 * coordinates
3678 x /= rhw;
3679 y /= rhw;
3680 z /= rhw;
3682 y *= -1;
3684 x *= vp.Width / 2;
3685 y *= vp.Height / 2;
3686 z *= vp.MaxZ - vp.MinZ;
3688 x += vp.Width / 2 + vp.X;
3689 y += vp.Height / 2 + vp.Y;
3690 z += vp.MinZ;
3692 rhw = 1 / rhw;
3693 } else {
3694 /* That vertex got clipped
3695 * Contrary to OpenGL it is not dropped completely, it just
3696 * undergoes a different calculation.
3698 TRACE("Vertex got clipped\n");
3699 x += rhw;
3700 y += rhw;
3702 x /= 2;
3703 y /= 2;
3705 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3706 * outside of the main vertex buffer memory. That needs some more
3707 * investigation...
3711 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3714 ( (float *) dest_ptr)[0] = x;
3715 ( (float *) dest_ptr)[1] = y;
3716 ( (float *) dest_ptr)[2] = z;
3717 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3719 dest_ptr += 3 * sizeof(float);
3721 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3722 dest_ptr += sizeof(float);
3725 if(dest_conv) {
3726 float w = 1 / rhw;
3727 ( (float *) dest_conv)[0] = x * w;
3728 ( (float *) dest_conv)[1] = y * w;
3729 ( (float *) dest_conv)[2] = z * w;
3730 ( (float *) dest_conv)[3] = w;
3732 dest_conv += 3 * sizeof(float);
3734 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3735 dest_conv += sizeof(float);
3739 if (DestFVF & WINED3DFVF_PSIZE) {
3740 dest_ptr += sizeof(DWORD);
3741 if(dest_conv) dest_conv += sizeof(DWORD);
3743 if (DestFVF & WINED3DFVF_NORMAL) {
3744 float *normal =
3745 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3746 /* AFAIK this should go into the lighting information */
3747 FIXME("Didn't expect the destination to have a normal\n");
3748 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3749 if(dest_conv) {
3750 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3754 if (DestFVF & WINED3DFVF_DIFFUSE) {
3755 DWORD *color_d =
3756 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3757 if(!color_d) {
3758 static BOOL warned = FALSE;
3760 if(!warned) {
3761 ERR("No diffuse color in source, but destination has one\n");
3762 warned = TRUE;
3765 *( (DWORD *) dest_ptr) = 0xffffffff;
3766 dest_ptr += sizeof(DWORD);
3768 if(dest_conv) {
3769 *( (DWORD *) dest_conv) = 0xffffffff;
3770 dest_conv += sizeof(DWORD);
3773 else {
3774 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3775 if(dest_conv) {
3776 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3777 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3778 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3779 dest_conv += sizeof(DWORD);
3784 if (DestFVF & WINED3DFVF_SPECULAR) {
3785 /* What's the color value in the feedback buffer? */
3786 DWORD *color_s =
3787 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3788 if(!color_s) {
3789 static BOOL warned = FALSE;
3791 if(!warned) {
3792 ERR("No specular color in source, but destination has one\n");
3793 warned = TRUE;
3796 *( (DWORD *) dest_ptr) = 0xFF000000;
3797 dest_ptr += sizeof(DWORD);
3799 if(dest_conv) {
3800 *( (DWORD *) dest_conv) = 0xFF000000;
3801 dest_conv += sizeof(DWORD);
3804 else {
3805 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3806 if(dest_conv) {
3807 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3808 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3809 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3810 dest_conv += sizeof(DWORD);
3815 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3816 float *tex_coord =
3817 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3818 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3819 if(!tex_coord) {
3820 ERR("No source texture, but destination requests one\n");
3821 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3822 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3824 else {
3825 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3826 if(dest_conv) {
3827 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3833 if(dest_conv) {
3834 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3835 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3836 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3837 dwCount * get_flexible_vertex_size(DestFVF),
3838 dest_conv_addr));
3839 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3840 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3843 LEAVE_GL();
3845 return WINED3D_OK;
3847 #undef copy_and_next
3849 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3851 WineDirect3DVertexStridedData strided;
3852 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3853 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3855 if(pVertexDecl) {
3856 ERR("Output vertex declaration not implemented yet\n");
3859 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3860 * and this call is quite performance critical, so don't call needlessly
3862 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3863 ENTER_GL();
3864 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3865 LEAVE_GL();
3868 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3869 * control the streamIsUP flag, thus restore it afterwards.
3871 This->stateBlock->streamIsUP = FALSE;
3872 memset(&strided, 0, sizeof(strided));
3873 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3874 This->stateBlock->streamIsUP = streamWasUP;
3876 if(vbo || SrcStartIndex) {
3877 unsigned int i;
3878 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3879 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3881 * Also get the start index in, but only loop over all elements if there's something to add at all.
3883 #define FIXSRC(type) \
3884 if(strided.u.s.type.VBO) { \
3885 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3886 strided.u.s.type.VBO = 0; \
3887 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3888 ENTER_GL(); \
3889 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3890 vb->vbo = 0; \
3891 LEAVE_GL(); \
3893 if(strided.u.s.type.lpData) { \
3894 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3896 FIXSRC(position);
3897 FIXSRC(blendWeights);
3898 FIXSRC(blendMatrixIndices);
3899 FIXSRC(normal);
3900 FIXSRC(pSize);
3901 FIXSRC(diffuse);
3902 FIXSRC(specular);
3903 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3904 FIXSRC(texCoords[i]);
3906 FIXSRC(position2);
3907 FIXSRC(normal2);
3908 FIXSRC(tangent);
3909 FIXSRC(binormal);
3910 FIXSRC(tessFactor);
3911 FIXSRC(fog);
3912 FIXSRC(depth);
3913 FIXSRC(sample);
3914 #undef FIXSRC
3917 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3920 /*****
3921 * Get / Set Texture Stage States
3922 * TODO: Verify against dx9 definitions
3923 *****/
3924 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3926 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3928 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3930 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3932 if (Stage >= MAX_TEXTURES) {
3933 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3934 return WINED3D_OK;
3937 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3938 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3939 This->updateStateBlock->textureState[Stage][Type] = Value;
3941 if (This->isRecordingState) {
3942 TRACE("Recording... not performing anything\n");
3943 return WINED3D_OK;
3946 /* Checked after the assignments to allow proper stateblock recording */
3947 if(oldValue == Value) {
3948 TRACE("App is setting the old value over, nothing to do\n");
3949 return WINED3D_OK;
3952 if(Stage > This->stateBlock->lowest_disabled_stage &&
3953 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3954 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3955 * Changes in other states are important on disabled stages too
3957 return WINED3D_OK;
3960 if(Type == WINED3DTSS_COLOROP) {
3961 int i;
3963 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3964 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3965 * they have to be disabled
3967 * The current stage is dirtified below.
3969 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3970 TRACE("Additionally dirtifying stage %d\n", i);
3971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3973 This->stateBlock->lowest_disabled_stage = Stage;
3974 TRACE("New lowest disabled: %d\n", Stage);
3975 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3976 /* Previously disabled stage enabled. Stages above it may need enabling
3977 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3978 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3980 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3983 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3984 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3985 break;
3987 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3990 This->stateBlock->lowest_disabled_stage = i;
3991 TRACE("New lowest disabled: %d\n", i);
3993 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3994 /* TODO: Built a stage -> texture unit mapping for register combiners */
3998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4000 return WINED3D_OK;
4003 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4005 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4006 *pValue = This->updateStateBlock->textureState[Stage][Type];
4007 return WINED3D_OK;
4010 /*****
4011 * Get / Set Texture
4012 *****/
4013 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4016 IWineD3DBaseTexture *oldTexture;
4018 oldTexture = This->updateStateBlock->textures[Stage];
4019 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4021 #if 0 /* TODO: check so vertex textures */
4022 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4023 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4024 return WINED3D_OK;
4026 #endif
4028 if(pTexture != NULL) {
4029 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4031 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4032 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4033 return WINED3DERR_INVALIDCALL;
4035 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4038 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4039 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4041 This->updateStateBlock->set.textures[Stage] = TRUE;
4042 This->updateStateBlock->changed.textures[Stage] = TRUE;
4043 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4044 This->updateStateBlock->textures[Stage] = pTexture;
4046 /* Handle recording of state blocks */
4047 if (This->isRecordingState) {
4048 TRACE("Recording... not performing anything\n");
4049 return WINED3D_OK;
4052 if(oldTexture == pTexture) {
4053 TRACE("App is setting the same texture again, nothing to do\n");
4054 return WINED3D_OK;
4057 /** NOTE: MSDN says that setTexture increases the reference count,
4058 * and the the application must set the texture back to null (or have a leaky application),
4059 * This means we should pass the refcount up to the parent
4060 *******************************/
4061 if (NULL != This->updateStateBlock->textures[Stage]) {
4062 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4063 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4065 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4066 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4067 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4068 * so the COLOROP and ALPHAOP have to be dirtified.
4070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4073 if(bindCount == 1) {
4074 new->baseTexture.sampler = Stage;
4076 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4080 if (NULL != oldTexture) {
4081 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4082 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4084 IWineD3DBaseTexture_Release(oldTexture);
4085 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4090 if(bindCount && old->baseTexture.sampler == Stage) {
4091 int i;
4092 /* Have to do a search for the other sampler(s) where the texture is bound to
4093 * Shouldn't happen as long as apps bind a texture only to one stage
4095 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4096 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4097 if(This->updateStateBlock->textures[i] == oldTexture) {
4098 old->baseTexture.sampler = i;
4099 break;
4105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4107 return WINED3D_OK;
4110 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4112 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4114 *ppTexture=This->stateBlock->textures[Stage];
4115 if (*ppTexture)
4116 IWineD3DBaseTexture_AddRef(*ppTexture);
4118 return WINED3D_OK;
4121 /*****
4122 * Get Back Buffer
4123 *****/
4124 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4125 IWineD3DSurface **ppBackBuffer) {
4126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4127 IWineD3DSwapChain *swapChain;
4128 HRESULT hr;
4130 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4132 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4133 if (hr == WINED3D_OK) {
4134 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4135 IWineD3DSwapChain_Release(swapChain);
4136 } else {
4137 *ppBackBuffer = NULL;
4139 return hr;
4142 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4144 WARN("(%p) : stub, calling idirect3d for now\n", This);
4145 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4148 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4150 IWineD3DSwapChain *swapChain;
4151 HRESULT hr;
4153 if(iSwapChain > 0) {
4154 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4155 if (hr == WINED3D_OK) {
4156 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4157 IWineD3DSwapChain_Release(swapChain);
4158 } else {
4159 FIXME("(%p) Error getting display mode\n", This);
4161 } else {
4162 /* Don't read the real display mode,
4163 but return the stored mode instead. X11 can't change the color
4164 depth, and some apps are pretty angry if they SetDisplayMode from
4165 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4167 Also don't relay to the swapchain because with ddraw it's possible
4168 that there isn't a swapchain at all */
4169 pMode->Width = This->ddraw_width;
4170 pMode->Height = This->ddraw_height;
4171 pMode->Format = This->ddraw_format;
4172 pMode->RefreshRate = 0;
4173 hr = WINED3D_OK;
4176 return hr;
4179 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4181 TRACE("(%p)->(%p)\n", This, hWnd);
4183 if(This->ddraw_fullscreen) {
4184 if(This->ddraw_window && This->ddraw_window != hWnd) {
4185 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4187 if(hWnd && This->ddraw_window != hWnd) {
4188 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4192 This->ddraw_window = hWnd;
4193 return WINED3D_OK;
4196 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4198 TRACE("(%p)->(%p)\n", This, hWnd);
4200 *hWnd = This->ddraw_window;
4201 return WINED3D_OK;
4204 /*****
4205 * Stateblock related functions
4206 *****/
4208 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4210 IWineD3DStateBlockImpl *object;
4211 HRESULT temp_result;
4212 int i;
4214 TRACE("(%p)\n", This);
4216 if (This->isRecordingState) {
4217 return WINED3DERR_INVALIDCALL;
4220 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4221 if (NULL == object ) {
4222 FIXME("(%p)Error allocating memory for stateblock\n", This);
4223 return E_OUTOFMEMORY;
4225 TRACE("(%p) created object %p\n", This, object);
4226 object->wineD3DDevice= This;
4227 /** FIXME: object->parent = parent; **/
4228 object->parent = NULL;
4229 object->blockType = WINED3DSBT_ALL;
4230 object->ref = 1;
4231 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4233 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4234 list_init(&object->lightMap[i]);
4237 temp_result = allocate_shader_constants(object);
4238 if (WINED3D_OK != temp_result)
4239 return temp_result;
4241 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4242 This->updateStateBlock = object;
4243 This->isRecordingState = TRUE;
4245 TRACE("(%p) recording stateblock %p\n",This , object);
4246 return WINED3D_OK;
4249 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4252 if (!This->isRecordingState) {
4253 FIXME("(%p) not recording! returning error\n", This);
4254 *ppStateBlock = NULL;
4255 return WINED3DERR_INVALIDCALL;
4258 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4259 This->isRecordingState = FALSE;
4260 This->updateStateBlock = This->stateBlock;
4261 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4262 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4263 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4264 return WINED3D_OK;
4267 /*****
4268 * Scene related functions
4269 *****/
4270 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4271 /* At the moment we have no need for any functionality at the beginning
4272 of a scene */
4273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4274 TRACE("(%p)\n", This);
4276 if(This->inScene) {
4277 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4278 return WINED3DERR_INVALIDCALL;
4280 This->inScene = TRUE;
4281 return WINED3D_OK;
4284 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4286 TRACE("(%p)\n", This);
4288 if(!This->inScene) {
4289 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4290 return WINED3DERR_INVALIDCALL;
4293 ENTER_GL();
4294 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4295 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4297 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4298 glFlush();
4299 checkGLcall("glFlush");
4300 LEAVE_GL();
4302 This->inScene = FALSE;
4303 return WINED3D_OK;
4306 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4307 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4308 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4310 IWineD3DSwapChain *swapChain = NULL;
4311 int i;
4312 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4314 TRACE("(%p) Presenting the frame\n", This);
4316 for(i = 0 ; i < swapchains ; i ++) {
4318 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4319 TRACE("presentinng chain %d, %p\n", i, swapChain);
4320 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4321 IWineD3DSwapChain_Release(swapChain);
4324 return WINED3D_OK;
4327 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4328 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4330 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4332 GLbitfield glMask = 0;
4333 unsigned int i;
4334 CONST WINED3DRECT* curRect;
4336 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4337 Count, pRects, Flags, Color, Z, Stencil);
4339 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4340 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4341 /* TODO: What about depth stencil buffers without stencil bits? */
4342 return WINED3DERR_INVALIDCALL;
4345 ENTER_GL();
4346 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4347 * and not the last active one.
4350 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4351 apply_fbo_state(iface);
4354 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4356 glEnable(GL_SCISSOR_TEST);
4357 checkGLcall("glEnable GL_SCISSOR_TEST");
4358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4361 if (Count > 0 && pRects) {
4362 curRect = pRects;
4363 } else {
4364 curRect = NULL;
4367 /* Only set the values up once, as they are not changing */
4368 if (Flags & WINED3DCLEAR_STENCIL) {
4369 glClearStencil(Stencil);
4370 checkGLcall("glClearStencil");
4371 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4372 glStencilMask(0xFFFFFFFF);
4375 if (Flags & WINED3DCLEAR_ZBUFFER) {
4376 glDepthMask(GL_TRUE);
4377 glClearDepth(Z);
4378 checkGLcall("glClearDepth");
4379 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4383 if (Flags & WINED3DCLEAR_TARGET) {
4384 TRACE("Clearing screen with glClear to color %x\n", Color);
4385 glClearColor(D3DCOLOR_R(Color),
4386 D3DCOLOR_G(Color),
4387 D3DCOLOR_B(Color),
4388 D3DCOLOR_A(Color));
4389 checkGLcall("glClearColor");
4391 /* Clear ALL colors! */
4392 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4393 glMask = glMask | GL_COLOR_BUFFER_BIT;
4396 if (!curRect) {
4397 /* In drawable flag is set below */
4399 glScissor(This->stateBlock->viewport.X,
4400 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4401 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4402 This->stateBlock->viewport.Width,
4403 This->stateBlock->viewport.Height);
4404 checkGLcall("glScissor");
4405 glClear(glMask);
4406 checkGLcall("glClear");
4407 } else {
4408 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4409 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4411 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4412 curRect[0].x2 < target->currentDesc.Width ||
4413 curRect[0].y2 < target->currentDesc.Height) {
4414 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4415 blt_to_drawable(This, target);
4419 /* Now process each rect in turn */
4420 for (i = 0; i < Count; i++) {
4421 /* Note gl uses lower left, width/height */
4422 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4423 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4424 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4425 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4427 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4428 * The rectangle is not cleared, no error is returned, but further rectanlges are
4429 * still cleared if they are valid
4431 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4432 TRACE("Rectangle with negative dimensions, ignoring\n");
4433 continue;
4436 if(This->render_offscreen) {
4437 glScissor(curRect[i].x1, curRect[i].y1,
4438 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4439 } else {
4440 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4441 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4443 checkGLcall("glScissor");
4445 glClear(glMask);
4446 checkGLcall("glClear");
4450 /* Restore the old values (why..?) */
4451 if (Flags & WINED3DCLEAR_STENCIL) {
4452 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4454 if (Flags & WINED3DCLEAR_TARGET) {
4455 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4456 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4457 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4458 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4459 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4462 LEAVE_GL();
4464 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4465 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4467 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4468 target->Flags |= SFLAG_INTEXTURE;
4469 target->Flags &= ~SFLAG_INSYSMEM;
4470 } else {
4471 target->Flags |= SFLAG_INDRAWABLE;
4472 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4474 return WINED3D_OK;
4477 /*****
4478 * Drawing functions
4479 *****/
4480 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4481 UINT PrimitiveCount) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4486 debug_d3dprimitivetype(PrimitiveType),
4487 StartVertex, PrimitiveCount);
4489 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4490 if(This->stateBlock->streamIsUP) {
4491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4492 This->stateBlock->streamIsUP = FALSE;
4495 if(This->stateBlock->loadBaseVertexIndex != 0) {
4496 This->stateBlock->loadBaseVertexIndex = 0;
4497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4499 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4500 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4501 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4502 return WINED3D_OK;
4505 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4506 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4507 WINED3DPRIMITIVETYPE PrimitiveType,
4508 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4511 UINT idxStride = 2;
4512 IWineD3DIndexBuffer *pIB;
4513 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4514 GLuint vbo;
4516 pIB = This->stateBlock->pIndexData;
4517 if (!pIB) {
4518 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4519 * without an index buffer set. (The first time at least...)
4520 * D3D8 simply dies, but I doubt it can do much harm to return
4521 * D3DERR_INVALIDCALL there as well. */
4522 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4523 return WINED3DERR_INVALIDCALL;
4526 if(This->stateBlock->streamIsUP) {
4527 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4528 This->stateBlock->streamIsUP = FALSE;
4530 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4532 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4533 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4534 minIndex, NumVertices, startIndex, primCount);
4536 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4537 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4538 idxStride = 2;
4539 } else {
4540 idxStride = 4;
4543 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4544 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4548 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4549 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4551 return WINED3D_OK;
4554 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4555 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4556 UINT VertexStreamZeroStride) {
4557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4560 debug_d3dprimitivetype(PrimitiveType),
4561 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4563 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4564 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4565 This->stateBlock->streamOffset[0] = 0;
4566 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4567 This->stateBlock->streamIsUP = TRUE;
4568 This->stateBlock->loadBaseVertexIndex = 0;
4570 /* TODO: Only mark dirty if drawing from a different UP address */
4571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4573 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4574 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4576 /* MSDN specifies stream zero settings must be set to NULL */
4577 This->stateBlock->streamStride[0] = 0;
4578 This->stateBlock->streamSource[0] = NULL;
4580 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4581 * the new stream sources or use UP drawing again
4583 return WINED3D_OK;
4586 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4587 UINT MinVertexIndex, UINT NumVertices,
4588 UINT PrimitiveCount, CONST void* pIndexData,
4589 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4590 UINT VertexStreamZeroStride) {
4591 int idxStride;
4592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4594 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4595 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4596 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4597 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4599 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4600 idxStride = 2;
4601 } else {
4602 idxStride = 4;
4605 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4606 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4607 This->stateBlock->streamIsUP = TRUE;
4608 This->stateBlock->streamOffset[0] = 0;
4609 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4611 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4612 This->stateBlock->baseVertexIndex = 0;
4613 This->stateBlock->loadBaseVertexIndex = 0;
4614 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4618 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4620 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4621 This->stateBlock->streamSource[0] = NULL;
4622 This->stateBlock->streamStride[0] = 0;
4623 This->stateBlock->pIndexData = NULL;
4624 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4625 * SetStreamSource to specify a vertex buffer
4628 return WINED3D_OK;
4631 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4634 /* Mark the state dirty until we have nicer tracking
4635 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4636 * that value.
4638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4640 This->stateBlock->baseVertexIndex = 0;
4641 This->up_strided = DrawPrimStrideData;
4642 This->stateBlock->streamIsUP = TRUE;
4643 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4644 This->up_strided = NULL;
4645 return WINED3D_OK;
4647 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4648 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 HRESULT hr = WINED3D_OK;
4651 WINED3DRESOURCETYPE sourceType;
4652 WINED3DRESOURCETYPE destinationType;
4653 int i ,levels;
4655 /* TODO: think about moving the code into IWineD3DBaseTexture */
4657 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4659 /* verify that the source and destination textures aren't NULL */
4660 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4661 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4662 This, pSourceTexture, pDestinationTexture);
4663 hr = WINED3DERR_INVALIDCALL;
4666 if (pSourceTexture == pDestinationTexture) {
4667 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4668 This, pSourceTexture, pDestinationTexture);
4669 hr = WINED3DERR_INVALIDCALL;
4671 /* Verify that the source and destination textures are the same type */
4672 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4673 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4675 if (sourceType != destinationType) {
4676 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4677 This);
4678 hr = WINED3DERR_INVALIDCALL;
4681 /* check that both textures have the identical numbers of levels */
4682 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4683 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4684 hr = WINED3DERR_INVALIDCALL;
4687 if (WINED3D_OK == hr) {
4689 /* Make sure that the destination texture is loaded */
4690 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4692 /* Update every surface level of the texture */
4693 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4695 switch (sourceType) {
4696 case WINED3DRTYPE_TEXTURE:
4698 IWineD3DSurface *srcSurface;
4699 IWineD3DSurface *destSurface;
4701 for (i = 0 ; i < levels ; ++i) {
4702 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4703 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4704 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4705 IWineD3DSurface_Release(srcSurface);
4706 IWineD3DSurface_Release(destSurface);
4707 if (WINED3D_OK != hr) {
4708 WARN("(%p) : Call to update surface failed\n", This);
4709 return hr;
4713 break;
4714 case WINED3DRTYPE_CUBETEXTURE:
4716 IWineD3DSurface *srcSurface;
4717 IWineD3DSurface *destSurface;
4718 WINED3DCUBEMAP_FACES faceType;
4720 for (i = 0 ; i < levels ; ++i) {
4721 /* Update each cube face */
4722 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4723 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4724 if (WINED3D_OK != hr) {
4725 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4726 } else {
4727 TRACE("Got srcSurface %p\n", srcSurface);
4729 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4730 if (WINED3D_OK != hr) {
4731 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4732 } else {
4733 TRACE("Got desrSurface %p\n", destSurface);
4735 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4736 IWineD3DSurface_Release(srcSurface);
4737 IWineD3DSurface_Release(destSurface);
4738 if (WINED3D_OK != hr) {
4739 WARN("(%p) : Call to update surface failed\n", This);
4740 return hr;
4745 break;
4746 #if 0 /* TODO: Add support for volume textures */
4747 case WINED3DRTYPE_VOLUMETEXTURE:
4749 IWineD3DVolume srcVolume = NULL;
4750 IWineD3DSurface destVolume = NULL;
4752 for (i = 0 ; i < levels ; ++i) {
4753 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4754 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4755 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4756 IWineD3DVolume_Release(srcSurface);
4757 IWineD3DVolume_Release(destSurface);
4758 if (WINED3D_OK != hr) {
4759 WARN("(%p) : Call to update volume failed\n", This);
4760 return hr;
4764 break;
4765 #endif
4766 default:
4767 FIXME("(%p) : Unsupported source and destination type\n", This);
4768 hr = WINED3DERR_INVALIDCALL;
4772 return hr;
4775 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4776 IWineD3DSwapChain *swapChain;
4777 HRESULT hr;
4778 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4779 if(hr == WINED3D_OK) {
4780 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4781 IWineD3DSwapChain_Release(swapChain);
4783 return hr;
4786 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4788 /* return a sensible default */
4789 *pNumPasses = 1;
4790 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4791 FIXME("(%p) : stub\n", This);
4792 return WINED3D_OK;
4795 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4797 int j;
4798 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4799 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4800 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4801 return WINED3DERR_INVALIDCALL;
4803 for (j = 0; j < 256; ++j) {
4804 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4805 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4806 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4807 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4809 TRACE("(%p) : returning\n", This);
4810 return WINED3D_OK;
4813 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4815 int j;
4816 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4817 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4818 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4819 return WINED3DERR_INVALIDCALL;
4821 for (j = 0; j < 256; ++j) {
4822 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4823 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4824 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4825 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4827 TRACE("(%p) : returning\n", This);
4828 return WINED3D_OK;
4831 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4833 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4834 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4835 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4836 return WINED3DERR_INVALIDCALL;
4838 /*TODO: stateblocks */
4839 This->currentPalette = PaletteNumber;
4840 TRACE("(%p) : returning\n", This);
4841 return WINED3D_OK;
4844 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4846 if (PaletteNumber == NULL) {
4847 WARN("(%p) : returning Invalid Call\n", This);
4848 return WINED3DERR_INVALIDCALL;
4850 /*TODO: stateblocks */
4851 *PaletteNumber = This->currentPalette;
4852 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4853 return WINED3D_OK;
4856 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4858 static BOOL showFixmes = TRUE;
4859 if (showFixmes) {
4860 FIXME("(%p) : stub\n", This);
4861 showFixmes = FALSE;
4864 This->softwareVertexProcessing = bSoftware;
4865 return WINED3D_OK;
4869 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4871 static BOOL showFixmes = TRUE;
4872 if (showFixmes) {
4873 FIXME("(%p) : stub\n", This);
4874 showFixmes = FALSE;
4876 return This->softwareVertexProcessing;
4880 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 IWineD3DSwapChain *swapChain;
4883 HRESULT hr;
4885 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4887 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4888 if(hr == WINED3D_OK){
4889 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4890 IWineD3DSwapChain_Release(swapChain);
4891 }else{
4892 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4894 return hr;
4898 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4900 static BOOL showfixmes = TRUE;
4901 if(nSegments != 0.0f) {
4902 if( showfixmes) {
4903 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4904 showfixmes = FALSE;
4907 return WINED3D_OK;
4910 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4912 static BOOL showfixmes = TRUE;
4913 if( showfixmes) {
4914 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4915 showfixmes = FALSE;
4917 return 0.0f;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4922 /** TODO: remove casts to IWineD3DSurfaceImpl
4923 * NOTE: move code to surface to accomplish this
4924 ****************************************/
4925 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4926 int srcWidth, srcHeight;
4927 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4928 WINED3DFORMAT destFormat, srcFormat;
4929 UINT destSize;
4930 int srcLeft, destLeft, destTop;
4931 WINED3DPOOL srcPool, destPool;
4932 int offset = 0;
4933 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4934 glDescriptor *glDescription = NULL;
4936 WINED3DSURFACE_DESC winedesc;
4938 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4939 memset(&winedesc, 0, sizeof(winedesc));
4940 winedesc.Width = &srcSurfaceWidth;
4941 winedesc.Height = &srcSurfaceHeight;
4942 winedesc.Pool = &srcPool;
4943 winedesc.Format = &srcFormat;
4945 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4947 winedesc.Width = &destSurfaceWidth;
4948 winedesc.Height = &destSurfaceHeight;
4949 winedesc.Pool = &destPool;
4950 winedesc.Format = &destFormat;
4951 winedesc.Size = &destSize;
4953 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4955 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4956 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4957 return WINED3DERR_INVALIDCALL;
4960 if (destFormat == WINED3DFMT_UNKNOWN) {
4961 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4962 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4964 /* Get the update surface description */
4965 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4968 ENTER_GL();
4970 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4972 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4973 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4974 checkGLcall("glActiveTextureARB");
4977 /* Make sure the surface is loaded and up to date */
4978 IWineD3DSurface_PreLoad(pDestinationSurface);
4980 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4982 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4983 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4984 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4985 srcLeft = pSourceRect ? pSourceRect->left : 0;
4986 destLeft = pDestPoint ? pDestPoint->x : 0;
4987 destTop = pDestPoint ? pDestPoint->y : 0;
4990 /* This function doesn't support compressed textures
4991 the pitch is just bytesPerPixel * width */
4992 if(srcWidth != srcSurfaceWidth || srcLeft ){
4993 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4994 offset += srcLeft * pSrcSurface->bytesPerPixel;
4995 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4997 /* TODO DXT formats */
4999 if(pSourceRect != NULL && pSourceRect->top != 0){
5000 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5002 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5003 ,This
5004 ,glDescription->level
5005 ,destLeft
5006 ,destTop
5007 ,srcWidth
5008 ,srcHeight
5009 ,glDescription->glFormat
5010 ,glDescription->glType
5011 ,IWineD3DSurface_GetData(pSourceSurface)
5014 /* Sanity check */
5015 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5017 /* need to lock the surface to get the data */
5018 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5021 /* TODO: Cube and volume support */
5022 if(rowoffset != 0){
5023 /* not a whole row so we have to do it a line at a time */
5024 int j;
5026 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5027 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5029 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5031 glTexSubImage2D(glDescription->target
5032 ,glDescription->level
5033 ,destLeft
5035 ,srcWidth
5037 ,glDescription->glFormat
5038 ,glDescription->glType
5039 ,data /* could be quicker using */
5041 data += rowoffset;
5044 } else { /* Full width, so just write out the whole texture */
5046 if (WINED3DFMT_DXT1 == destFormat ||
5047 WINED3DFMT_DXT2 == destFormat ||
5048 WINED3DFMT_DXT3 == destFormat ||
5049 WINED3DFMT_DXT4 == destFormat ||
5050 WINED3DFMT_DXT5 == destFormat) {
5051 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5052 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5053 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5054 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5055 } if (destFormat != srcFormat) {
5056 FIXME("Updating mixed format compressed texture is not curretly support\n");
5057 } else {
5058 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5059 glDescription->level,
5060 glDescription->glFormatInternal,
5061 srcWidth,
5062 srcHeight,
5064 destSize,
5065 IWineD3DSurface_GetData(pSourceSurface));
5067 } else {
5068 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5072 } else {
5073 glTexSubImage2D(glDescription->target
5074 ,glDescription->level
5075 ,destLeft
5076 ,destTop
5077 ,srcWidth
5078 ,srcHeight
5079 ,glDescription->glFormat
5080 ,glDescription->glType
5081 ,IWineD3DSurface_GetData(pSourceSurface)
5085 checkGLcall("glTexSubImage2D");
5087 LEAVE_GL();
5089 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5090 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5093 return WINED3D_OK;
5096 /* Implementation details at http://developer.nvidia.com/attach/6494
5098 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5099 hmm.. no longer supported use
5100 OpenGL evaluators or tessellate surfaces within your application.
5103 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5104 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5106 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5107 FIXME("(%p) : Stub\n", This);
5108 return WINED3D_OK;
5112 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5113 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5115 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5116 FIXME("(%p) : Stub\n", This);
5117 return WINED3D_OK;
5120 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5122 TRACE("(%p) Handle(%d)\n", This, Handle);
5123 FIXME("(%p) : Stub\n", This);
5124 return WINED3D_OK;
5127 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5128 HRESULT hr;
5129 IWineD3DSwapChain *swapchain;
5131 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5132 if (SUCCEEDED(hr)) {
5133 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5134 return swapchain;
5137 return NULL;
5140 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5143 if (!*fbo) {
5144 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5145 checkGLcall("glGenFramebuffersEXT()");
5147 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5148 checkGLcall("glBindFramebuffer()");
5151 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5152 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5153 IWineD3DBaseTextureImpl *texture_impl;
5154 GLenum texttarget, target;
5155 GLint old_binding;
5157 texttarget = surface_impl->glDescription.target;
5158 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5159 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5161 IWineD3DSurface_PreLoad(surface);
5163 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5164 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5165 glBindTexture(target, old_binding);
5167 /* Update base texture states array */
5168 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5169 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5170 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5171 if (texture_impl->baseTexture.bindCount) {
5172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5175 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5178 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5180 checkGLcall("attach_surface_fbo");
5183 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5185 IWineD3DSwapChain *swapchain;
5187 swapchain = get_swapchain(surface);
5188 if (swapchain) {
5189 GLenum buffer;
5191 TRACE("Surface %p is onscreen\n", surface);
5193 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5194 buffer = surface_get_gl_buffer(surface, swapchain);
5195 glDrawBuffer(buffer);
5196 checkGLcall("glDrawBuffer()");
5197 } else {
5198 TRACE("Surface %p is offscreen\n", surface);
5199 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5200 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5203 if (rect) {
5204 glEnable(GL_SCISSOR_TEST);
5205 if(!swapchain) {
5206 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5207 } else {
5208 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5209 rect->x2 - rect->x1, rect->y2 - rect->y1);
5211 checkGLcall("glScissor");
5212 } else {
5213 glDisable(GL_SCISSOR_TEST);
5215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5217 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5220 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5221 glClear(GL_COLOR_BUFFER_BIT);
5222 checkGLcall("glClear");
5224 if (This->render_offscreen) {
5225 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5226 } else {
5227 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5228 checkGLcall("glBindFramebuffer()");
5231 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5232 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5233 glDrawBuffer(GL_BACK);
5234 checkGLcall("glDrawBuffer()");
5238 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5240 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5241 WINEDDBLTFX BltFx;
5242 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5244 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5245 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5246 return WINED3DERR_INVALIDCALL;
5249 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5250 color_fill_fbo(iface, pSurface, pRect, color);
5251 return WINED3D_OK;
5252 } else {
5253 /* Just forward this to the DirectDraw blitting engine */
5254 memset(&BltFx, 0, sizeof(BltFx));
5255 BltFx.dwSize = sizeof(BltFx);
5256 BltFx.u5.dwFillColor = color;
5257 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5261 /* rendertarget and deptth stencil functions */
5262 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5265 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5266 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5267 return WINED3DERR_INVALIDCALL;
5270 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5271 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5272 /* Note inc ref on returned surface */
5273 if(*ppRenderTarget != NULL)
5274 IWineD3DSurface_AddRef(*ppRenderTarget);
5275 return WINED3D_OK;
5278 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5280 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5281 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5282 IWineD3DSwapChainImpl *Swapchain;
5283 HRESULT hr;
5285 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5287 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5288 if(hr != WINED3D_OK) {
5289 ERR("Can't get the swapchain\n");
5290 return hr;
5293 /* Make sure to release the swapchain */
5294 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5296 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5297 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5298 return WINED3DERR_INVALIDCALL;
5300 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5301 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5302 return WINED3DERR_INVALIDCALL;
5305 if(Swapchain->frontBuffer != Front) {
5306 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5308 if(Swapchain->frontBuffer)
5309 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5310 Swapchain->frontBuffer = Front;
5312 if(Swapchain->frontBuffer) {
5313 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5317 if(Back && !Swapchain->backBuffer) {
5318 /* We need memory for the back buffer array - only one back buffer this way */
5319 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5320 if(!Swapchain->backBuffer) {
5321 ERR("Out of memory\n");
5322 return E_OUTOFMEMORY;
5326 if(Swapchain->backBuffer[0] != Back) {
5327 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5329 /* What to do about the context here in the case of multithreading? Not sure.
5330 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5332 ENTER_GL();
5333 if(!Swapchain->backBuffer[0]) {
5334 /* GL was told to draw to the front buffer at creation,
5335 * undo that
5337 glDrawBuffer(GL_BACK);
5338 checkGLcall("glDrawBuffer(GL_BACK)");
5339 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5340 Swapchain->presentParms.BackBufferCount = 1;
5341 } else if (!Back) {
5342 /* That makes problems - disable for now */
5343 /* glDrawBuffer(GL_FRONT); */
5344 checkGLcall("glDrawBuffer(GL_FRONT)");
5345 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5346 Swapchain->presentParms.BackBufferCount = 0;
5348 LEAVE_GL();
5350 if(Swapchain->backBuffer[0])
5351 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5352 Swapchain->backBuffer[0] = Back;
5354 if(Swapchain->backBuffer[0]) {
5355 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5356 } else {
5357 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5362 return WINED3D_OK;
5365 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5367 *ppZStencilSurface = This->depthStencilBuffer;
5368 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5370 if(*ppZStencilSurface != NULL) {
5371 /* Note inc ref on returned surface */
5372 IWineD3DSurface_AddRef(*ppZStencilSurface);
5374 return WINED3D_OK;
5377 /* TODO: Handle stencil attachments */
5378 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5380 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5382 TRACE("Set depth stencil to %p\n", depth_stencil);
5384 if (depth_stencil_impl) {
5385 if (depth_stencil_impl->current_renderbuffer) {
5386 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5387 checkGLcall("glFramebufferRenderbufferEXT()");
5388 } else {
5389 IWineD3DBaseTextureImpl *texture_impl;
5390 GLenum texttarget, target;
5391 GLint old_binding = 0;
5393 texttarget = depth_stencil_impl->glDescription.target;
5394 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5395 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5397 IWineD3DSurface_PreLoad(depth_stencil);
5399 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5400 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5401 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5402 glBindTexture(target, old_binding);
5404 /* Update base texture states array */
5405 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5406 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5407 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5408 if (texture_impl->baseTexture.bindCount) {
5409 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5412 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5415 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5416 checkGLcall("glFramebufferTexture2DEXT()");
5418 } else {
5419 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5420 checkGLcall("glFramebufferTexture2DEXT()");
5424 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5426 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5428 TRACE("Set render target %u to %p\n", idx, render_target);
5430 if (rtimpl) {
5431 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5432 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5433 } else {
5434 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5435 checkGLcall("glFramebufferTexture2DEXT()");
5437 This->draw_buffers[idx] = GL_NONE;
5441 static void check_fbo_status(IWineD3DDevice *iface) {
5442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5443 GLenum status;
5445 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5446 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5447 TRACE("FBO complete\n");
5448 } else {
5449 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5451 /* Dump the FBO attachments */
5452 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5453 IWineD3DSurfaceImpl *attachment;
5454 int i;
5456 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5457 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5458 if (attachment) {
5459 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5460 attachment->pow2Width, attachment->pow2Height);
5463 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5464 if (attachment) {
5465 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5466 attachment->pow2Width, attachment->pow2Height);
5472 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5475 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5477 if (!ds_impl) return FALSE;
5479 if (ds_impl->current_renderbuffer) {
5480 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5481 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5484 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5485 rt_impl->pow2Height != ds_impl->pow2Height);
5488 void apply_fbo_state(IWineD3DDevice *iface) {
5489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5490 unsigned int i;
5492 if (This->render_offscreen) {
5493 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5495 /* Apply render targets */
5496 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5497 IWineD3DSurface *render_target = This->render_targets[i];
5498 if (This->fbo_color_attachments[i] != render_target) {
5499 set_render_target_fbo(iface, i, render_target);
5500 This->fbo_color_attachments[i] = render_target;
5504 /* Apply depth targets */
5505 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5506 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5507 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5509 if (This->stencilBufferTarget) {
5510 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5512 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5513 This->fbo_depth_attachment = This->stencilBufferTarget;
5516 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5517 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5518 checkGLcall("glDrawBuffers()");
5519 } else {
5520 glDrawBuffer(This->draw_buffers[0]);
5521 checkGLcall("glDrawBuffer()");
5523 } else {
5524 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5527 check_fbo_status(iface);
5530 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5531 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5533 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5534 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5535 GLenum gl_filter;
5537 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5538 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5539 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5540 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5542 switch (filter) {
5543 case WINED3DTEXF_LINEAR:
5544 gl_filter = GL_LINEAR;
5545 break;
5547 default:
5548 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5549 case WINED3DTEXF_NONE:
5550 case WINED3DTEXF_POINT:
5551 gl_filter = GL_NEAREST;
5552 break;
5555 /* Attach src surface to src fbo */
5556 src_swapchain = get_swapchain(src_surface);
5557 ENTER_GL();
5558 if (src_swapchain) {
5559 GLenum buffer;
5561 TRACE("Source surface %p is onscreen\n", src_surface);
5562 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5564 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5565 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5566 glReadBuffer(buffer);
5567 checkGLcall("glReadBuffer()");
5569 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5570 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5571 } else {
5572 TRACE("Source surface %p is offscreen\n", src_surface);
5573 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5574 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5575 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5576 checkGLcall("glReadBuffer()");
5579 /* Attach dst surface to dst fbo */
5580 dst_swapchain = get_swapchain(dst_surface);
5581 if (dst_swapchain) {
5582 GLenum buffer;
5584 TRACE("Destination surface %p is onscreen\n", dst_surface);
5585 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5587 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5588 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5589 glDrawBuffer(buffer);
5590 checkGLcall("glDrawBuffer()");
5592 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5593 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5594 } else {
5595 TRACE("Destination surface %p is offscreen\n", dst_surface);
5597 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5598 if(!src_swapchain) {
5599 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5602 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5603 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5604 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5605 checkGLcall("glDrawBuffer()");
5607 glDisable(GL_SCISSOR_TEST);
5608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5610 if (flip) {
5611 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5612 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5613 checkGLcall("glBlitFramebuffer()");
5614 } else {
5615 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5616 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5617 checkGLcall("glBlitFramebuffer()");
5620 if (This->render_offscreen) {
5621 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5622 } else {
5623 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5624 checkGLcall("glBindFramebuffer()");
5627 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5628 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5629 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5630 glDrawBuffer(GL_BACK);
5631 checkGLcall("glDrawBuffer()");
5633 LEAVE_GL();
5636 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5638 WINED3DVIEWPORT viewport;
5640 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5642 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5643 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5644 return WINED3DERR_INVALIDCALL;
5647 /* MSDN says that null disables the render target
5648 but a device must always be associated with a render target
5649 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5651 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5652 for more details
5654 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5655 FIXME("Trying to set render target 0 to NULL\n");
5656 return WINED3DERR_INVALIDCALL;
5658 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5659 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);
5660 return WINED3DERR_INVALIDCALL;
5663 /* If we are trying to set what we already have, don't bother */
5664 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5665 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5666 return WINED3D_OK;
5668 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5669 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5670 This->render_targets[RenderTargetIndex] = pRenderTarget;
5672 /* Render target 0 is special */
5673 if(RenderTargetIndex == 0) {
5674 /* Finally, reset the viewport as the MSDN states. */
5675 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5676 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5677 viewport.X = 0;
5678 viewport.Y = 0;
5679 viewport.MaxZ = 1.0f;
5680 viewport.MinZ = 0.0f;
5681 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5682 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5683 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5687 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5688 * ctx properly.
5689 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5690 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5692 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5694 return WINED3D_OK;
5697 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5699 HRESULT hr = WINED3D_OK;
5700 IWineD3DSurface *tmp;
5702 TRACE("(%p) Swapping z-buffer\n",This);
5704 if (pNewZStencil == This->stencilBufferTarget) {
5705 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5706 } else {
5707 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5708 * depending on the renter target implementation being used.
5709 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5710 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5711 * stencil buffer and incure an extra memory overhead
5712 ******************************************************/
5714 tmp = This->stencilBufferTarget;
5715 This->stencilBufferTarget = pNewZStencil;
5716 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5717 /* should we be calling the parent or the wined3d surface? */
5718 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5719 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5720 hr = WINED3D_OK;
5722 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5723 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5730 return hr;
5733 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5734 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5736 /* TODO: the use of Impl is deprecated. */
5737 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5738 WINED3DLOCKED_RECT lockedRect;
5740 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5742 /* some basic validation checks */
5743 if(This->cursorTexture) {
5744 ENTER_GL();
5745 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5746 glDeleteTextures(1, &This->cursorTexture);
5747 LEAVE_GL();
5748 This->cursorTexture = 0;
5751 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5752 This->haveHardwareCursor = TRUE;
5753 else
5754 This->haveHardwareCursor = FALSE;
5756 if(pCursorBitmap) {
5757 WINED3DLOCKED_RECT rect;
5759 /* MSDN: Cursor must be A8R8G8B8 */
5760 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5761 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5762 return WINED3DERR_INVALIDCALL;
5765 /* MSDN: Cursor must be smaller than the display mode */
5766 if(pSur->currentDesc.Width > This->ddraw_width ||
5767 pSur->currentDesc.Height > This->ddraw_height) {
5768 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);
5769 return WINED3DERR_INVALIDCALL;
5772 if (!This->haveHardwareCursor) {
5773 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5775 /* Do not store the surface's pointer because the application may
5776 * release it after setting the cursor image. Windows doesn't
5777 * addref the set surface, so we can't do this either without
5778 * creating circular refcount dependencies. Copy out the gl texture
5779 * instead.
5781 This->cursorWidth = pSur->currentDesc.Width;
5782 This->cursorHeight = pSur->currentDesc.Height;
5783 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5785 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5786 char *mem, *bits = (char *)rect.pBits;
5787 GLint intfmt = tableEntry->glInternal;
5788 GLint format = tableEntry->glFormat;
5789 GLint type = tableEntry->glType;
5790 INT height = This->cursorHeight;
5791 INT width = This->cursorWidth;
5792 INT bpp = tableEntry->bpp;
5793 INT i;
5795 /* Reformat the texture memory (pitch and width can be
5796 * different) */
5797 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5798 for(i = 0; i < height; i++)
5799 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5800 IWineD3DSurface_UnlockRect(pCursorBitmap);
5801 ENTER_GL();
5803 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5804 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5805 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5808 /* Make sure that a proper texture unit is selected */
5809 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5810 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5811 checkGLcall("glActiveTextureARB");
5813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5814 /* Create a new cursor texture */
5815 glGenTextures(1, &This->cursorTexture);
5816 checkGLcall("glGenTextures");
5817 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5818 checkGLcall("glBindTexture");
5819 /* Copy the bitmap memory into the cursor texture */
5820 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5821 HeapFree(GetProcessHeap(), 0, mem);
5822 checkGLcall("glTexImage2D");
5824 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5825 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5826 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5829 LEAVE_GL();
5831 else
5833 FIXME("A cursor texture was not returned.\n");
5834 This->cursorTexture = 0;
5837 else
5839 /* Draw a hardware cursor */
5840 ICONINFO cursorInfo;
5841 HCURSOR cursor;
5842 /* Create and clear maskBits because it is not needed for
5843 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5844 * chunks. */
5845 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5846 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5847 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5848 WINED3DLOCK_NO_DIRTY_UPDATE |
5849 WINED3DLOCK_READONLY
5851 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5852 pSur->currentDesc.Height);
5854 cursorInfo.fIcon = FALSE;
5855 cursorInfo.xHotspot = XHotSpot;
5856 cursorInfo.yHotspot = YHotSpot;
5857 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5858 pSur->currentDesc.Height, 1,
5859 1, &maskBits);
5860 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5861 pSur->currentDesc.Height, 1,
5862 32, lockedRect.pBits);
5863 IWineD3DSurface_UnlockRect(pCursorBitmap);
5864 /* Create our cursor and clean up. */
5865 cursor = CreateIconIndirect(&cursorInfo);
5866 SetCursor(cursor);
5867 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5868 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5869 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5870 This->hardwareCursor = cursor;
5871 HeapFree(GetProcessHeap(), 0, maskBits);
5875 This->xHotSpot = XHotSpot;
5876 This->yHotSpot = YHotSpot;
5877 return WINED3D_OK;
5880 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5882 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5884 This->xScreenSpace = XScreenSpace;
5885 This->yScreenSpace = YScreenSpace;
5887 return;
5891 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5893 BOOL oldVisible = This->bCursorVisible;
5894 POINT pt;
5896 TRACE("(%p) : visible(%d)\n", This, bShow);
5899 * When ShowCursor is first called it should make the cursor appear at the OS's last
5900 * known cursor position. Because of this, some applications just repetitively call
5901 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5903 GetCursorPos(&pt);
5904 This->xScreenSpace = pt.x;
5905 This->yScreenSpace = pt.y;
5907 if (This->haveHardwareCursor) {
5908 This->bCursorVisible = bShow;
5909 if (bShow)
5910 SetCursor(This->hardwareCursor);
5911 else
5912 SetCursor(NULL);
5914 else
5916 if (This->cursorTexture)
5917 This->bCursorVisible = bShow;
5920 return oldVisible;
5923 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5925 TRACE("(%p) : state (%u)\n", This, This->state);
5926 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5927 switch (This->state) {
5928 case WINED3D_OK:
5929 return WINED3D_OK;
5930 case WINED3DERR_DEVICELOST:
5932 ResourceList *resourceList = This->resources;
5933 while (NULL != resourceList) {
5934 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5935 return WINED3DERR_DEVICENOTRESET;
5936 resourceList = resourceList->next;
5938 return WINED3DERR_DEVICELOST;
5940 case WINED3DERR_DRIVERINTERNALERROR:
5941 return WINED3DERR_DRIVERINTERNALERROR;
5944 /* Unknown state */
5945 return WINED3DERR_DRIVERINTERNALERROR;
5949 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5951 /** FIXME: Resource tracking needs to be done,
5952 * The closes we can do to this is set the priorities of all managed textures low
5953 * and then reset them.
5954 ***********************************************************/
5955 FIXME("(%p) : stub\n", This);
5956 return WINED3D_OK;
5959 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5960 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5962 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5963 if(surface->Flags & SFLAG_DIBSECTION) {
5964 /* Release the DC */
5965 SelectObject(surface->hDC, surface->dib.holdbitmap);
5966 DeleteDC(surface->hDC);
5967 /* Release the DIB section */
5968 DeleteObject(surface->dib.DIBsection);
5969 surface->dib.bitmap_data = NULL;
5970 surface->resource.allocatedMemory = NULL;
5971 surface->Flags &= ~SFLAG_DIBSECTION;
5973 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5974 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5975 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5976 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5977 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5978 } else {
5979 surface->pow2Width = surface->pow2Height = 1;
5980 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5981 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5983 if(surface->glDescription.textureName) {
5984 ENTER_GL();
5985 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5986 glDeleteTextures(1, &surface->glDescription.textureName);
5987 LEAVE_GL();
5988 surface->glDescription.textureName = 0;
5989 surface->Flags &= ~SFLAG_CLIENT;
5991 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5992 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5993 surface->Flags |= SFLAG_NONPOW2;
5994 } else {
5995 surface->Flags &= ~SFLAG_NONPOW2;
5997 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5998 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6001 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6003 IWineD3DSwapChainImpl *swapchain;
6004 HRESULT hr;
6005 BOOL DisplayModeChanged = FALSE;
6006 WINED3DDISPLAYMODE mode;
6007 TRACE("(%p)\n", This);
6009 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6010 if(FAILED(hr)) {
6011 ERR("Failed to get the first implicit swapchain\n");
6012 return hr;
6015 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6016 * on an existing gl context, so there's no real need for recreation.
6018 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6020 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6022 TRACE("New params:\n");
6023 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6024 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6025 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6026 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6027 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6028 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6029 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6030 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6031 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6032 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6033 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6034 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6035 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6037 /* No special treatment of these parameters. Just store them */
6038 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6039 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6040 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6041 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6043 /* What to do about these? */
6044 if(pPresentationParameters->BackBufferCount != 0 &&
6045 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6046 ERR("Cannot change the back buffer count yet\n");
6048 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6049 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6050 ERR("Cannot change the back buffer format yet\n");
6052 if(pPresentationParameters->hDeviceWindow != NULL &&
6053 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6054 ERR("Cannot change the device window yet\n");
6056 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6057 ERR("What do do about a changed auto depth stencil parameter?\n");
6060 if(pPresentationParameters->Windowed) {
6061 mode.Width = swapchain->orig_width;
6062 mode.Height = swapchain->orig_height;
6063 mode.RefreshRate = 0;
6064 mode.Format = swapchain->presentParms.BackBufferFormat;
6065 } else {
6066 mode.Width = pPresentationParameters->BackBufferWidth;
6067 mode.Height = pPresentationParameters->BackBufferHeight;
6068 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6069 mode.Format = swapchain->presentParms.BackBufferFormat;
6072 /* Should Width == 800 && Height == 0 set 800x600? */
6073 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6074 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6075 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6077 WINED3DVIEWPORT vp;
6078 int i;
6080 vp.X = 0;
6081 vp.Y = 0;
6082 vp.Width = pPresentationParameters->BackBufferWidth;
6083 vp.Height = pPresentationParameters->BackBufferHeight;
6084 vp.MinZ = 0;
6085 vp.MaxZ = 1;
6087 if(!pPresentationParameters->Windowed) {
6088 DisplayModeChanged = TRUE;
6090 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6091 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6093 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6094 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6095 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6098 /* Now set the new viewport */
6099 IWineD3DDevice_SetViewport(iface, &vp);
6102 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6103 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6104 DisplayModeChanged) {
6106 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6107 if(!pPresentationParameters->Windowed) {
6108 IWineD3DDevice_SetFullscreen(iface, TRUE);
6111 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6113 /* Switching out of fullscreen mode? First set the original res, then change the window */
6114 if(pPresentationParameters->Windowed) {
6115 IWineD3DDevice_SetFullscreen(iface, FALSE);
6117 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6120 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6121 return WINED3D_OK;
6124 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6126 /** FIXME: always true at the moment **/
6127 if(!bEnableDialogs) {
6128 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6130 return WINED3D_OK;
6134 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6136 TRACE("(%p) : pParameters %p\n", This, pParameters);
6138 *pParameters = This->createParms;
6139 return WINED3D_OK;
6142 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6143 IWineD3DSwapChain *swapchain;
6144 HRESULT hrc = WINED3D_OK;
6146 TRACE("Relaying to swapchain\n");
6148 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6149 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6150 IWineD3DSwapChain_Release(swapchain);
6152 return;
6155 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6156 IWineD3DSwapChain *swapchain;
6157 HRESULT hrc = WINED3D_OK;
6159 TRACE("Relaying to swapchain\n");
6161 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6162 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6163 IWineD3DSwapChain_Release(swapchain);
6165 return;
6169 /** ********************************************************
6170 * Notification functions
6171 ** ********************************************************/
6172 /** This function must be called in the release of a resource when ref == 0,
6173 * the contents of resource must still be correct,
6174 * any handels to other resource held by the caller must be closed
6175 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6176 *****************************************************/
6177 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6179 ResourceList* resourceList;
6181 TRACE("(%p) : resource %p\n", This, resource);
6182 /* add a new texture to the frot of the linked list */
6183 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6184 resourceList->resource = resource;
6186 /* Get the old head */
6187 resourceList->next = This->resources;
6189 This->resources = resourceList;
6190 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6192 return;
6195 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6197 ResourceList* resourceList = NULL;
6198 ResourceList* previousResourceList = NULL;
6200 TRACE("(%p) : resource %p\n", This, resource);
6202 resourceList = This->resources;
6204 while (resourceList != NULL) {
6205 if(resourceList->resource == resource) break;
6206 previousResourceList = resourceList;
6207 resourceList = resourceList->next;
6210 if (resourceList == NULL) {
6211 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6212 return;
6213 } else {
6214 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6216 /* make sure we don't leave a hole in the list */
6217 if (previousResourceList != NULL) {
6218 previousResourceList->next = resourceList->next;
6219 } else {
6220 This->resources = resourceList->next;
6223 return;
6227 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6229 int counter;
6231 TRACE("(%p) : resource %p\n", This, resource);
6232 switch(IWineD3DResource_GetType(resource)){
6233 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6234 case WINED3DRTYPE_SURFACE: {
6235 unsigned int i;
6237 /* Cleanup any FBO attachments */
6238 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6239 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6240 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6241 set_render_target_fbo(iface, i, NULL);
6242 This->fbo_color_attachments[i] = NULL;
6245 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6246 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6247 set_depth_stencil_fbo(iface, NULL);
6248 This->fbo_depth_attachment = NULL;
6251 break;
6254 case WINED3DRTYPE_TEXTURE:
6255 case WINED3DRTYPE_CUBETEXTURE:
6256 case WINED3DRTYPE_VOLUMETEXTURE:
6257 for (counter = 0; counter < MAX_SAMPLERS; counter++) {
6258 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6259 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6260 This->stateBlock->textures[counter] = NULL;
6262 if (This->updateStateBlock != This->stateBlock ){
6263 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6264 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6265 This->updateStateBlock->textures[counter] = NULL;
6269 break;
6270 case WINED3DRTYPE_VOLUME:
6271 /* TODO: nothing really? */
6272 break;
6273 case WINED3DRTYPE_VERTEXBUFFER:
6274 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6276 int streamNumber;
6277 TRACE("Cleaning up stream pointers\n");
6279 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6280 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6281 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6283 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6284 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6285 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6286 This->updateStateBlock->streamSource[streamNumber] = 0;
6287 /* Set changed flag? */
6290 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) */
6291 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6292 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6293 This->stateBlock->streamSource[streamNumber] = 0;
6296 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6297 else { /* This shouldn't happen */
6298 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6300 #endif
6304 break;
6305 case WINED3DRTYPE_INDEXBUFFER:
6306 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6307 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6308 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6309 This->updateStateBlock->pIndexData = NULL;
6312 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6313 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6314 This->stateBlock->pIndexData = NULL;
6318 break;
6319 default:
6320 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6321 break;
6325 /* Remove the resoruce from the resourceStore */
6326 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6328 TRACE("Resource released\n");
6332 /**********************************************************
6333 * IWineD3DDevice VTbl follows
6334 **********************************************************/
6336 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6338 /*** IUnknown methods ***/
6339 IWineD3DDeviceImpl_QueryInterface,
6340 IWineD3DDeviceImpl_AddRef,
6341 IWineD3DDeviceImpl_Release,
6342 /*** IWineD3DDevice methods ***/
6343 IWineD3DDeviceImpl_GetParent,
6344 /*** Creation methods**/
6345 IWineD3DDeviceImpl_CreateVertexBuffer,
6346 IWineD3DDeviceImpl_CreateIndexBuffer,
6347 IWineD3DDeviceImpl_CreateStateBlock,
6348 IWineD3DDeviceImpl_CreateSurface,
6349 IWineD3DDeviceImpl_CreateTexture,
6350 IWineD3DDeviceImpl_CreateVolumeTexture,
6351 IWineD3DDeviceImpl_CreateVolume,
6352 IWineD3DDeviceImpl_CreateCubeTexture,
6353 IWineD3DDeviceImpl_CreateQuery,
6354 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6355 IWineD3DDeviceImpl_CreateVertexDeclaration,
6356 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6357 IWineD3DDeviceImpl_CreateVertexShader,
6358 IWineD3DDeviceImpl_CreatePixelShader,
6359 IWineD3DDeviceImpl_CreatePalette,
6360 /*** Odd functions **/
6361 IWineD3DDeviceImpl_Init3D,
6362 IWineD3DDeviceImpl_Uninit3D,
6363 IWineD3DDeviceImpl_SetFullscreen,
6364 IWineD3DDeviceImpl_SetMultithreaded,
6365 IWineD3DDeviceImpl_EvictManagedResources,
6366 IWineD3DDeviceImpl_GetAvailableTextureMem,
6367 IWineD3DDeviceImpl_GetBackBuffer,
6368 IWineD3DDeviceImpl_GetCreationParameters,
6369 IWineD3DDeviceImpl_GetDeviceCaps,
6370 IWineD3DDeviceImpl_GetDirect3D,
6371 IWineD3DDeviceImpl_GetDisplayMode,
6372 IWineD3DDeviceImpl_SetDisplayMode,
6373 IWineD3DDeviceImpl_GetHWND,
6374 IWineD3DDeviceImpl_SetHWND,
6375 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6376 IWineD3DDeviceImpl_GetRasterStatus,
6377 IWineD3DDeviceImpl_GetSwapChain,
6378 IWineD3DDeviceImpl_Reset,
6379 IWineD3DDeviceImpl_SetDialogBoxMode,
6380 IWineD3DDeviceImpl_SetCursorProperties,
6381 IWineD3DDeviceImpl_SetCursorPosition,
6382 IWineD3DDeviceImpl_ShowCursor,
6383 IWineD3DDeviceImpl_TestCooperativeLevel,
6384 /*** Getters and setters **/
6385 IWineD3DDeviceImpl_SetClipPlane,
6386 IWineD3DDeviceImpl_GetClipPlane,
6387 IWineD3DDeviceImpl_SetClipStatus,
6388 IWineD3DDeviceImpl_GetClipStatus,
6389 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6390 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6391 IWineD3DDeviceImpl_SetDepthStencilSurface,
6392 IWineD3DDeviceImpl_GetDepthStencilSurface,
6393 IWineD3DDeviceImpl_SetFVF,
6394 IWineD3DDeviceImpl_GetFVF,
6395 IWineD3DDeviceImpl_SetGammaRamp,
6396 IWineD3DDeviceImpl_GetGammaRamp,
6397 IWineD3DDeviceImpl_SetIndices,
6398 IWineD3DDeviceImpl_GetIndices,
6399 IWineD3DDeviceImpl_SetBaseVertexIndex,
6400 IWineD3DDeviceImpl_GetBaseVertexIndex,
6401 IWineD3DDeviceImpl_SetLight,
6402 IWineD3DDeviceImpl_GetLight,
6403 IWineD3DDeviceImpl_SetLightEnable,
6404 IWineD3DDeviceImpl_GetLightEnable,
6405 IWineD3DDeviceImpl_SetMaterial,
6406 IWineD3DDeviceImpl_GetMaterial,
6407 IWineD3DDeviceImpl_SetNPatchMode,
6408 IWineD3DDeviceImpl_GetNPatchMode,
6409 IWineD3DDeviceImpl_SetPaletteEntries,
6410 IWineD3DDeviceImpl_GetPaletteEntries,
6411 IWineD3DDeviceImpl_SetPixelShader,
6412 IWineD3DDeviceImpl_GetPixelShader,
6413 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6414 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6415 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6416 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6417 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6418 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6419 IWineD3DDeviceImpl_SetRenderState,
6420 IWineD3DDeviceImpl_GetRenderState,
6421 IWineD3DDeviceImpl_SetRenderTarget,
6422 IWineD3DDeviceImpl_GetRenderTarget,
6423 IWineD3DDeviceImpl_SetFrontBackBuffers,
6424 IWineD3DDeviceImpl_SetSamplerState,
6425 IWineD3DDeviceImpl_GetSamplerState,
6426 IWineD3DDeviceImpl_SetScissorRect,
6427 IWineD3DDeviceImpl_GetScissorRect,
6428 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6429 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6430 IWineD3DDeviceImpl_SetStreamSource,
6431 IWineD3DDeviceImpl_GetStreamSource,
6432 IWineD3DDeviceImpl_SetStreamSourceFreq,
6433 IWineD3DDeviceImpl_GetStreamSourceFreq,
6434 IWineD3DDeviceImpl_SetTexture,
6435 IWineD3DDeviceImpl_GetTexture,
6436 IWineD3DDeviceImpl_SetTextureStageState,
6437 IWineD3DDeviceImpl_GetTextureStageState,
6438 IWineD3DDeviceImpl_SetTransform,
6439 IWineD3DDeviceImpl_GetTransform,
6440 IWineD3DDeviceImpl_SetVertexDeclaration,
6441 IWineD3DDeviceImpl_GetVertexDeclaration,
6442 IWineD3DDeviceImpl_SetVertexShader,
6443 IWineD3DDeviceImpl_GetVertexShader,
6444 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6445 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6446 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6447 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6448 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6449 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6450 IWineD3DDeviceImpl_SetViewport,
6451 IWineD3DDeviceImpl_GetViewport,
6452 IWineD3DDeviceImpl_MultiplyTransform,
6453 IWineD3DDeviceImpl_ValidateDevice,
6454 IWineD3DDeviceImpl_ProcessVertices,
6455 /*** State block ***/
6456 IWineD3DDeviceImpl_BeginStateBlock,
6457 IWineD3DDeviceImpl_EndStateBlock,
6458 /*** Scene management ***/
6459 IWineD3DDeviceImpl_BeginScene,
6460 IWineD3DDeviceImpl_EndScene,
6461 IWineD3DDeviceImpl_Present,
6462 IWineD3DDeviceImpl_Clear,
6463 /*** Drawing ***/
6464 IWineD3DDeviceImpl_DrawPrimitive,
6465 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6466 IWineD3DDeviceImpl_DrawPrimitiveUP,
6467 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6468 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6469 IWineD3DDeviceImpl_DrawRectPatch,
6470 IWineD3DDeviceImpl_DrawTriPatch,
6471 IWineD3DDeviceImpl_DeletePatch,
6472 IWineD3DDeviceImpl_ColorFill,
6473 IWineD3DDeviceImpl_UpdateTexture,
6474 IWineD3DDeviceImpl_UpdateSurface,
6475 IWineD3DDeviceImpl_GetFrontBufferData,
6476 /*** object tracking ***/
6477 IWineD3DDeviceImpl_ResourceReleased
6481 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6482 WINED3DRS_ALPHABLENDENABLE ,
6483 WINED3DRS_ALPHAFUNC ,
6484 WINED3DRS_ALPHAREF ,
6485 WINED3DRS_ALPHATESTENABLE ,
6486 WINED3DRS_BLENDOP ,
6487 WINED3DRS_COLORWRITEENABLE ,
6488 WINED3DRS_DESTBLEND ,
6489 WINED3DRS_DITHERENABLE ,
6490 WINED3DRS_FILLMODE ,
6491 WINED3DRS_FOGDENSITY ,
6492 WINED3DRS_FOGEND ,
6493 WINED3DRS_FOGSTART ,
6494 WINED3DRS_LASTPIXEL ,
6495 WINED3DRS_SHADEMODE ,
6496 WINED3DRS_SRCBLEND ,
6497 WINED3DRS_STENCILENABLE ,
6498 WINED3DRS_STENCILFAIL ,
6499 WINED3DRS_STENCILFUNC ,
6500 WINED3DRS_STENCILMASK ,
6501 WINED3DRS_STENCILPASS ,
6502 WINED3DRS_STENCILREF ,
6503 WINED3DRS_STENCILWRITEMASK ,
6504 WINED3DRS_STENCILZFAIL ,
6505 WINED3DRS_TEXTUREFACTOR ,
6506 WINED3DRS_WRAP0 ,
6507 WINED3DRS_WRAP1 ,
6508 WINED3DRS_WRAP2 ,
6509 WINED3DRS_WRAP3 ,
6510 WINED3DRS_WRAP4 ,
6511 WINED3DRS_WRAP5 ,
6512 WINED3DRS_WRAP6 ,
6513 WINED3DRS_WRAP7 ,
6514 WINED3DRS_ZENABLE ,
6515 WINED3DRS_ZFUNC ,
6516 WINED3DRS_ZWRITEENABLE
6519 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6520 WINED3DTSS_ADDRESSW ,
6521 WINED3DTSS_ALPHAARG0 ,
6522 WINED3DTSS_ALPHAARG1 ,
6523 WINED3DTSS_ALPHAARG2 ,
6524 WINED3DTSS_ALPHAOP ,
6525 WINED3DTSS_BUMPENVLOFFSET ,
6526 WINED3DTSS_BUMPENVLSCALE ,
6527 WINED3DTSS_BUMPENVMAT00 ,
6528 WINED3DTSS_BUMPENVMAT01 ,
6529 WINED3DTSS_BUMPENVMAT10 ,
6530 WINED3DTSS_BUMPENVMAT11 ,
6531 WINED3DTSS_COLORARG0 ,
6532 WINED3DTSS_COLORARG1 ,
6533 WINED3DTSS_COLORARG2 ,
6534 WINED3DTSS_COLOROP ,
6535 WINED3DTSS_RESULTARG ,
6536 WINED3DTSS_TEXCOORDINDEX ,
6537 WINED3DTSS_TEXTURETRANSFORMFLAGS
6540 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6541 WINED3DSAMP_ADDRESSU ,
6542 WINED3DSAMP_ADDRESSV ,
6543 WINED3DSAMP_ADDRESSW ,
6544 WINED3DSAMP_BORDERCOLOR ,
6545 WINED3DSAMP_MAGFILTER ,
6546 WINED3DSAMP_MINFILTER ,
6547 WINED3DSAMP_MIPFILTER ,
6548 WINED3DSAMP_MIPMAPLODBIAS ,
6549 WINED3DSAMP_MAXMIPLEVEL ,
6550 WINED3DSAMP_MAXANISOTROPY ,
6551 WINED3DSAMP_SRGBTEXTURE ,
6552 WINED3DSAMP_ELEMENTINDEX
6555 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6556 WINED3DRS_AMBIENT ,
6557 WINED3DRS_AMBIENTMATERIALSOURCE ,
6558 WINED3DRS_CLIPPING ,
6559 WINED3DRS_CLIPPLANEENABLE ,
6560 WINED3DRS_COLORVERTEX ,
6561 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6562 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6563 WINED3DRS_FOGDENSITY ,
6564 WINED3DRS_FOGEND ,
6565 WINED3DRS_FOGSTART ,
6566 WINED3DRS_FOGTABLEMODE ,
6567 WINED3DRS_FOGVERTEXMODE ,
6568 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6569 WINED3DRS_LIGHTING ,
6570 WINED3DRS_LOCALVIEWER ,
6571 WINED3DRS_MULTISAMPLEANTIALIAS ,
6572 WINED3DRS_MULTISAMPLEMASK ,
6573 WINED3DRS_NORMALIZENORMALS ,
6574 WINED3DRS_PATCHEDGESTYLE ,
6575 WINED3DRS_POINTSCALE_A ,
6576 WINED3DRS_POINTSCALE_B ,
6577 WINED3DRS_POINTSCALE_C ,
6578 WINED3DRS_POINTSCALEENABLE ,
6579 WINED3DRS_POINTSIZE ,
6580 WINED3DRS_POINTSIZE_MAX ,
6581 WINED3DRS_POINTSIZE_MIN ,
6582 WINED3DRS_POINTSPRITEENABLE ,
6583 WINED3DRS_RANGEFOGENABLE ,
6584 WINED3DRS_SPECULARMATERIALSOURCE ,
6585 WINED3DRS_TWEENFACTOR ,
6586 WINED3DRS_VERTEXBLEND
6589 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6590 WINED3DTSS_TEXCOORDINDEX ,
6591 WINED3DTSS_TEXTURETRANSFORMFLAGS
6594 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6595 WINED3DSAMP_DMAPOFFSET
6598 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6599 DWORD rep = StateTable[state].representative;
6600 DWORD idx;
6601 BYTE shift;
6602 UINT i;
6603 WineD3DContext *context;
6605 if(!rep) return;
6606 for(i = 0; i < This->numContexts; i++) {
6607 context = This->contexts[i];
6608 if(isStateDirty(context, rep)) continue;
6610 context->dirtyArray[context->numDirtyEntries++] = rep;
6611 idx = rep >> 5;
6612 shift = rep & 0x1f;
6613 context->isStateDirty[idx] |= (1 << shift);