wined3d: Do not set the dynlock flag on all created surfaces.
[wine.git] / dlls / wined3d / device.c
blobd81ea0b6e1fea4818d4279c06590d61bfdcb107c
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; \
143 _basetexture.is_srgb = FALSE; \
144 _basetexture.srgb_mode_change_count = 0; \
147 /**********************************************************
148 * Global variable / Constants follow
149 **********************************************************/
150 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
152 /**********************************************************
153 * IUnknown parts follows
154 **********************************************************/
156 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
161 if (IsEqualGUID(riid, &IID_IUnknown)
162 || IsEqualGUID(riid, &IID_IWineD3DBase)
163 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
164 IUnknown_AddRef(iface);
165 *ppobj = This;
166 return S_OK;
168 *ppobj = NULL;
169 return E_NOINTERFACE;
172 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
174 ULONG refCount = InterlockedIncrement(&This->ref);
176 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
177 return refCount;
180 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
182 ULONG refCount = InterlockedDecrement(&This->ref);
184 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
186 if (!refCount) {
187 if (This->fbo) {
188 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
190 if (This->src_fbo) {
191 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
193 if (This->dst_fbo) {
194 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
197 HeapFree(GetProcessHeap(), 0, This->render_targets);
198 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
199 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
201 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
203 /* TODO: Clean up all the surfaces and textures! */
204 /* NOTE: You must release the parent if the object was created via a callback
205 ** ***************************/
207 /* Release the update stateblock */
208 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
209 if(This->updateStateBlock != This->stateBlock)
210 FIXME("(%p) Something's still holding the Update stateblock\n",This);
212 This->updateStateBlock = NULL;
213 { /* because were not doing proper internal refcounts releasing the primary state block
214 causes recursion with the extra checks in ResourceReleased, to avoid this we have
215 to set this->stateBlock = NULL; first */
216 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
217 This->stateBlock = NULL;
219 /* Release the stateblock */
220 if(IWineD3DStateBlock_Release(stateBlock) > 0){
221 FIXME("(%p) Something's still holding the Update stateblock\n",This);
225 if (This->resources != NULL ) {
226 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
227 dumpResources(This->resources);
230 if(This->contexts) ERR("Context array not freed!\n");
231 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
232 This->haveHardwareCursor = FALSE;
234 IWineD3D_Release(This->wineD3D);
235 This->wineD3D = NULL;
236 HeapFree(GetProcessHeap(), 0, This);
237 TRACE("Freed device %p\n", This);
238 This = NULL;
240 return refCount;
243 /**********************************************************
244 * IWineD3DDevice implementation follows
245 **********************************************************/
246 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
248 *pParent = This->parent;
249 IUnknown_AddRef(This->parent);
250 return WINED3D_OK;
253 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
254 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
255 GLenum error, glUsage;
256 DWORD vboUsage = object->resource.usage;
257 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
258 WARN("Creating a vbo failed once, not trying again\n");
259 return;
262 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
264 ENTER_GL();
265 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
266 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
268 /* Make sure that the gl error is cleared. Do not use checkGLcall
269 * here because checkGLcall just prints a fixme and continues. However,
270 * if an error during VBO creation occurs we can fall back to non-vbo operation
271 * with full functionality(but performance loss)
273 while(glGetError() != GL_NO_ERROR);
275 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
276 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
277 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
278 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
279 * to check if the rhw and color values are in the correct format.
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(object->vbo == 0 || error != GL_NO_ERROR) {
285 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
286 goto error;
289 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
293 goto error;
296 /* Don't use static, because dx apps tend to update the buffer
297 * quite often even if they specify 0 usage. Because we always keep the local copy
298 * we never read from the vbo and can create a write only opengl buffer.
300 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
301 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
302 case WINED3DUSAGE_DYNAMIC:
303 TRACE("Gl usage = GL_STREAM_DRAW\n");
304 glUsage = GL_STREAM_DRAW_ARB;
305 break;
306 case WINED3DUSAGE_WRITEONLY:
307 default:
308 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
309 glUsage = GL_DYNAMIC_DRAW_ARB;
310 break;
313 /* Reserve memory for the buffer. The amount of data won't change
314 * so we are safe with calling glBufferData once with a NULL ptr and
315 * calling glBufferSubData on updates
317 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
318 error = glGetError();
319 if(error != GL_NO_ERROR) {
320 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
321 goto error;
324 LEAVE_GL();
326 return;
327 error:
328 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
329 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
330 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
331 object->vbo = 0;
332 object->Flags |= VBFLAG_VBOCREATEFAIL;
333 LEAVE_GL();
334 return;
337 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
338 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
339 IUnknown *parent) {
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DVertexBufferImpl *object;
342 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
343 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
344 BOOL conv;
346 if(Size == 0) {
347 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
348 *ppVertexBuffer = NULL;
349 return WINED3DERR_INVALIDCALL;
352 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
354 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
355 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
357 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
358 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
360 object->fvf = FVF;
362 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
363 * drawStridedFast (half-life 2).
365 * Basically converting the vertices in the buffer is quite expensive, and observations
366 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
367 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
369 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
370 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
371 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
372 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
373 * dx7 apps.
374 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
375 * more. In this call we can convert dx7 buffers too.
377 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
378 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
379 (dxVersion > 7 || !conv) ) {
380 CreateVBO(object);
382 return WINED3D_OK;
385 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
386 GLenum error, glUsage;
387 TRACE("Creating VBO for Index Buffer %p\n", object);
389 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
390 * restored on the next draw
392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
394 ENTER_GL();
395 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
396 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
398 while(glGetError());
400 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
401 error = glGetError();
402 if(error != GL_NO_ERROR || object->vbo == 0) {
403 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
404 goto out;
407 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
408 error = glGetError();
409 if(error != GL_NO_ERROR) {
410 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
411 goto out;
414 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
415 * copy no readback will be needed
417 glUsage = GL_STATIC_DRAW_ARB;
418 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
419 error = glGetError();
420 if(error != GL_NO_ERROR) {
421 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
422 goto out;
424 LEAVE_GL();
425 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
426 return;
428 out:
429 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
430 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
431 LEAVE_GL();
432 object->vbo = 0;
435 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
436 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
437 HANDLE *sharedHandle, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DIndexBufferImpl *object;
440 TRACE("(%p) Creating index buffer\n", This);
442 /* Allocate the storage for the device */
443 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
445 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
446 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
449 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
450 CreateIndexBufferVBO(This, object);
453 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
454 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
455 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
457 return WINED3D_OK;
460 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
463 IWineD3DStateBlockImpl *object;
464 int i, j;
465 HRESULT temp_result;
467 D3DCREATEOBJECTINSTANCE(object, StateBlock)
468 object->blockType = Type;
470 for(i = 0; i < LIGHTMAP_SIZE; i++) {
471 list_init(&object->lightMap[i]);
474 /* Special case - Used during initialization to produce a placeholder stateblock
475 so other functions called can update a state block */
476 if (Type == WINED3DSBT_INIT) {
477 /* Don't bother increasing the reference count otherwise a device will never
478 be freed due to circular dependencies */
479 return WINED3D_OK;
482 temp_result = allocate_shader_constants(object);
483 if (WINED3D_OK != temp_result)
484 return temp_result;
486 /* Otherwise, might as well set the whole state block to the appropriate values */
487 if (This->stateBlock != NULL)
488 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
489 else
490 memset(object->streamFreq, 1, sizeof(object->streamFreq));
492 /* Reset the ref and type after kludging it */
493 object->wineD3DDevice = This;
494 object->ref = 1;
495 object->blockType = Type;
497 TRACE("Updating changed flags appropriate for type %d\n", Type);
499 if (Type == WINED3DSBT_ALL) {
501 TRACE("ALL => Pretend everything has changed\n");
502 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
504 /* Lights are not part of the changed / set structure */
505 for(j = 0; j < LIGHTMAP_SIZE; j++) {
506 struct list *e;
507 LIST_FOR_EACH(e, &object->lightMap[j]) {
508 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
509 light->changed = TRUE;
510 light->enabledChanged = TRUE;
513 } else if (Type == WINED3DSBT_PIXELSTATE) {
515 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
516 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
518 object->changed.pixelShader = TRUE;
520 /* Pixel Shader Constants */
521 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
522 object->changed.pixelShaderConstantsF[i] = TRUE;
523 for (i = 0; i < MAX_CONST_B; ++i)
524 object->changed.pixelShaderConstantsB[i] = TRUE;
525 for (i = 0; i < MAX_CONST_I; ++i)
526 object->changed.pixelShaderConstantsI[i] = TRUE;
528 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
529 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
531 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
532 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
533 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
536 for (j = 0 ; j < 16; j++) {
537 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
539 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
543 } else if (Type == WINED3DSBT_VERTEXSTATE) {
545 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
546 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
548 object->changed.vertexShader = TRUE;
550 /* Vertex Shader Constants */
551 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
552 object->changed.vertexShaderConstantsF[i] = TRUE;
553 for (i = 0; i < MAX_CONST_B; ++i)
554 object->changed.vertexShaderConstantsB[i] = TRUE;
555 for (i = 0; i < MAX_CONST_I; ++i)
556 object->changed.vertexShaderConstantsI[i] = TRUE;
558 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
559 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
561 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
562 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
563 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
566 for (j = 0 ; j < 16; j++){
567 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
568 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
572 for(j = 0; j < LIGHTMAP_SIZE; j++) {
573 struct list *e;
574 LIST_FOR_EACH(e, &object->lightMap[j]) {
575 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
576 light->changed = TRUE;
577 light->enabledChanged = TRUE;
580 } else {
581 FIXME("Unrecognized state block type %d\n", Type);
584 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
585 return WINED3D_OK;
588 /* ************************************
589 MSDN:
590 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
592 Discard
593 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
595 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.
597 ******************************** */
599 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) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
602 unsigned int pow2Width, pow2Height;
603 unsigned int Size = 1;
604 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
605 TRACE("(%p) Create surface\n",This);
607 /** FIXME: Check ranges on the inputs are valid
608 * MSDN
609 * MultisampleQuality
610 * [in] Quality level. The valid range is between zero and one less than the level
611 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
612 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
613 * values of paired render targets, depth stencil surfaces, and the MultiSample type
614 * must all match.
615 *******************************/
619 * TODO: Discard MSDN
620 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
622 * If this flag is set, the contents of the depth stencil buffer will be
623 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
624 * with a different depth surface.
626 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
627 ***************************/
629 if(MultisampleQuality < 0) {
630 FIXME("Invalid multisample level %d\n", MultisampleQuality);
631 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
634 if(MultisampleQuality > 0) {
635 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
636 MultisampleQuality=0;
639 /** FIXME: Check that the format is supported
640 * by the device.
641 *******************************/
643 /* Non-power2 support */
644 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
645 pow2Width = Width;
646 pow2Height = Height;
647 } else {
648 /* Find the nearest pow2 match */
649 pow2Width = pow2Height = 1;
650 while (pow2Width < Width) pow2Width <<= 1;
651 while (pow2Height < Height) pow2Height <<= 1;
654 if (pow2Width > Width || pow2Height > Height) {
655 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
656 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
657 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
658 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
659 This, Width, Height);
660 return WINED3DERR_NOTAVAILABLE;
664 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
665 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
666 * space!
667 *********************************/
668 if (WINED3DFMT_UNKNOWN == Format) {
669 Size = 0;
670 } else if (Format == WINED3DFMT_DXT1) {
671 /* DXT1 is half byte per pixel */
672 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
674 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
675 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
676 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
677 } else {
678 /* The pitch is a multiple of 4 bytes */
679 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
680 Size *= Height;
683 /** Create and initialise the surface resource **/
684 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
685 /* "Standalone" surface */
686 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
688 object->currentDesc.Width = Width;
689 object->currentDesc.Height = Height;
690 object->currentDesc.MultiSampleType = MultiSample;
691 object->currentDesc.MultiSampleQuality = MultisampleQuality;
693 /* Setup some glformat defaults */
694 object->glDescription.glFormat = tableEntry->glFormat;
695 object->glDescription.glFormatInternal = tableEntry->glInternal;
696 object->glDescription.glType = tableEntry->glType;
698 object->glDescription.textureName = 0;
699 object->glDescription.level = Level;
700 object->glDescription.target = GL_TEXTURE_2D;
702 /* Internal data */
703 object->pow2Width = pow2Width;
704 object->pow2Height = pow2Height;
706 /* Flags */
707 object->Flags = 0;
708 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
709 object->Flags |= Discard ? SFLAG_DISCARD : 0;
710 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
711 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
714 if (WINED3DFMT_UNKNOWN != Format) {
715 object->bytesPerPixel = tableEntry->bpp;
716 } else {
717 object->bytesPerPixel = 0;
720 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
722 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
724 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
725 * this function is too deep to need to care about things like this.
726 * Levels need to be checked too, and possibly Type since they all affect what can be done.
727 * ****************************************/
728 switch(Pool) {
729 case WINED3DPOOL_SCRATCH:
730 if(!Lockable)
731 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
732 "which are mutually exclusive, setting lockable to TRUE\n");
733 Lockable = TRUE;
734 break;
735 case WINED3DPOOL_SYSTEMMEM:
736 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
737 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
738 case WINED3DPOOL_MANAGED:
739 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
740 "Usage of DYNAMIC which are mutually exclusive, not doing "
741 "anything just telling you.\n");
742 break;
743 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
744 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
745 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
746 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
747 break;
748 default:
749 FIXME("(%p) Unknown pool %d\n", This, Pool);
750 break;
753 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
754 FIXME("Trying to create a render target that isn't in the default pool\n");
757 /* mark the texture as dirty so that it gets loaded first time around*/
758 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
759 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
760 This, Width, Height, Format, debug_d3dformat(Format),
761 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
763 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
764 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
765 This->ddraw_primary = (IWineD3DSurface *) object;
767 /* Look at the implementation and set the correct Vtable */
768 switch(Impl) {
769 case SURFACE_OPENGL:
770 /* Nothing to do, it's set already */
771 break;
773 case SURFACE_GDI:
774 object->lpVtbl = &IWineGDISurface_Vtbl;
775 break;
777 default:
778 /* To be sure to catch this */
779 ERR("Unknown requested surface implementation %d!\n", Impl);
780 IWineD3DSurface_Release((IWineD3DSurface *) object);
781 return WINED3DERR_INVALIDCALL;
784 list_init(&object->renderbuffers);
786 /* Call the private setup routine */
787 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
791 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
792 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
793 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
794 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
797 IWineD3DTextureImpl *object;
798 unsigned int i;
799 UINT tmpW;
800 UINT tmpH;
801 HRESULT hr;
802 unsigned int pow2Width;
803 unsigned int pow2Height;
806 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
807 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
808 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
810 /* TODO: It should only be possible to create textures for formats
811 that are reported as supported */
812 if (WINED3DFMT_UNKNOWN >= Format) {
813 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
814 return WINED3DERR_INVALIDCALL;
817 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
818 D3DINITIALIZEBASETEXTURE(object->baseTexture);
819 object->width = Width;
820 object->height = Height;
822 /** Non-power2 support **/
823 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
824 pow2Width = Width;
825 pow2Height = Height;
826 } else {
827 /* Find the nearest pow2 match */
828 pow2Width = pow2Height = 1;
829 while (pow2Width < Width) pow2Width <<= 1;
830 while (pow2Height < Height) pow2Height <<= 1;
833 /** FIXME: add support for real non-power-two if it's provided by the video card **/
834 /* Precalculated scaling for 'faked' non power of two texture coords */
835 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
836 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
837 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
839 /* Calculate levels for mip mapping */
840 if (Levels == 0) {
841 TRACE("calculating levels %d\n", object->baseTexture.levels);
842 object->baseTexture.levels++;
843 tmpW = Width;
844 tmpH = Height;
845 while (tmpW > 1 || tmpH > 1) {
846 tmpW = max(1, tmpW >> 1);
847 tmpH = max(1, tmpH >> 1);
848 object->baseTexture.levels++;
850 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
853 /* Generate all the surfaces */
854 tmpW = Width;
855 tmpH = Height;
856 for (i = 0; i < object->baseTexture.levels; i++)
858 /* use the callback to create the texture surface */
859 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
860 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
861 FIXME("Failed to create surface %p\n", object);
862 /* clean up */
863 object->surfaces[i] = NULL;
864 IWineD3DTexture_Release((IWineD3DTexture *)object);
866 *ppTexture = NULL;
867 return hr;
870 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
871 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
872 /* calculate the next mipmap level */
873 tmpW = max(1, tmpW >> 1);
874 tmpH = max(1, tmpH >> 1);
877 TRACE("(%p) : Created texture %p\n", This, object);
878 return WINED3D_OK;
881 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
882 UINT Width, UINT Height, UINT Depth,
883 UINT Levels, DWORD Usage,
884 WINED3DFORMAT Format, WINED3DPOOL Pool,
885 IWineD3DVolumeTexture **ppVolumeTexture,
886 HANDLE *pSharedHandle, IUnknown *parent,
887 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
890 IWineD3DVolumeTextureImpl *object;
891 unsigned int i;
892 UINT tmpW;
893 UINT tmpH;
894 UINT tmpD;
896 /* TODO: It should only be possible to create textures for formats
897 that are reported as supported */
898 if (WINED3DFMT_UNKNOWN >= Format) {
899 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
900 return WINED3DERR_INVALIDCALL;
903 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
904 D3DINITIALIZEBASETEXTURE(object->baseTexture);
906 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
907 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
909 object->width = Width;
910 object->height = Height;
911 object->depth = Depth;
913 /* Calculate levels for mip mapping */
914 if (Levels == 0) {
915 object->baseTexture.levels++;
916 tmpW = Width;
917 tmpH = Height;
918 tmpD = Depth;
919 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
920 tmpW = max(1, tmpW >> 1);
921 tmpH = max(1, tmpH >> 1);
922 tmpD = max(1, tmpD >> 1);
923 object->baseTexture.levels++;
925 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
928 /* Generate all the surfaces */
929 tmpW = Width;
930 tmpH = Height;
931 tmpD = Depth;
933 for (i = 0; i < object->baseTexture.levels; i++)
935 HRESULT hr;
936 /* Create the volume */
937 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
938 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
940 if(FAILED(hr)) {
941 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
942 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
943 *ppVolumeTexture = NULL;
944 return hr;
947 /* Set its container to this object */
948 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
950 /* calcualte the next mipmap level */
951 tmpW = max(1, tmpW >> 1);
952 tmpH = max(1, tmpH >> 1);
953 tmpD = max(1, tmpD >> 1);
956 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
957 TRACE("(%p) : Created volume texture %p\n", This, object);
958 return WINED3D_OK;
961 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
962 UINT Width, UINT Height, UINT Depth,
963 DWORD Usage,
964 WINED3DFORMAT Format, WINED3DPOOL Pool,
965 IWineD3DVolume** ppVolume,
966 HANDLE* pSharedHandle, IUnknown *parent) {
968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
969 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
970 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
972 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
974 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
975 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
977 object->currentDesc.Width = Width;
978 object->currentDesc.Height = Height;
979 object->currentDesc.Depth = Depth;
980 object->bytesPerPixel = formatDesc->bpp;
982 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
983 object->lockable = TRUE;
984 object->locked = FALSE;
985 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
986 object->dirty = TRUE;
988 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
992 UINT Levels, DWORD Usage,
993 WINED3DFORMAT Format, WINED3DPOOL Pool,
994 IWineD3DCubeTexture **ppCubeTexture,
995 HANDLE *pSharedHandle, IUnknown *parent,
996 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
999 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1000 unsigned int i, j;
1001 UINT tmpW;
1002 HRESULT hr;
1003 unsigned int pow2EdgeLength = EdgeLength;
1005 /* TODO: It should only be possible to create textures for formats
1006 that are reported as supported */
1007 if (WINED3DFMT_UNKNOWN >= Format) {
1008 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1009 return WINED3DERR_INVALIDCALL;
1012 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1013 WARN("(%p) : Tried to create not supported cube texture\n", This);
1014 return WINED3DERR_INVALIDCALL;
1017 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1018 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1020 TRACE("(%p) Create Cube Texture\n", This);
1022 /** Non-power2 support **/
1024 /* Find the nearest pow2 match */
1025 pow2EdgeLength = 1;
1026 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1028 object->edgeLength = EdgeLength;
1029 /* TODO: support for native non-power 2 */
1030 /* Precalculated scaling for 'faked' non power of two texture coords */
1031 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1033 /* Calculate levels for mip mapping */
1034 if (Levels == 0) {
1035 object->baseTexture.levels++;
1036 tmpW = EdgeLength;
1037 while (tmpW > 1) {
1038 tmpW = max(1, tmpW >> 1);
1039 object->baseTexture.levels++;
1041 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1044 /* Generate all the surfaces */
1045 tmpW = EdgeLength;
1046 for (i = 0; i < object->baseTexture.levels; i++) {
1048 /* Create the 6 faces */
1049 for (j = 0; j < 6; j++) {
1051 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1052 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1054 if(hr!= WINED3D_OK) {
1055 /* clean up */
1056 int k;
1057 int l;
1058 for (l = 0; l < j; l++) {
1059 IWineD3DSurface_Release(object->surfaces[j][i]);
1061 for (k = 0; k < i; k++) {
1062 for (l = 0; l < 6; l++) {
1063 IWineD3DSurface_Release(object->surfaces[l][j]);
1067 FIXME("(%p) Failed to create surface\n",object);
1068 HeapFree(GetProcessHeap(),0,object);
1069 *ppCubeTexture = NULL;
1070 return hr;
1072 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1073 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1075 tmpW = max(1, tmpW >> 1);
1078 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1079 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1080 return WINED3D_OK;
1083 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1085 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1086 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1088 /* Just a check to see if we support this type of query */
1089 switch(Type) {
1090 case WINED3DQUERYTYPE_OCCLUSION:
1091 TRACE("(%p) occlusion query\n", This);
1092 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1093 hr = WINED3D_OK;
1094 else
1095 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1096 break;
1098 case WINED3DQUERYTYPE_EVENT:
1099 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1100 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1101 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1103 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1105 hr = WINED3D_OK;
1106 break;
1108 case WINED3DQUERYTYPE_VCACHE:
1109 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1110 case WINED3DQUERYTYPE_VERTEXSTATS:
1111 case WINED3DQUERYTYPE_TIMESTAMP:
1112 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1113 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1114 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1115 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1116 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1117 case WINED3DQUERYTYPE_PIXELTIMINGS:
1118 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1119 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1120 default:
1121 FIXME("(%p) Unhandled query type %d\n", This, Type);
1123 if(NULL == ppQuery || hr != WINED3D_OK) {
1124 return hr;
1127 D3DCREATEOBJECTINSTANCE(object, Query)
1128 object->type = Type;
1129 /* allocated the 'extended' data based on the type of query requested */
1130 switch(Type){
1131 case WINED3DQUERYTYPE_OCCLUSION:
1132 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1133 TRACE("(%p) Allocating data for an occlusion query\n", This);
1134 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1135 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1136 break;
1138 case WINED3DQUERYTYPE_EVENT:
1139 /* TODO: GL_APPLE_fence */
1140 if(GL_SUPPORT(APPLE_FENCE)) {
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1142 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1143 checkGLcall("glGenFencesAPPLE");
1144 } else if(GL_SUPPORT(NV_FENCE)) {
1145 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1146 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1147 checkGLcall("glGenFencesNV");
1149 break;
1151 case WINED3DQUERYTYPE_VCACHE:
1152 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1153 case WINED3DQUERYTYPE_VERTEXSTATS:
1154 case WINED3DQUERYTYPE_TIMESTAMP:
1155 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1156 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1157 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1158 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1159 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1160 case WINED3DQUERYTYPE_PIXELTIMINGS:
1161 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1162 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1163 default:
1164 object->extendedData = 0;
1165 FIXME("(%p) Unhandled query type %d\n",This , Type);
1167 TRACE("(%p) : Created Query %p\n", This, object);
1168 return WINED3D_OK;
1171 /*****************************************************************************
1172 * IWineD3DDeviceImpl_SetupFullscreenWindow
1174 * Helper function that modifies a HWND's Style and ExStyle for proper
1175 * fullscreen use.
1177 * Params:
1178 * iface: Pointer to the IWineD3DDevice interface
1179 * window: Window to setup
1181 *****************************************************************************/
1182 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1185 LONG style, exStyle;
1186 /* Don't do anything if an original style is stored.
1187 * That shouldn't happen
1189 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1190 if (This->style || This->exStyle) {
1191 ERR("(%p): Want to change the window parameters of HWND %p, but "
1192 "another style is stored for restoration afterwards\n", This, window);
1195 /* Get the parameters and save them */
1196 style = GetWindowLongW(window, GWL_STYLE);
1197 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1198 This->style = style;
1199 This->exStyle = exStyle;
1201 /* Filter out window decorations */
1202 style &= ~WS_CAPTION;
1203 style &= ~WS_THICKFRAME;
1204 exStyle &= ~WS_EX_WINDOWEDGE;
1205 exStyle &= ~WS_EX_CLIENTEDGE;
1207 /* Make sure the window is managed, otherwise we won't get keyboard input */
1208 style |= WS_POPUP | WS_SYSMENU;
1210 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1211 This->style, This->exStyle, style, exStyle);
1213 SetWindowLongW(window, GWL_STYLE, style);
1214 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1216 /* Inform the window about the update. */
1217 SetWindowPos(window, HWND_TOP, 0, 0,
1218 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1219 ShowWindow(window, SW_NORMAL);
1222 /*****************************************************************************
1223 * IWineD3DDeviceImpl_RestoreWindow
1225 * Helper function that restores a windows' properties when taking it out
1226 * of fullscreen mode
1228 * Params:
1229 * iface: Pointer to the IWineD3DDevice interface
1230 * window: Window to setup
1232 *****************************************************************************/
1233 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1236 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1237 * switch, do nothing
1239 if (!This->style && !This->exStyle) return;
1241 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1242 This, window, This->style, This->exStyle);
1244 SetWindowLongW(window, GWL_STYLE, This->style);
1245 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1247 /* Delete the old values */
1248 This->style = 0;
1249 This->exStyle = 0;
1251 /* Inform the window about the update */
1252 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1253 0, 0, 0, 0, /* Pos, Size, ignored */
1254 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1257 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1258 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1259 IUnknown* parent,
1260 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1261 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1264 HDC hDc;
1265 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1266 HRESULT hr = WINED3D_OK;
1267 IUnknown *bufferParent;
1268 Display *display;
1270 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1272 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1273 * does a device hold a reference to a swap chain giving them a lifetime of the device
1274 * or does the swap chain notify the device of its destruction.
1275 *******************************/
1277 /* Check the params */
1278 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1279 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1280 return WINED3DERR_INVALIDCALL;
1281 } else if (pPresentationParameters->BackBufferCount > 1) {
1282 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");
1285 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1287 /*********************
1288 * Lookup the window Handle and the relating X window handle
1289 ********************/
1291 /* Setup hwnd we are using, plus which display this equates to */
1292 object->win_handle = pPresentationParameters->hDeviceWindow;
1293 if (!object->win_handle) {
1294 object->win_handle = This->createParms.hFocusWindow;
1297 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1298 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1299 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1300 return WINED3DERR_NOTAVAILABLE;
1302 hDc = GetDC(object->win_handle);
1303 display = get_display(hDc);
1304 ReleaseDC(object->win_handle, hDc);
1305 TRACE("Using a display of %p %p\n", display, hDc);
1307 if (NULL == display || NULL == hDc) {
1308 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1309 return WINED3DERR_NOTAVAILABLE;
1312 if (object->win == 0) {
1313 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1314 return WINED3DERR_NOTAVAILABLE;
1317 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1318 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1319 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1321 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1322 * then the corresponding dimension of the client area of the hDeviceWindow
1323 * (or the focus window, if hDeviceWindow is NULL) is taken.
1324 **********************/
1326 if (pPresentationParameters->Windowed &&
1327 ((pPresentationParameters->BackBufferWidth == 0) ||
1328 (pPresentationParameters->BackBufferHeight == 0))) {
1330 RECT Rect;
1331 GetClientRect(object->win_handle, &Rect);
1333 if (pPresentationParameters->BackBufferWidth == 0) {
1334 pPresentationParameters->BackBufferWidth = Rect.right;
1335 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1337 if (pPresentationParameters->BackBufferHeight == 0) {
1338 pPresentationParameters->BackBufferHeight = Rect.bottom;
1339 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1343 /* Put the correct figures in the presentation parameters */
1344 TRACE("Copying across presentation parameters\n");
1345 object->presentParms = *pPresentationParameters;
1347 TRACE("calling rendertarget CB\n");
1348 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1349 parent,
1350 object->presentParms.BackBufferWidth,
1351 object->presentParms.BackBufferHeight,
1352 object->presentParms.BackBufferFormat,
1353 object->presentParms.MultiSampleType,
1354 object->presentParms.MultiSampleQuality,
1355 TRUE /* Lockable */,
1356 &object->frontBuffer,
1357 NULL /* pShared (always null)*/);
1358 if (object->frontBuffer != NULL) {
1359 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1360 } else {
1361 ERR("Failed to create the front buffer\n");
1362 goto error;
1366 * Create an opengl context for the display visual
1367 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1368 * use different properties after that point in time. FIXME: How to handle when requested format
1369 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1370 * it chooses is identical to the one already being used!
1371 **********************************/
1372 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1374 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1375 if(!object->context)
1376 return E_OUTOFMEMORY;
1377 object->num_contexts = 1;
1379 ENTER_GL();
1380 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1381 LEAVE_GL();
1383 if (!object->context[0]) {
1384 ERR("Failed to create a new context\n");
1385 hr = WINED3DERR_NOTAVAILABLE;
1386 goto error;
1387 } else {
1388 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1389 object->win_handle, object->context[0]->glCtx, object->win);
1392 /*********************
1393 * Windowed / Fullscreen
1394 *******************/
1397 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1398 * so we should really check to see if there is a fullscreen swapchain already
1399 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1400 **************************************/
1402 if (!pPresentationParameters->Windowed) {
1404 DEVMODEW devmode;
1405 HDC hdc;
1406 int bpp = 0;
1407 RECT clip_rc;
1409 /* Get info on the current display setup */
1410 hdc = GetDC(0);
1411 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1412 ReleaseDC(0, hdc);
1414 /* Change the display settings */
1415 memset(&devmode, 0, sizeof(DEVMODEW));
1416 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1417 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1418 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1419 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1420 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1421 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1423 /* For GetDisplayMode */
1424 This->ddraw_width = devmode.dmPelsWidth;
1425 This->ddraw_height = devmode.dmPelsHeight;
1426 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1428 IWineD3DDevice_SetFullscreen(iface, TRUE);
1430 /* And finally clip mouse to our screen */
1431 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1432 ClipCursor(&clip_rc);
1435 /*********************
1436 * Create the back, front and stencil buffers
1437 *******************/
1438 if(object->presentParms.BackBufferCount > 0) {
1439 int i;
1441 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1442 if(!object->backBuffer) {
1443 ERR("Out of memory\n");
1444 hr = E_OUTOFMEMORY;
1445 goto error;
1448 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1449 TRACE("calling rendertarget CB\n");
1450 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1451 parent,
1452 object->presentParms.BackBufferWidth,
1453 object->presentParms.BackBufferHeight,
1454 object->presentParms.BackBufferFormat,
1455 object->presentParms.MultiSampleType,
1456 object->presentParms.MultiSampleQuality,
1457 TRUE /* Lockable */,
1458 &object->backBuffer[i],
1459 NULL /* pShared (always null)*/);
1460 if(hr == WINED3D_OK && object->backBuffer[i]) {
1461 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1462 } else {
1463 ERR("Cannot create new back buffer\n");
1464 goto error;
1466 ENTER_GL();
1467 glDrawBuffer(GL_BACK);
1468 checkGLcall("glDrawBuffer(GL_BACK)");
1469 LEAVE_GL();
1471 } else {
1472 object->backBuffer = NULL;
1474 /* Single buffering - draw to front buffer */
1475 ENTER_GL();
1476 glDrawBuffer(GL_FRONT);
1477 checkGLcall("glDrawBuffer(GL_FRONT)");
1478 LEAVE_GL();
1481 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1482 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1483 TRACE("Creating depth stencil buffer\n");
1484 if (This->depthStencilBuffer == NULL ) {
1485 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1486 parent,
1487 object->presentParms.BackBufferWidth,
1488 object->presentParms.BackBufferHeight,
1489 object->presentParms.AutoDepthStencilFormat,
1490 object->presentParms.MultiSampleType,
1491 object->presentParms.MultiSampleQuality,
1492 FALSE /* FIXME: Discard */,
1493 &This->depthStencilBuffer,
1494 NULL /* pShared (always null)*/ );
1495 if (This->depthStencilBuffer != NULL)
1496 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1499 /** TODO: A check on width, height and multisample types
1500 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1501 ****************************/
1502 object->wantsDepthStencilBuffer = TRUE;
1503 } else {
1504 object->wantsDepthStencilBuffer = FALSE;
1507 TRACE("Created swapchain %p\n", object);
1508 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1509 return WINED3D_OK;
1511 error:
1512 if (object->backBuffer) {
1513 int i;
1514 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1515 if(object->backBuffer[i]) {
1516 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1517 IUnknown_Release(bufferParent); /* once for the get parent */
1518 if (IUnknown_Release(bufferParent) > 0) {
1519 FIXME("(%p) Something's still holding the back buffer\n",This);
1523 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1524 object->backBuffer = NULL;
1526 if(object->context[0])
1527 DestroyContext(This, object->context[0]);
1528 if(object->frontBuffer) {
1529 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1530 IUnknown_Release(bufferParent); /* once for the get parent */
1531 if (IUnknown_Release(bufferParent) > 0) {
1532 FIXME("(%p) Something's still holding the front buffer\n",This);
1535 HeapFree(GetProcessHeap(), 0, object);
1536 return hr;
1539 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1540 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1542 TRACE("(%p)\n", This);
1544 return This->NumberOfSwapChains;
1547 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1549 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1551 if(iSwapChain < This->NumberOfSwapChains) {
1552 *pSwapChain = This->swapchains[iSwapChain];
1553 IWineD3DSwapChain_AddRef(*pSwapChain);
1554 TRACE("(%p) returning %p\n", This, *pSwapChain);
1555 return WINED3D_OK;
1556 } else {
1557 TRACE("Swapchain out of range\n");
1558 *pSwapChain = NULL;
1559 return WINED3DERR_INVALIDCALL;
1563 /*****
1564 * Vertex Declaration
1565 *****/
1566 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1567 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1569 IWineD3DVertexDeclarationImpl *object = NULL;
1570 HRESULT hr = WINED3D_OK;
1572 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1573 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1575 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1577 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1579 return hr;
1582 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1584 unsigned int idx, idx2;
1585 unsigned int offset;
1586 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1587 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1588 BOOL has_blend_idx = has_blend &&
1589 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1590 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1591 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1592 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1593 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1594 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1595 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1597 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1598 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1600 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1601 WINED3DVERTEXELEMENT *elements = NULL;
1603 unsigned int size;
1604 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1605 if (has_blend_idx) num_blends--;
1607 /* Compute declaration size */
1608 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1609 has_psize + has_diffuse + has_specular + num_textures + 1;
1611 /* convert the declaration */
1612 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1613 if (!elements)
1614 return 0;
1616 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1617 idx = 0;
1618 if (has_pos) {
1619 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1620 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1621 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1623 else {
1624 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1625 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1627 elements[idx].UsageIndex = 0;
1628 idx++;
1630 if (has_blend && (num_blends > 0)) {
1631 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1632 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1633 else
1634 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1635 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1636 elements[idx].UsageIndex = 0;
1637 idx++;
1639 if (has_blend_idx) {
1640 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1641 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1642 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1643 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1644 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1645 else
1646 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1647 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1648 elements[idx].UsageIndex = 0;
1649 idx++;
1651 if (has_normal) {
1652 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1653 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1654 elements[idx].UsageIndex = 0;
1655 idx++;
1657 if (has_psize) {
1658 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1659 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1660 elements[idx].UsageIndex = 0;
1661 idx++;
1663 if (has_diffuse) {
1664 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1665 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1666 elements[idx].UsageIndex = 0;
1667 idx++;
1669 if (has_specular) {
1670 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1671 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1672 elements[idx].UsageIndex = 1;
1673 idx++;
1675 for (idx2 = 0; idx2 < num_textures; idx2++) {
1676 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1677 switch (numcoords) {
1678 case WINED3DFVF_TEXTUREFORMAT1:
1679 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1680 break;
1681 case WINED3DFVF_TEXTUREFORMAT2:
1682 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1683 break;
1684 case WINED3DFVF_TEXTUREFORMAT3:
1685 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1686 break;
1687 case WINED3DFVF_TEXTUREFORMAT4:
1688 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1689 break;
1691 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1692 elements[idx].UsageIndex = idx2;
1693 idx++;
1696 /* Now compute offsets, and initialize the rest of the fields */
1697 for (idx = 0, offset = 0; idx < size-1; idx++) {
1698 elements[idx].Stream = 0;
1699 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1700 elements[idx].Offset = offset;
1701 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1704 *ppVertexElements = elements;
1705 return size;
1708 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1709 WINED3DVERTEXELEMENT* elements = NULL;
1710 size_t size;
1711 DWORD hr;
1713 size = ConvertFvfToDeclaration(Fvf, &elements);
1714 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1716 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1717 HeapFree(GetProcessHeap(), 0, elements);
1718 if (hr != S_OK) return hr;
1720 return WINED3D_OK;
1723 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1724 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1726 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1727 HRESULT hr = WINED3D_OK;
1728 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1729 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1731 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1733 if (vertex_declaration) {
1734 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1737 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1739 if (WINED3D_OK != hr) {
1740 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1741 IWineD3DVertexShader_Release(*ppVertexShader);
1742 return WINED3DERR_INVALIDCALL;
1745 return WINED3D_OK;
1748 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1750 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1751 HRESULT hr = WINED3D_OK;
1753 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1754 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1755 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1756 if (WINED3D_OK == hr) {
1757 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1758 } else {
1759 WARN("(%p) : Failed to create pixel shader\n", This);
1762 return hr;
1765 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1767 IWineD3DPaletteImpl *object;
1768 HRESULT hr;
1769 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1771 /* Create the new object */
1772 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1773 if(!object) {
1774 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1775 return E_OUTOFMEMORY;
1778 object->lpVtbl = &IWineD3DPalette_Vtbl;
1779 object->ref = 1;
1780 object->Flags = Flags;
1781 object->parent = Parent;
1782 object->wineD3DDevice = This;
1783 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1785 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1787 if(!object->hpal) {
1788 HeapFree( GetProcessHeap(), 0, object);
1789 return E_OUTOFMEMORY;
1792 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1793 if(FAILED(hr)) {
1794 IWineD3DPalette_Release((IWineD3DPalette *) object);
1795 return hr;
1798 *Palette = (IWineD3DPalette *) object;
1800 return WINED3D_OK;
1803 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1805 IWineD3DSwapChainImpl *swapchain;
1806 DWORD state;
1808 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1809 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1811 /* TODO: Test if OpenGL is compiled in and loaded */
1813 /* Initialize the texture unit mapping to a 1:1 mapping */
1814 for(state = 0; state < MAX_SAMPLERS; state++) {
1815 This->texUnitMap[state] = state;
1817 This->oneToOneTexUnitMap = TRUE;
1819 /* Setup the implicit swapchain */
1820 TRACE("Creating implicit swapchain\n");
1821 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1822 WARN("Failed to create implicit swapchain\n");
1823 return WINED3DERR_INVALIDCALL;
1826 This->NumberOfSwapChains = 1;
1827 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1828 if(!This->swapchains) {
1829 ERR("Out of memory!\n");
1830 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1831 return E_OUTOFMEMORY;
1833 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1835 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1837 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1838 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1839 This->render_targets[0] = swapchain->backBuffer[0];
1840 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1842 else {
1843 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1844 This->render_targets[0] = swapchain->frontBuffer;
1845 This->lastActiveRenderTarget = swapchain->frontBuffer;
1847 IWineD3DSurface_AddRef(This->render_targets[0]);
1848 This->activeContext = swapchain->context[0];
1850 /* Depth Stencil support */
1851 This->stencilBufferTarget = This->depthStencilBuffer;
1852 if (NULL != This->stencilBufferTarget) {
1853 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1856 /* Set up some starting GL setup */
1857 ENTER_GL();
1859 /* Setup all the devices defaults */
1860 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1861 #if 0
1862 IWineD3DImpl_CheckGraphicsMemory();
1863 #endif
1865 { /* Set a default viewport */
1866 WINED3DVIEWPORT vp;
1867 vp.X = 0;
1868 vp.Y = 0;
1869 vp.Width = pPresentationParameters->BackBufferWidth;
1870 vp.Height = pPresentationParameters->BackBufferHeight;
1871 vp.MinZ = 0.0f;
1872 vp.MaxZ = 1.0f;
1873 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1876 /* Initialize the current view state */
1877 This->view_ident = 1;
1878 This->contexts[0]->last_was_rhw = 0;
1879 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1880 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1882 switch(wined3d_settings.offscreen_rendering_mode) {
1883 case ORM_FBO:
1884 case ORM_PBUFFER:
1885 This->offscreenBuffer = GL_BACK;
1886 break;
1888 case ORM_BACKBUFFER:
1890 if(GL_LIMITS(aux_buffers) > 0) {
1891 TRACE("Using auxilliary buffer for offscreen rendering\n");
1892 This->offscreenBuffer = GL_AUX0;
1893 } else {
1894 TRACE("Using back buffer for offscreen rendering\n");
1895 This->offscreenBuffer = GL_BACK;
1900 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1901 LEAVE_GL();
1903 /* Clear the screen */
1904 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1905 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1906 0x00, 1.0, 0);
1908 This->d3d_initialized = TRUE;
1909 return WINED3D_OK;
1912 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1914 int sampler;
1915 uint i;
1916 TRACE("(%p)\n", This);
1918 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1920 ENTER_GL();
1921 /* I don't think that the interface guarants that the device is destroyed from the same thread
1922 * it was created. Thus make sure a context is active for the glDelete* calls
1924 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1925 LEAVE_GL();
1927 /* Delete the pbuffer context if there is any */
1928 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1930 /* Delete the mouse cursor texture */
1931 if(This->cursorTexture) {
1932 ENTER_GL();
1933 glDeleteTextures(1, &This->cursorTexture);
1934 LEAVE_GL();
1935 This->cursorTexture = 0;
1938 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1939 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1942 /* Release the buffers (with sanity checks)*/
1943 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1944 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1945 if(This->depthStencilBuffer != This->stencilBufferTarget)
1946 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1948 This->stencilBufferTarget = NULL;
1950 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1951 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1952 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1954 TRACE("Setting rendertarget to NULL\n");
1955 This->render_targets[0] = NULL;
1957 if (This->depthStencilBuffer) {
1958 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1959 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1961 This->depthStencilBuffer = NULL;
1964 for(i=0; i < This->NumberOfSwapChains; i++) {
1965 TRACE("Releasing the implicit swapchain %d\n", i);
1966 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1967 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1971 HeapFree(GetProcessHeap(), 0, This->swapchains);
1972 This->swapchains = NULL;
1973 This->NumberOfSwapChains = 0;
1975 This->d3d_initialized = FALSE;
1976 return WINED3D_OK;
1979 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1981 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1983 /* Setup the window for fullscreen mode */
1984 if(fullscreen && !This->ddraw_fullscreen) {
1985 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1986 } else if(!fullscreen && This->ddraw_fullscreen) {
1987 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1990 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1991 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1992 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1993 * separately.
1995 This->ddraw_fullscreen = fullscreen;
1998 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1999 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2000 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2002 * There is no way to deactivate thread safety once it is enabled
2004 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 FIXME("No thread safety in wined3d yet\n");
2008 /*For now just store the flag(needed in case of ddraw) */
2009 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2011 return;
2014 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2015 DEVMODEW devmode;
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2017 LONG ret;
2018 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2019 RECT clip_rc;
2021 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2023 /* Resize the screen even without a window:
2024 * The app could have unset it with SetCooperativeLevel, but not called
2025 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2026 * but we don't have any hwnd
2029 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2030 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2031 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2032 devmode.dmPelsWidth = pMode->Width;
2033 devmode.dmPelsHeight = pMode->Height;
2035 devmode.dmDisplayFrequency = pMode->RefreshRate;
2036 if (pMode->RefreshRate != 0) {
2037 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2040 /* Only change the mode if necessary */
2041 if( (This->ddraw_width == pMode->Width) &&
2042 (This->ddraw_height == pMode->Height) &&
2043 (This->ddraw_format == pMode->Format) &&
2044 (pMode->RefreshRate == 0) ) {
2045 return WINED3D_OK;
2048 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2049 if (ret != DISP_CHANGE_SUCCESSFUL) {
2050 if(devmode.dmDisplayFrequency != 0) {
2051 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2052 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2053 devmode.dmDisplayFrequency = 0;
2054 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2056 if(ret != DISP_CHANGE_SUCCESSFUL) {
2057 return WINED3DERR_NOTAVAILABLE;
2061 /* Store the new values */
2062 This->ddraw_width = pMode->Width;
2063 This->ddraw_height = pMode->Height;
2064 This->ddraw_format = pMode->Format;
2066 /* Only do this with a window of course */
2067 if(This->ddraw_window)
2068 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2070 /* And finally clip mouse to our screen */
2071 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2072 ClipCursor(&clip_rc);
2074 return WINED3D_OK;
2077 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2079 *ppD3D= This->wineD3D;
2080 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2081 IWineD3D_AddRef(*ppD3D);
2082 return WINED3D_OK;
2085 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2086 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2087 * into the video ram as possible and seeing how many fit
2088 * you can also get the correct initial value from nvidia and ATI's driver via X
2089 * texture memory is video memory + AGP memory
2090 *******************/
2091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2092 static BOOL showfixmes = TRUE;
2093 if (showfixmes) {
2094 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2095 (wined3d_settings.emulated_textureram/(1024*1024)),
2096 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2097 showfixmes = FALSE;
2099 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2100 (wined3d_settings.emulated_textureram/(1024*1024)),
2101 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2102 /* return simulated texture memory left */
2103 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2108 /*****
2109 * Get / Set FVF
2110 *****/
2111 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2114 /* Update the current state block */
2115 This->updateStateBlock->changed.fvf = TRUE;
2116 This->updateStateBlock->set.fvf = TRUE;
2118 if(This->updateStateBlock->fvf == fvf) {
2119 TRACE("Application is setting the old fvf over, nothing to do\n");
2120 return WINED3D_OK;
2123 This->updateStateBlock->fvf = fvf;
2124 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2126 return WINED3D_OK;
2130 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2132 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2133 *pfvf = This->stateBlock->fvf;
2134 return WINED3D_OK;
2137 /*****
2138 * Get / Set Stream Source
2139 *****/
2140 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2142 IWineD3DVertexBuffer *oldSrc;
2144 if (StreamNumber >= MAX_STREAMS) {
2145 WARN("Stream out of range %d\n", StreamNumber);
2146 return WINED3DERR_INVALIDCALL;
2149 oldSrc = This->stateBlock->streamSource[StreamNumber];
2150 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2152 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2153 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2155 if(oldSrc == pStreamData &&
2156 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2157 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2158 TRACE("Application is setting the old values over, nothing to do\n");
2159 return WINED3D_OK;
2162 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2163 if (pStreamData) {
2164 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2165 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2168 /* Handle recording of state blocks */
2169 if (This->isRecordingState) {
2170 TRACE("Recording... not performing anything\n");
2171 return WINED3D_OK;
2174 /* Need to do a getParent and pass the reffs up */
2175 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2176 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2177 so for now, just count internally */
2178 if (pStreamData != NULL) {
2179 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2180 InterlockedIncrement(&vbImpl->bindCount);
2182 if (oldSrc != NULL) {
2183 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2188 return WINED3D_OK;
2191 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2194 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2195 This->stateBlock->streamSource[StreamNumber],
2196 This->stateBlock->streamOffset[StreamNumber],
2197 This->stateBlock->streamStride[StreamNumber]);
2199 if (StreamNumber >= MAX_STREAMS) {
2200 WARN("Stream out of range %d\n", StreamNumber);
2201 return WINED3DERR_INVALIDCALL;
2203 *pStream = This->stateBlock->streamSource[StreamNumber];
2204 *pStride = This->stateBlock->streamStride[StreamNumber];
2205 if (pOffset) {
2206 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2209 if (*pStream != NULL) {
2210 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2212 return WINED3D_OK;
2215 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2217 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2218 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2220 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2221 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2223 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2224 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2225 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2227 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2228 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2232 return WINED3D_OK;
2235 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2238 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2239 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2241 TRACE("(%p) : returning %d\n", This, *Divider);
2243 return WINED3D_OK;
2246 /*****
2247 * Get / Set & Multiply Transform
2248 *****/
2249 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2252 /* Most of this routine, comments included copied from ddraw tree initially: */
2253 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2255 /* Handle recording of state blocks */
2256 if (This->isRecordingState) {
2257 TRACE("Recording... not performing anything\n");
2258 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2259 This->updateStateBlock->set.transform[d3dts] = TRUE;
2260 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2261 return WINED3D_OK;
2265 * If the new matrix is the same as the current one,
2266 * we cut off any further processing. this seems to be a reasonable
2267 * optimization because as was noticed, some apps (warcraft3 for example)
2268 * tend towards setting the same matrix repeatedly for some reason.
2270 * From here on we assume that the new matrix is different, wherever it matters.
2272 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2273 TRACE("The app is setting the same matrix over again\n");
2274 return WINED3D_OK;
2275 } else {
2276 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2280 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2281 where ViewMat = Camera space, WorldMat = world space.
2283 In OpenGL, camera and world space is combined into GL_MODELVIEW
2284 matrix. The Projection matrix stay projection matrix.
2287 /* Capture the times we can just ignore the change for now */
2288 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2289 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2290 /* Handled by the state manager */
2293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2294 return WINED3D_OK;
2297 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2299 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2300 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2301 return WINED3D_OK;
2304 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2305 WINED3DMATRIX *mat = NULL;
2306 WINED3DMATRIX temp;
2308 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2309 * below means it will be recorded in a state block change, but it
2310 * works regardless where it is recorded.
2311 * If this is found to be wrong, change to StateBlock.
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2314 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2316 if (State < HIGHEST_TRANSFORMSTATE)
2318 mat = &This->updateStateBlock->transforms[State];
2319 } else {
2320 FIXME("Unhandled transform state!!\n");
2323 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2325 /* Apply change via set transform - will reapply to eg. lights this way */
2326 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2329 /*****
2330 * Get / Set Light
2331 *****/
2332 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2333 you can reference any indexes you want as long as that number max are enabled at any
2334 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2335 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2336 but when recording, just build a chain pretty much of commands to be replayed. */
2338 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2339 float rho;
2340 PLIGHTINFOEL *object = NULL;
2341 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2342 struct list *e;
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2347 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2348 * the gl driver.
2350 if(!pLight) {
2351 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2352 return WINED3DERR_INVALIDCALL;
2355 switch(pLight->Type) {
2356 case WINED3DLIGHT_POINT:
2357 case WINED3DLIGHT_SPOT:
2358 case WINED3DLIGHT_PARALLELPOINT:
2359 case WINED3DLIGHT_GLSPOT:
2360 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2361 * most wanted
2363 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2364 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2365 return WINED3DERR_INVALIDCALL;
2367 break;
2369 case WINED3DLIGHT_DIRECTIONAL:
2370 /* Ignores attenuation */
2371 break;
2373 default:
2374 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2375 return WINED3DERR_INVALIDCALL;
2378 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2379 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2380 if(object->OriginalIndex == Index) break;
2381 object = NULL;
2384 if(!object) {
2385 TRACE("Adding new light\n");
2386 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2387 if(!object) {
2388 ERR("Out of memory error when allocating a light\n");
2389 return E_OUTOFMEMORY;
2391 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2392 object->glIndex = -1;
2393 object->OriginalIndex = Index;
2394 object->changed = TRUE;
2397 /* Initialize the object */
2398 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,
2399 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2400 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2401 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2402 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2403 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2404 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2406 /* Save away the information */
2407 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2409 switch (pLight->Type) {
2410 case WINED3DLIGHT_POINT:
2411 /* Position */
2412 object->lightPosn[0] = pLight->Position.x;
2413 object->lightPosn[1] = pLight->Position.y;
2414 object->lightPosn[2] = pLight->Position.z;
2415 object->lightPosn[3] = 1.0f;
2416 object->cutoff = 180.0f;
2417 /* FIXME: Range */
2418 break;
2420 case WINED3DLIGHT_DIRECTIONAL:
2421 /* Direction */
2422 object->lightPosn[0] = -pLight->Direction.x;
2423 object->lightPosn[1] = -pLight->Direction.y;
2424 object->lightPosn[2] = -pLight->Direction.z;
2425 object->lightPosn[3] = 0.0;
2426 object->exponent = 0.0f;
2427 object->cutoff = 180.0f;
2428 break;
2430 case WINED3DLIGHT_SPOT:
2431 /* Position */
2432 object->lightPosn[0] = pLight->Position.x;
2433 object->lightPosn[1] = pLight->Position.y;
2434 object->lightPosn[2] = pLight->Position.z;
2435 object->lightPosn[3] = 1.0;
2437 /* Direction */
2438 object->lightDirn[0] = pLight->Direction.x;
2439 object->lightDirn[1] = pLight->Direction.y;
2440 object->lightDirn[2] = pLight->Direction.z;
2441 object->lightDirn[3] = 1.0;
2444 * opengl-ish and d3d-ish spot lights use too different models for the
2445 * light "intensity" as a function of the angle towards the main light direction,
2446 * so we only can approximate very roughly.
2447 * however spot lights are rather rarely used in games (if ever used at all).
2448 * furthermore if still used, probably nobody pays attention to such details.
2450 if (pLight->Falloff == 0) {
2451 rho = 6.28f;
2452 } else {
2453 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2455 if (rho < 0.0001) rho = 0.0001f;
2456 object->exponent = -0.3/log(cos(rho/2));
2457 if (object->exponent > 128.0) {
2458 object->exponent = 128.0;
2460 object->cutoff = pLight->Phi*90/M_PI;
2462 /* FIXME: Range */
2463 break;
2465 default:
2466 FIXME("Unrecognized light type %d\n", pLight->Type);
2469 /* Update the live definitions if the light is currently assigned a glIndex */
2470 if (object->glIndex != -1 && !This->isRecordingState) {
2471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2473 return WINED3D_OK;
2476 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2477 PLIGHTINFOEL *lightInfo = NULL;
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2480 struct list *e;
2481 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2483 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2484 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2485 if(lightInfo->OriginalIndex == Index) break;
2486 lightInfo = NULL;
2489 if (lightInfo == NULL) {
2490 TRACE("Light information requested but light not defined\n");
2491 return WINED3DERR_INVALIDCALL;
2494 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2495 return WINED3D_OK;
2498 /*****
2499 * Get / Set Light Enable
2500 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2501 *****/
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2503 PLIGHTINFOEL *lightInfo = NULL;
2504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2505 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2506 struct list *e;
2507 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2509 /* Tests show true = 128...not clear why */
2510 Enable = Enable? 128: 0;
2512 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2513 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2514 if(lightInfo->OriginalIndex == Index) break;
2515 lightInfo = NULL;
2517 TRACE("Found light: %p\n", lightInfo);
2519 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2520 if (lightInfo == NULL) {
2522 TRACE("Light enabled requested but light not defined, so defining one!\n");
2523 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2525 /* Search for it again! Should be fairly quick as near head of list */
2526 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2527 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2528 if(lightInfo->OriginalIndex == Index) break;
2529 lightInfo = NULL;
2531 if (lightInfo == NULL) {
2532 FIXME("Adding default lights has failed dismally\n");
2533 return WINED3DERR_INVALIDCALL;
2537 lightInfo->enabledChanged = TRUE;
2538 if(!Enable) {
2539 if(lightInfo->glIndex != -1) {
2540 if(!This->isRecordingState) {
2541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2544 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2545 lightInfo->glIndex = -1;
2546 } else {
2547 TRACE("Light already disabled, nothing to do\n");
2549 } else {
2550 if (lightInfo->glIndex != -1) {
2551 /* nop */
2552 TRACE("Nothing to do as light was enabled\n");
2553 } else {
2554 int i;
2555 /* Find a free gl light */
2556 for(i = 0; i < This->maxConcurrentLights; i++) {
2557 if(This->stateBlock->activeLights[i] == NULL) {
2558 This->stateBlock->activeLights[i] = lightInfo;
2559 lightInfo->glIndex = i;
2560 break;
2563 if(lightInfo->glIndex == -1) {
2564 ERR("Too many concurrently active lights\n");
2565 return WINED3DERR_INVALIDCALL;
2568 /* i == lightInfo->glIndex */
2569 if(!This->isRecordingState) {
2570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2575 return WINED3D_OK;
2578 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2580 PLIGHTINFOEL *lightInfo = NULL;
2581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2582 struct list *e;
2583 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2584 TRACE("(%p) : for idx(%d)\n", This, Index);
2586 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2587 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2588 if(lightInfo->OriginalIndex == Index) break;
2589 lightInfo = NULL;
2592 if (lightInfo == NULL) {
2593 TRACE("Light enabled state requested but light not defined\n");
2594 return WINED3DERR_INVALIDCALL;
2596 /* true is 128 according to SetLightEnable */
2597 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2598 return WINED3D_OK;
2601 /*****
2602 * Get / Set Clip Planes
2603 *****/
2604 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2606 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2608 /* Validate Index */
2609 if (Index >= GL_LIMITS(clipplanes)) {
2610 TRACE("Application has requested clipplane this device doesn't support\n");
2611 return WINED3DERR_INVALIDCALL;
2614 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2615 This->updateStateBlock->set.clipplane[Index] = TRUE;
2617 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2618 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2619 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2620 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2621 TRACE("Application is setting old values over, nothing to do\n");
2622 return WINED3D_OK;
2625 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2626 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2627 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2628 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2630 /* Handle recording of state blocks */
2631 if (This->isRecordingState) {
2632 TRACE("Recording... not performing anything\n");
2633 return WINED3D_OK;
2636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2638 return WINED3D_OK;
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 TRACE("(%p) : for idx %d\n", This, Index);
2645 /* Validate Index */
2646 if (Index >= GL_LIMITS(clipplanes)) {
2647 TRACE("Application has requested clipplane this device doesn't support\n");
2648 return WINED3DERR_INVALIDCALL;
2651 pPlane[0] = This->stateBlock->clipplane[Index][0];
2652 pPlane[1] = This->stateBlock->clipplane[Index][1];
2653 pPlane[2] = This->stateBlock->clipplane[Index][2];
2654 pPlane[3] = This->stateBlock->clipplane[Index][3];
2655 return WINED3D_OK;
2658 /*****
2659 * Get / Set Clip Plane Status
2660 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2661 *****/
2662 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 FIXME("(%p) : stub\n", This);
2665 if (NULL == pClipStatus) {
2666 return WINED3DERR_INVALIDCALL;
2668 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2669 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2670 return WINED3D_OK;
2673 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 FIXME("(%p) : stub\n", This);
2676 if (NULL == pClipStatus) {
2677 return WINED3DERR_INVALIDCALL;
2679 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2680 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2681 return WINED3D_OK;
2684 /*****
2685 * Get / Set Material
2686 *****/
2687 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2690 This->updateStateBlock->changed.material = TRUE;
2691 This->updateStateBlock->set.material = TRUE;
2692 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2694 /* Handle recording of state blocks */
2695 if (This->isRecordingState) {
2696 TRACE("Recording... not performing anything\n");
2697 return WINED3D_OK;
2700 ENTER_GL();
2701 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2702 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2703 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2704 pMaterial->Ambient.b, pMaterial->Ambient.a);
2705 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2706 pMaterial->Specular.b, pMaterial->Specular.a);
2707 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2708 pMaterial->Emissive.b, pMaterial->Emissive.a);
2709 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2711 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2712 checkGLcall("glMaterialfv(GL_AMBIENT)");
2713 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2714 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2716 /* Only change material color if specular is enabled, otherwise it is set to black */
2717 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2718 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2719 checkGLcall("glMaterialfv(GL_SPECULAR");
2720 } else {
2721 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2722 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2723 checkGLcall("glMaterialfv(GL_SPECULAR");
2725 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2726 checkGLcall("glMaterialfv(GL_EMISSION)");
2727 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2728 checkGLcall("glMaterialf(GL_SHININESS");
2730 LEAVE_GL();
2731 return WINED3D_OK;
2734 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2737 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2738 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2739 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2740 pMaterial->Ambient.b, pMaterial->Ambient.a);
2741 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2742 pMaterial->Specular.b, pMaterial->Specular.a);
2743 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2744 pMaterial->Emissive.b, pMaterial->Emissive.a);
2745 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2747 return WINED3D_OK;
2750 /*****
2751 * Get / Set Indices
2752 *****/
2753 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 IWineD3DIndexBuffer *oldIdxs;
2757 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2758 oldIdxs = This->updateStateBlock->pIndexData;
2760 This->updateStateBlock->changed.indices = TRUE;
2761 This->updateStateBlock->set.indices = TRUE;
2762 This->updateStateBlock->pIndexData = pIndexData;
2764 /* Handle recording of state blocks */
2765 if (This->isRecordingState) {
2766 TRACE("Recording... not performing anything\n");
2767 return WINED3D_OK;
2770 if(oldIdxs != pIndexData) {
2771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2773 return WINED3D_OK;
2776 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2779 *ppIndexData = This->stateBlock->pIndexData;
2781 /* up ref count on ppindexdata */
2782 if (*ppIndexData) {
2783 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2784 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2785 }else{
2786 TRACE("(%p) No index data set\n", This);
2788 TRACE("Returning %p\n", *ppIndexData);
2790 return WINED3D_OK;
2793 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 TRACE("(%p)->(%d)\n", This, BaseIndex);
2798 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2799 TRACE("Application is setting the old value over, nothing to do\n");
2800 return WINED3D_OK;
2803 This->updateStateBlock->baseVertexIndex = BaseIndex;
2805 if (This->isRecordingState) {
2806 TRACE("Recording... not performing anything\n");
2807 return WINED3D_OK;
2809 /* The base vertex index affects the stream sources */
2810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2811 return WINED3D_OK;
2814 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2816 TRACE("(%p) : base_index %p\n", This, base_index);
2818 *base_index = This->stateBlock->baseVertexIndex;
2820 TRACE("Returning %u\n", *base_index);
2822 return WINED3D_OK;
2825 /*****
2826 * Get / Set Viewports
2827 *****/
2828 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2831 TRACE("(%p)\n", This);
2832 This->updateStateBlock->changed.viewport = TRUE;
2833 This->updateStateBlock->set.viewport = TRUE;
2834 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2836 /* Handle recording of state blocks */
2837 if (This->isRecordingState) {
2838 TRACE("Recording... not performing anything\n");
2839 return WINED3D_OK;
2842 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2843 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2846 return WINED3D_OK;
2850 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2852 TRACE("(%p)\n", This);
2853 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2854 return WINED3D_OK;
2857 /*****
2858 * Get / Set Render States
2859 * TODO: Verify against dx9 definitions
2860 *****/
2861 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 DWORD oldValue = This->stateBlock->renderState[State];
2866 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2868 This->updateStateBlock->changed.renderState[State] = TRUE;
2869 This->updateStateBlock->set.renderState[State] = TRUE;
2870 This->updateStateBlock->renderState[State] = Value;
2872 /* Handle recording of state blocks */
2873 if (This->isRecordingState) {
2874 TRACE("Recording... not performing anything\n");
2875 return WINED3D_OK;
2878 /* Compared here and not before the assignment to allow proper stateblock recording */
2879 if(Value == oldValue) {
2880 TRACE("Application is setting the old value over, nothing to do\n");
2881 } else {
2882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2885 return WINED3D_OK;
2888 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2891 *pValue = This->stateBlock->renderState[State];
2892 return WINED3D_OK;
2895 /*****
2896 * Get / Set Sampler States
2897 * TODO: Verify against dx9 definitions
2898 *****/
2900 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2902 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2905 * SetSampler is designed to allow for more than the standard up to 8 textures
2906 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2907 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2909 * http://developer.nvidia.com/object/General_FAQ.html#t6
2911 * There are two new settings for GForce
2912 * the sampler one:
2913 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2914 * and the texture one:
2915 * GL_MAX_TEXTURE_COORDS_ARB.
2916 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2917 ******************/
2919 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2920 debug_d3dsamplerstate(Type), Type, Value);
2921 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2922 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2923 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2925 /* Handle recording of state blocks */
2926 if (This->isRecordingState) {
2927 TRACE("Recording... not performing anything\n");
2928 return WINED3D_OK;
2931 if(oldValue == Value) {
2932 TRACE("Application is setting the old value over, nothing to do\n");
2933 return WINED3D_OK;
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2938 return WINED3D_OK;
2941 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 *Value = This->stateBlock->samplerState[Sampler][Type];
2944 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2946 return WINED3D_OK;
2949 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 This->updateStateBlock->set.scissorRect = TRUE;
2953 This->updateStateBlock->changed.scissorRect = TRUE;
2954 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2955 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2956 return WINED3D_OK;
2958 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2960 if(This->isRecordingState) {
2961 TRACE("Recording... not performing anything\n");
2962 return WINED3D_OK;
2965 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2967 return WINED3D_OK;
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2974 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2980 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2982 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2984 This->updateStateBlock->vertexDecl = pDecl;
2985 This->updateStateBlock->changed.vertexDecl = TRUE;
2986 This->updateStateBlock->set.vertexDecl = TRUE;
2988 if (This->isRecordingState) {
2989 TRACE("Recording... not performing anything\n");
2990 return WINED3D_OK;
2991 } else if(pDecl == oldDecl) {
2992 /* Checked after the assignment to allow proper stateblock recording */
2993 TRACE("Application is setting the old declaration over, nothing to do\n");
2994 return WINED3D_OK;
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3006 *ppDecl = This->stateBlock->vertexDecl;
3007 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3008 return WINED3D_OK;
3011 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3015 This->updateStateBlock->vertexShader = pShader;
3016 This->updateStateBlock->changed.vertexShader = TRUE;
3017 This->updateStateBlock->set.vertexShader = TRUE;
3019 if (This->isRecordingState) {
3020 TRACE("Recording... not performing anything\n");
3021 return WINED3D_OK;
3022 } else if(oldShader == pShader) {
3023 /* Checked here to allow proper stateblock recording */
3024 TRACE("App is setting the old shader over, nothing to do\n");
3025 return WINED3D_OK;
3028 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3032 return WINED3D_OK;
3035 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3038 if (NULL == ppShader) {
3039 return WINED3DERR_INVALIDCALL;
3041 *ppShader = This->stateBlock->vertexShader;
3042 if( NULL != *ppShader)
3043 IWineD3DVertexShader_AddRef(*ppShader);
3045 TRACE("(%p) : returning %p\n", This, *ppShader);
3046 return WINED3D_OK;
3049 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3050 IWineD3DDevice *iface,
3051 UINT start,
3052 CONST BOOL *srcData,
3053 UINT count) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 int i, cnt = min(count, MAX_CONST_B - start);
3058 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3059 iface, srcData, start, count);
3061 if (srcData == NULL || cnt < 0)
3062 return WINED3DERR_INVALIDCALL;
3064 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3065 for (i = 0; i < cnt; i++)
3066 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3068 for (i = start; i < cnt + start; ++i) {
3069 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3070 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3075 return WINED3D_OK;
3078 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3079 IWineD3DDevice *iface,
3080 UINT start,
3081 BOOL *dstData,
3082 UINT count) {
3084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3085 int cnt = min(count, MAX_CONST_B - start);
3087 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3088 iface, dstData, start, count);
3090 if (dstData == NULL || cnt < 0)
3091 return WINED3DERR_INVALIDCALL;
3093 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3094 return WINED3D_OK;
3097 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3098 IWineD3DDevice *iface,
3099 UINT start,
3100 CONST int *srcData,
3101 UINT count) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 int i, cnt = min(count, MAX_CONST_I - start);
3106 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3107 iface, srcData, start, count);
3109 if (srcData == NULL || cnt < 0)
3110 return WINED3DERR_INVALIDCALL;
3112 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3113 for (i = 0; i < cnt; i++)
3114 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3115 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3117 for (i = start; i < cnt + start; ++i) {
3118 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3119 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3124 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3128 IWineD3DDevice *iface,
3129 UINT start,
3130 int *dstData,
3131 UINT count) {
3133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3134 int cnt = min(count, MAX_CONST_I - start);
3136 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3137 iface, dstData, start, count);
3139 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3140 return WINED3DERR_INVALIDCALL;
3142 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3143 return WINED3D_OK;
3146 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3147 IWineD3DDevice *iface,
3148 UINT start,
3149 CONST float *srcData,
3150 UINT count) {
3152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3153 int i;
3155 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3156 iface, srcData, start, count);
3158 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3159 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3160 return WINED3DERR_INVALIDCALL;
3162 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3163 if(TRACE_ON(d3d)) {
3164 for (i = 0; i < count; i++)
3165 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3166 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3169 for (i = start; i < count + start; ++i) {
3170 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3171 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3172 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3173 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3174 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3176 ptr->idx[ptr->count++] = i;
3177 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3179 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3184 return WINED3D_OK;
3187 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3188 IWineD3DDevice *iface,
3189 UINT start,
3190 float *dstData,
3191 UINT count) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3196 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3197 iface, dstData, start, count);
3199 if (dstData == NULL || cnt < 0)
3200 return WINED3DERR_INVALIDCALL;
3202 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3203 return WINED3D_OK;
3206 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3207 DWORD i;
3208 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3213 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3214 DWORD i, tex;
3215 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3216 * it is never called.
3218 * Rules are:
3219 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3220 * that would be really messy and require shader recompilation
3221 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3222 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3223 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3224 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3226 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3227 if(This->oneToOneTexUnitMap) {
3228 TRACE("Not touching 1:1 map\n");
3229 return;
3231 TRACE("Restoring 1:1 texture unit mapping\n");
3232 /* Restore a 1:1 mapping */
3233 for(i = 0; i < MAX_SAMPLERS; i++) {
3234 if(This->texUnitMap[i] != i) {
3235 This->texUnitMap[i] = i;
3236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3237 markTextureStagesDirty(This, i);
3240 This->oneToOneTexUnitMap = TRUE;
3241 return;
3242 } else {
3243 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3244 * First, see if we can succeed at all
3246 tex = 0;
3247 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3248 if(This->stateBlock->textures[i] == NULL) tex++;
3251 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3252 FIXME("Too many bound textures to support the combiner settings\n");
3253 return;
3256 /* Now work out the mapping */
3257 tex = 0;
3258 This->oneToOneTexUnitMap = FALSE;
3259 WARN("Non 1:1 mapping UNTESTED!\n");
3260 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3261 /* Skip NULL textures */
3262 if (!This->stateBlock->textures[i]) {
3263 /* Map to -1, so the check below doesn't fail if a non-NULL
3264 * texture is set on this stage */
3265 TRACE("Mapping texture stage %d to -1\n", i);
3266 This->texUnitMap[i] = -1;
3268 continue;
3271 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3272 if(This->texUnitMap[i] != tex) {
3273 This->texUnitMap[i] = tex;
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3275 markTextureStagesDirty(This, i);
3278 ++tex;
3283 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3284 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3285 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3286 This->updateStateBlock->pixelShader = pShader;
3287 This->updateStateBlock->changed.pixelShader = TRUE;
3288 This->updateStateBlock->set.pixelShader = TRUE;
3290 /* Handle recording of state blocks */
3291 if (This->isRecordingState) {
3292 TRACE("Recording... not performing anything\n");
3295 if (This->isRecordingState) {
3296 TRACE("Recording... not performing anything\n");
3297 return WINED3D_OK;
3300 if(pShader == oldShader) {
3301 TRACE("App is setting the old pixel shader over, nothing to do\n");
3302 return WINED3D_OK;
3305 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3308 /* Rebuild the texture unit mapping if nvrc's are supported */
3309 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3310 IWineD3DDeviceImpl_FindTexUnitMap(This);
3313 return WINED3D_OK;
3316 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3319 if (NULL == ppShader) {
3320 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3321 return WINED3DERR_INVALIDCALL;
3324 *ppShader = This->stateBlock->pixelShader;
3325 if (NULL != *ppShader) {
3326 IWineD3DPixelShader_AddRef(*ppShader);
3328 TRACE("(%p) : returning %p\n", This, *ppShader);
3329 return WINED3D_OK;
3332 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3333 IWineD3DDevice *iface,
3334 UINT start,
3335 CONST BOOL *srcData,
3336 UINT count) {
3338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3339 int i, cnt = min(count, MAX_CONST_B - start);
3341 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3342 iface, srcData, start, count);
3344 if (srcData == NULL || cnt < 0)
3345 return WINED3DERR_INVALIDCALL;
3347 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3348 for (i = 0; i < cnt; i++)
3349 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3351 for (i = start; i < cnt + start; ++i) {
3352 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3353 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3358 return WINED3D_OK;
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3362 IWineD3DDevice *iface,
3363 UINT start,
3364 BOOL *dstData,
3365 UINT count) {
3367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3368 int cnt = min(count, MAX_CONST_B - start);
3370 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3371 iface, dstData, start, count);
3373 if (dstData == NULL || cnt < 0)
3374 return WINED3DERR_INVALIDCALL;
3376 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3377 return WINED3D_OK;
3380 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3381 IWineD3DDevice *iface,
3382 UINT start,
3383 CONST int *srcData,
3384 UINT count) {
3386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 int i, cnt = min(count, MAX_CONST_I - start);
3389 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3390 iface, srcData, start, count);
3392 if (srcData == NULL || cnt < 0)
3393 return WINED3DERR_INVALIDCALL;
3395 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3396 for (i = 0; i < cnt; i++)
3397 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3398 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3400 for (i = start; i < cnt + start; ++i) {
3401 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3402 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3405 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3407 return WINED3D_OK;
3410 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3411 IWineD3DDevice *iface,
3412 UINT start,
3413 int *dstData,
3414 UINT count) {
3416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3417 int cnt = min(count, MAX_CONST_I - start);
3419 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3420 iface, dstData, start, count);
3422 if (dstData == NULL || cnt < 0)
3423 return WINED3DERR_INVALIDCALL;
3425 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3426 return WINED3D_OK;
3429 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3430 IWineD3DDevice *iface,
3431 UINT start,
3432 CONST float *srcData,
3433 UINT count) {
3435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3436 int i;
3438 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3439 iface, srcData, start, count);
3441 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3442 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3443 return WINED3DERR_INVALIDCALL;
3445 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3446 if(TRACE_ON(d3d)) {
3447 for (i = 0; i < count; i++)
3448 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3449 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3452 for (i = start; i < count + start; ++i) {
3453 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3454 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3455 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3456 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3457 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3459 ptr->idx[ptr->count++] = i;
3460 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3462 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3467 return WINED3D_OK;
3470 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3471 IWineD3DDevice *iface,
3472 UINT start,
3473 float *dstData,
3474 UINT count) {
3476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3477 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3479 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3480 iface, dstData, start, count);
3482 if (dstData == NULL || cnt < 0)
3483 return WINED3DERR_INVALIDCALL;
3485 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3486 return WINED3D_OK;
3489 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3490 static HRESULT
3491 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3492 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3493 unsigned int i;
3494 DWORD DestFVF = dest->fvf;
3495 WINED3DVIEWPORT vp;
3496 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3497 BOOL doClip;
3498 int numTextures;
3500 if (lpStrideData->u.s.normal.lpData) {
3501 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3504 if (lpStrideData->u.s.position.lpData == NULL) {
3505 ERR("Source has no position mask\n");
3506 return WINED3DERR_INVALIDCALL;
3509 /* We might access VBOs from this code, so hold the lock */
3510 ENTER_GL();
3512 if (dest->resource.allocatedMemory == NULL) {
3513 /* This may happen if we do direct locking into a vbo. Unlikely,
3514 * but theoretically possible(ddraw processvertices test)
3516 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3517 if(!dest->resource.allocatedMemory) {
3518 LEAVE_GL();
3519 ERR("Out of memory\n");
3520 return E_OUTOFMEMORY;
3522 if(dest->vbo) {
3523 void *src;
3524 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3525 checkGLcall("glBindBufferARB");
3526 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3527 if(src) {
3528 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3530 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3531 checkGLcall("glUnmapBufferARB");
3535 /* Get a pointer into the destination vbo(create one if none exists) and
3536 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3538 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3539 CreateVBO(dest);
3542 if(dest->vbo) {
3543 unsigned char extrabytes = 0;
3544 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3545 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3546 * this may write 4 extra bytes beyond the area that should be written
3548 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3549 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3550 if(!dest_conv_addr) {
3551 ERR("Out of memory\n");
3552 /* Continue without storing converted vertices */
3554 dest_conv = dest_conv_addr;
3557 /* Should I clip?
3558 * a) WINED3DRS_CLIPPING is enabled
3559 * b) WINED3DVOP_CLIP is passed
3561 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3562 static BOOL warned = FALSE;
3564 * The clipping code is not quite correct. Some things need
3565 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3566 * so disable clipping for now.
3567 * (The graphics in Half-Life are broken, and my processvertices
3568 * test crashes with IDirect3DDevice3)
3569 doClip = TRUE;
3571 doClip = FALSE;
3572 if(!warned) {
3573 warned = TRUE;
3574 FIXME("Clipping is broken and disabled for now\n");
3576 } else doClip = FALSE;
3577 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3579 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3580 WINED3DTS_VIEW,
3581 &view_mat);
3582 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3583 WINED3DTS_PROJECTION,
3584 &proj_mat);
3585 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3586 WINED3DTS_WORLDMATRIX(0),
3587 &world_mat);
3589 TRACE("View mat:\n");
3590 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);
3591 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);
3592 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);
3593 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);
3595 TRACE("Proj mat:\n");
3596 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);
3597 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);
3598 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);
3599 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);
3601 TRACE("World mat:\n");
3602 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);
3603 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);
3604 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);
3605 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);
3607 /* Get the viewport */
3608 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3609 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3610 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3612 multiply_matrix(&mat,&view_mat,&world_mat);
3613 multiply_matrix(&mat,&proj_mat,&mat);
3615 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3617 for (i = 0; i < dwCount; i+= 1) {
3618 unsigned int tex_index;
3620 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3621 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3622 /* The position first */
3623 float *p =
3624 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3625 float x, y, z, rhw;
3626 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3628 /* Multiplication with world, view and projection matrix */
3629 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);
3630 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);
3631 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);
3632 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);
3634 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3636 /* WARNING: The following things are taken from d3d7 and were not yet checked
3637 * against d3d8 or d3d9!
3640 /* Clipping conditions: From
3641 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3643 * A vertex is clipped if it does not match the following requirements
3644 * -rhw < x <= rhw
3645 * -rhw < y <= rhw
3646 * 0 < z <= rhw
3647 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3649 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3650 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3654 if( !doClip ||
3655 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3656 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3657 ( rhw > eps ) ) ) {
3659 /* "Normal" viewport transformation (not clipped)
3660 * 1) The values are divided by rhw
3661 * 2) The y axis is negative, so multiply it with -1
3662 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3663 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3664 * 4) Multiply x with Width/2 and add Width/2
3665 * 5) The same for the height
3666 * 6) Add the viewpoint X and Y to the 2D coordinates and
3667 * The minimum Z value to z
3668 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3670 * Well, basically it's simply a linear transformation into viewport
3671 * coordinates
3674 x /= rhw;
3675 y /= rhw;
3676 z /= rhw;
3678 y *= -1;
3680 x *= vp.Width / 2;
3681 y *= vp.Height / 2;
3682 z *= vp.MaxZ - vp.MinZ;
3684 x += vp.Width / 2 + vp.X;
3685 y += vp.Height / 2 + vp.Y;
3686 z += vp.MinZ;
3688 rhw = 1 / rhw;
3689 } else {
3690 /* That vertex got clipped
3691 * Contrary to OpenGL it is not dropped completely, it just
3692 * undergoes a different calculation.
3694 TRACE("Vertex got clipped\n");
3695 x += rhw;
3696 y += rhw;
3698 x /= 2;
3699 y /= 2;
3701 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3702 * outside of the main vertex buffer memory. That needs some more
3703 * investigation...
3707 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3710 ( (float *) dest_ptr)[0] = x;
3711 ( (float *) dest_ptr)[1] = y;
3712 ( (float *) dest_ptr)[2] = z;
3713 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3715 dest_ptr += 3 * sizeof(float);
3717 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3718 dest_ptr += sizeof(float);
3721 if(dest_conv) {
3722 float w = 1 / rhw;
3723 ( (float *) dest_conv)[0] = x * w;
3724 ( (float *) dest_conv)[1] = y * w;
3725 ( (float *) dest_conv)[2] = z * w;
3726 ( (float *) dest_conv)[3] = w;
3728 dest_conv += 3 * sizeof(float);
3730 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3731 dest_conv += sizeof(float);
3735 if (DestFVF & WINED3DFVF_PSIZE) {
3736 dest_ptr += sizeof(DWORD);
3737 if(dest_conv) dest_conv += sizeof(DWORD);
3739 if (DestFVF & WINED3DFVF_NORMAL) {
3740 float *normal =
3741 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3742 /* AFAIK this should go into the lighting information */
3743 FIXME("Didn't expect the destination to have a normal\n");
3744 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3745 if(dest_conv) {
3746 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3750 if (DestFVF & WINED3DFVF_DIFFUSE) {
3751 DWORD *color_d =
3752 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3753 if(!color_d) {
3754 static BOOL warned = FALSE;
3756 if(!warned) {
3757 ERR("No diffuse color in source, but destination has one\n");
3758 warned = TRUE;
3761 *( (DWORD *) dest_ptr) = 0xffffffff;
3762 dest_ptr += sizeof(DWORD);
3764 if(dest_conv) {
3765 *( (DWORD *) dest_conv) = 0xffffffff;
3766 dest_conv += sizeof(DWORD);
3769 else {
3770 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3771 if(dest_conv) {
3772 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3773 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3774 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3775 dest_conv += sizeof(DWORD);
3780 if (DestFVF & WINED3DFVF_SPECULAR) {
3781 /* What's the color value in the feedback buffer? */
3782 DWORD *color_s =
3783 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3784 if(!color_s) {
3785 static BOOL warned = FALSE;
3787 if(!warned) {
3788 ERR("No specular color in source, but destination has one\n");
3789 warned = TRUE;
3792 *( (DWORD *) dest_ptr) = 0xFF000000;
3793 dest_ptr += sizeof(DWORD);
3795 if(dest_conv) {
3796 *( (DWORD *) dest_conv) = 0xFF000000;
3797 dest_conv += sizeof(DWORD);
3800 else {
3801 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3802 if(dest_conv) {
3803 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3804 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3805 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3806 dest_conv += sizeof(DWORD);
3811 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3812 float *tex_coord =
3813 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3814 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3815 if(!tex_coord) {
3816 ERR("No source texture, but destination requests one\n");
3817 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3818 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3820 else {
3821 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3822 if(dest_conv) {
3823 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3829 if(dest_conv) {
3830 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3831 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3832 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3833 dwCount * get_flexible_vertex_size(DestFVF),
3834 dest_conv_addr));
3835 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3836 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3839 LEAVE_GL();
3841 return WINED3D_OK;
3843 #undef copy_and_next
3845 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3847 WineDirect3DVertexStridedData strided;
3848 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3849 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3851 if(pVertexDecl) {
3852 ERR("Output vertex declaration not implemented yet\n");
3855 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3856 * and this call is quite performance critical, so don't call needlessly
3858 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3859 ENTER_GL();
3860 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3861 LEAVE_GL();
3864 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3865 * control the streamIsUP flag, thus restore it afterwards.
3867 This->stateBlock->streamIsUP = FALSE;
3868 memset(&strided, 0, sizeof(strided));
3869 if(This->stateBlock->vertexDecl) {
3870 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3871 } else {
3872 primitiveConvertToStridedData(iface, &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 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4001 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4002 * will call FindTexUnitMap too.
4004 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4005 IWineD3DDeviceImpl_FindTexUnitMap(This);
4007 return WINED3D_OK;
4010 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4012 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4013 *pValue = This->updateStateBlock->textureState[Stage][Type];
4014 return WINED3D_OK;
4017 /*****
4018 * Get / Set Texture
4019 *****/
4020 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4023 IWineD3DBaseTexture *oldTexture;
4025 oldTexture = This->updateStateBlock->textures[Stage];
4026 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4028 #if 0 /* TODO: check so vertex textures */
4029 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4030 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4031 return WINED3D_OK;
4033 #endif
4035 if(pTexture != NULL) {
4036 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4038 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4039 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4040 return WINED3DERR_INVALIDCALL;
4042 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4045 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4046 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4048 This->updateStateBlock->set.textures[Stage] = TRUE;
4049 This->updateStateBlock->changed.textures[Stage] = TRUE;
4050 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4051 This->updateStateBlock->textures[Stage] = pTexture;
4053 /* Handle recording of state blocks */
4054 if (This->isRecordingState) {
4055 TRACE("Recording... not performing anything\n");
4056 return WINED3D_OK;
4059 if(oldTexture == pTexture) {
4060 TRACE("App is setting the same texture again, nothing to do\n");
4061 return WINED3D_OK;
4064 /** NOTE: MSDN says that setTexture increases the reference count,
4065 * and the the application must set the texture back to null (or have a leaky application),
4066 * This means we should pass the refcount up to the parent
4067 *******************************/
4068 if (NULL != This->updateStateBlock->textures[Stage]) {
4069 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4070 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4072 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4073 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4074 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4075 * so the COLOROP and ALPHAOP have to be dirtified.
4077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4078 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4080 if(bindCount == 1) {
4081 new->baseTexture.sampler = Stage;
4083 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4087 if (NULL != oldTexture) {
4088 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4089 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4091 IWineD3DBaseTexture_Release(oldTexture);
4092 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4097 if(bindCount && old->baseTexture.sampler == Stage) {
4098 int i;
4099 /* Have to do a search for the other sampler(s) where the texture is bound to
4100 * Shouldn't happen as long as apps bind a texture only to one stage
4102 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4103 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4104 if(This->updateStateBlock->textures[i] == oldTexture) {
4105 old->baseTexture.sampler = i;
4106 break;
4112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4114 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4115 * pixel shader is used
4117 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4118 IWineD3DDeviceImpl_FindTexUnitMap(This);
4121 return WINED3D_OK;
4124 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4126 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4128 *ppTexture=This->stateBlock->textures[Stage];
4129 if (*ppTexture)
4130 IWineD3DBaseTexture_AddRef(*ppTexture);
4132 return WINED3D_OK;
4135 /*****
4136 * Get Back Buffer
4137 *****/
4138 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4139 IWineD3DSurface **ppBackBuffer) {
4140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4141 IWineD3DSwapChain *swapChain;
4142 HRESULT hr;
4144 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4146 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4147 if (hr == WINED3D_OK) {
4148 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4149 IWineD3DSwapChain_Release(swapChain);
4150 } else {
4151 *ppBackBuffer = NULL;
4153 return hr;
4156 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4158 WARN("(%p) : stub, calling idirect3d for now\n", This);
4159 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4162 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4164 IWineD3DSwapChain *swapChain;
4165 HRESULT hr;
4167 if(iSwapChain > 0) {
4168 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4169 if (hr == WINED3D_OK) {
4170 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4171 IWineD3DSwapChain_Release(swapChain);
4172 } else {
4173 FIXME("(%p) Error getting display mode\n", This);
4175 } else {
4176 /* Don't read the real display mode,
4177 but return the stored mode instead. X11 can't change the color
4178 depth, and some apps are pretty angry if they SetDisplayMode from
4179 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4181 Also don't relay to the swapchain because with ddraw it's possible
4182 that there isn't a swapchain at all */
4183 pMode->Width = This->ddraw_width;
4184 pMode->Height = This->ddraw_height;
4185 pMode->Format = This->ddraw_format;
4186 pMode->RefreshRate = 0;
4187 hr = WINED3D_OK;
4190 return hr;
4193 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4195 TRACE("(%p)->(%p)\n", This, hWnd);
4197 if(This->ddraw_fullscreen) {
4198 if(This->ddraw_window && This->ddraw_window != hWnd) {
4199 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4201 if(hWnd && This->ddraw_window != hWnd) {
4202 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4206 This->ddraw_window = hWnd;
4207 return WINED3D_OK;
4210 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4212 TRACE("(%p)->(%p)\n", This, hWnd);
4214 *hWnd = This->ddraw_window;
4215 return WINED3D_OK;
4218 /*****
4219 * Stateblock related functions
4220 *****/
4222 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4224 IWineD3DStateBlockImpl *object;
4225 HRESULT temp_result;
4226 int i;
4228 TRACE("(%p)\n", This);
4230 if (This->isRecordingState) {
4231 return WINED3DERR_INVALIDCALL;
4234 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4235 if (NULL == object ) {
4236 FIXME("(%p)Error allocating memory for stateblock\n", This);
4237 return E_OUTOFMEMORY;
4239 TRACE("(%p) created object %p\n", This, object);
4240 object->wineD3DDevice= This;
4241 /** FIXME: object->parent = parent; **/
4242 object->parent = NULL;
4243 object->blockType = WINED3DSBT_ALL;
4244 object->ref = 1;
4245 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4247 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4248 list_init(&object->lightMap[i]);
4251 temp_result = allocate_shader_constants(object);
4252 if (WINED3D_OK != temp_result)
4253 return temp_result;
4255 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4256 This->updateStateBlock = object;
4257 This->isRecordingState = TRUE;
4259 TRACE("(%p) recording stateblock %p\n",This , object);
4260 return WINED3D_OK;
4263 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4266 if (!This->isRecordingState) {
4267 FIXME("(%p) not recording! returning error\n", This);
4268 *ppStateBlock = NULL;
4269 return WINED3DERR_INVALIDCALL;
4272 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4273 This->isRecordingState = FALSE;
4274 This->updateStateBlock = This->stateBlock;
4275 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4276 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4277 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4278 return WINED3D_OK;
4281 /*****
4282 * Scene related functions
4283 *****/
4284 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4285 /* At the moment we have no need for any functionality at the beginning
4286 of a scene */
4287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4288 TRACE("(%p)\n", This);
4290 if(This->inScene) {
4291 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4292 return WINED3DERR_INVALIDCALL;
4294 This->inScene = TRUE;
4295 return WINED3D_OK;
4298 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4300 TRACE("(%p)\n", This);
4302 if(!This->inScene) {
4303 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4304 return WINED3DERR_INVALIDCALL;
4307 ENTER_GL();
4308 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4309 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4311 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4312 glFlush();
4313 checkGLcall("glFlush");
4314 LEAVE_GL();
4316 This->inScene = FALSE;
4317 return WINED3D_OK;
4320 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4321 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4322 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4324 IWineD3DSwapChain *swapChain = NULL;
4325 int i;
4326 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4328 TRACE("(%p) Presenting the frame\n", This);
4330 for(i = 0 ; i < swapchains ; i ++) {
4332 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4333 TRACE("presentinng chain %d, %p\n", i, swapChain);
4334 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4335 IWineD3DSwapChain_Release(swapChain);
4338 return WINED3D_OK;
4341 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4342 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4344 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4346 GLbitfield glMask = 0;
4347 unsigned int i;
4348 CONST WINED3DRECT* curRect;
4350 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4351 Count, pRects, Flags, Color, Z, Stencil);
4353 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4354 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4355 /* TODO: What about depth stencil buffers without stencil bits? */
4356 return WINED3DERR_INVALIDCALL;
4359 ENTER_GL();
4360 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4361 * and not the last active one.
4364 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4365 apply_fbo_state(iface);
4368 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4370 glEnable(GL_SCISSOR_TEST);
4371 checkGLcall("glEnable GL_SCISSOR_TEST");
4372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4375 if (Count > 0 && pRects) {
4376 curRect = pRects;
4377 } else {
4378 curRect = NULL;
4381 /* Only set the values up once, as they are not changing */
4382 if (Flags & WINED3DCLEAR_STENCIL) {
4383 glClearStencil(Stencil);
4384 checkGLcall("glClearStencil");
4385 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4386 glStencilMask(0xFFFFFFFF);
4389 if (Flags & WINED3DCLEAR_ZBUFFER) {
4390 glDepthMask(GL_TRUE);
4391 glClearDepth(Z);
4392 checkGLcall("glClearDepth");
4393 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4397 if (Flags & WINED3DCLEAR_TARGET) {
4398 TRACE("Clearing screen with glClear to color %x\n", Color);
4399 glClearColor(D3DCOLOR_R(Color),
4400 D3DCOLOR_G(Color),
4401 D3DCOLOR_B(Color),
4402 D3DCOLOR_A(Color));
4403 checkGLcall("glClearColor");
4405 /* Clear ALL colors! */
4406 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4407 glMask = glMask | GL_COLOR_BUFFER_BIT;
4410 if (!curRect) {
4411 /* In drawable flag is set below */
4413 glScissor(This->stateBlock->viewport.X,
4414 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4415 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4416 This->stateBlock->viewport.Width,
4417 This->stateBlock->viewport.Height);
4418 checkGLcall("glScissor");
4419 glClear(glMask);
4420 checkGLcall("glClear");
4421 } else {
4422 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4423 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4425 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4426 curRect[0].x2 < target->currentDesc.Width ||
4427 curRect[0].y2 < target->currentDesc.Height) {
4428 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4429 blt_to_drawable(This, target);
4433 /* Now process each rect in turn */
4434 for (i = 0; i < Count; i++) {
4435 /* Note gl uses lower left, width/height */
4436 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4437 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4438 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4439 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4441 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4442 * The rectangle is not cleared, no error is returned, but further rectanlges are
4443 * still cleared if they are valid
4445 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4446 TRACE("Rectangle with negative dimensions, ignoring\n");
4447 continue;
4450 if(This->render_offscreen) {
4451 glScissor(curRect[i].x1, curRect[i].y1,
4452 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4453 } else {
4454 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4455 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4457 checkGLcall("glScissor");
4459 glClear(glMask);
4460 checkGLcall("glClear");
4464 /* Restore the old values (why..?) */
4465 if (Flags & WINED3DCLEAR_STENCIL) {
4466 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4468 if (Flags & WINED3DCLEAR_TARGET) {
4469 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4470 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4471 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4472 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4473 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4476 LEAVE_GL();
4478 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4479 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4481 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4482 target->Flags |= SFLAG_INTEXTURE;
4483 target->Flags &= ~SFLAG_INSYSMEM;
4484 } else {
4485 target->Flags |= SFLAG_INDRAWABLE;
4486 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4488 return WINED3D_OK;
4491 /*****
4492 * Drawing functions
4493 *****/
4494 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4495 UINT PrimitiveCount) {
4497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4499 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4500 debug_d3dprimitivetype(PrimitiveType),
4501 StartVertex, PrimitiveCount);
4503 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4504 if(This->stateBlock->streamIsUP) {
4505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4506 This->stateBlock->streamIsUP = FALSE;
4509 if(This->stateBlock->loadBaseVertexIndex != 0) {
4510 This->stateBlock->loadBaseVertexIndex = 0;
4511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4513 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4514 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4515 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4516 return WINED3D_OK;
4519 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4520 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4521 WINED3DPRIMITIVETYPE PrimitiveType,
4522 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 UINT idxStride = 2;
4526 IWineD3DIndexBuffer *pIB;
4527 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4528 GLuint vbo;
4530 pIB = This->stateBlock->pIndexData;
4531 if (!pIB) {
4532 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4533 * without an index buffer set. (The first time at least...)
4534 * D3D8 simply dies, but I doubt it can do much harm to return
4535 * D3DERR_INVALIDCALL there as well. */
4536 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4537 return WINED3DERR_INVALIDCALL;
4540 if(This->stateBlock->streamIsUP) {
4541 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4542 This->stateBlock->streamIsUP = FALSE;
4544 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4546 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4547 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4548 minIndex, NumVertices, startIndex, primCount);
4550 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4551 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4552 idxStride = 2;
4553 } else {
4554 idxStride = 4;
4557 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4558 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4562 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4563 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4565 return WINED3D_OK;
4568 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4569 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4570 UINT VertexStreamZeroStride) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4573 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4574 debug_d3dprimitivetype(PrimitiveType),
4575 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4577 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4578 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4579 This->stateBlock->streamOffset[0] = 0;
4580 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4581 This->stateBlock->streamIsUP = TRUE;
4582 This->stateBlock->loadBaseVertexIndex = 0;
4584 /* TODO: Only mark dirty if drawing from a different UP address */
4585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4587 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4588 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4590 /* MSDN specifies stream zero settings must be set to NULL */
4591 This->stateBlock->streamStride[0] = 0;
4592 This->stateBlock->streamSource[0] = NULL;
4594 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4595 * the new stream sources or use UP drawing again
4597 return WINED3D_OK;
4600 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4601 UINT MinVertexIndex, UINT NumVertices,
4602 UINT PrimitiveCount, CONST void* pIndexData,
4603 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4604 UINT VertexStreamZeroStride) {
4605 int idxStride;
4606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4608 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4609 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4610 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4611 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4613 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4614 idxStride = 2;
4615 } else {
4616 idxStride = 4;
4619 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4620 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4621 This->stateBlock->streamIsUP = TRUE;
4622 This->stateBlock->streamOffset[0] = 0;
4623 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4625 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4626 This->stateBlock->baseVertexIndex = 0;
4627 This->stateBlock->loadBaseVertexIndex = 0;
4628 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4632 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4634 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4635 This->stateBlock->streamSource[0] = NULL;
4636 This->stateBlock->streamStride[0] = 0;
4637 This->stateBlock->pIndexData = NULL;
4638 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4639 * SetStreamSource to specify a vertex buffer
4642 return WINED3D_OK;
4645 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4648 /* Mark the state dirty until we have nicer tracking
4649 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4650 * that value.
4652 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4654 This->stateBlock->baseVertexIndex = 0;
4655 This->up_strided = DrawPrimStrideData;
4656 This->stateBlock->streamIsUP = TRUE;
4657 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4658 This->up_strided = NULL;
4659 return WINED3D_OK;
4661 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4662 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4664 HRESULT hr = WINED3D_OK;
4665 WINED3DRESOURCETYPE sourceType;
4666 WINED3DRESOURCETYPE destinationType;
4667 int i ,levels;
4669 /* TODO: think about moving the code into IWineD3DBaseTexture */
4671 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4673 /* verify that the source and destination textures aren't NULL */
4674 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4675 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4676 This, pSourceTexture, pDestinationTexture);
4677 hr = WINED3DERR_INVALIDCALL;
4680 if (pSourceTexture == pDestinationTexture) {
4681 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4682 This, pSourceTexture, pDestinationTexture);
4683 hr = WINED3DERR_INVALIDCALL;
4685 /* Verify that the source and destination textures are the same type */
4686 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4687 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4689 if (sourceType != destinationType) {
4690 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4691 This);
4692 hr = WINED3DERR_INVALIDCALL;
4695 /* check that both textures have the identical numbers of levels */
4696 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4697 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4698 hr = WINED3DERR_INVALIDCALL;
4701 if (WINED3D_OK == hr) {
4703 /* Make sure that the destination texture is loaded */
4704 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4706 /* Update every surface level of the texture */
4707 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4709 switch (sourceType) {
4710 case WINED3DRTYPE_TEXTURE:
4712 IWineD3DSurface *srcSurface;
4713 IWineD3DSurface *destSurface;
4715 for (i = 0 ; i < levels ; ++i) {
4716 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4717 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4718 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4719 IWineD3DSurface_Release(srcSurface);
4720 IWineD3DSurface_Release(destSurface);
4721 if (WINED3D_OK != hr) {
4722 WARN("(%p) : Call to update surface failed\n", This);
4723 return hr;
4727 break;
4728 case WINED3DRTYPE_CUBETEXTURE:
4730 IWineD3DSurface *srcSurface;
4731 IWineD3DSurface *destSurface;
4732 WINED3DCUBEMAP_FACES faceType;
4734 for (i = 0 ; i < levels ; ++i) {
4735 /* Update each cube face */
4736 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4737 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4738 if (WINED3D_OK != hr) {
4739 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4740 } else {
4741 TRACE("Got srcSurface %p\n", srcSurface);
4743 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4744 if (WINED3D_OK != hr) {
4745 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4746 } else {
4747 TRACE("Got desrSurface %p\n", destSurface);
4749 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4750 IWineD3DSurface_Release(srcSurface);
4751 IWineD3DSurface_Release(destSurface);
4752 if (WINED3D_OK != hr) {
4753 WARN("(%p) : Call to update surface failed\n", This);
4754 return hr;
4759 break;
4760 #if 0 /* TODO: Add support for volume textures */
4761 case WINED3DRTYPE_VOLUMETEXTURE:
4763 IWineD3DVolume srcVolume = NULL;
4764 IWineD3DSurface destVolume = NULL;
4766 for (i = 0 ; i < levels ; ++i) {
4767 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4768 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4769 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4770 IWineD3DVolume_Release(srcSurface);
4771 IWineD3DVolume_Release(destSurface);
4772 if (WINED3D_OK != hr) {
4773 WARN("(%p) : Call to update volume failed\n", This);
4774 return hr;
4778 break;
4779 #endif
4780 default:
4781 FIXME("(%p) : Unsupported source and destination type\n", This);
4782 hr = WINED3DERR_INVALIDCALL;
4786 return hr;
4789 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4790 IWineD3DSwapChain *swapChain;
4791 HRESULT hr;
4792 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4793 if(hr == WINED3D_OK) {
4794 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4795 IWineD3DSwapChain_Release(swapChain);
4797 return hr;
4800 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 /* return a sensible default */
4803 *pNumPasses = 1;
4804 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4805 FIXME("(%p) : stub\n", This);
4806 return WINED3D_OK;
4809 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4811 int j;
4812 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4813 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4814 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4815 return WINED3DERR_INVALIDCALL;
4817 for (j = 0; j < 256; ++j) {
4818 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4819 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4820 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4821 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4823 TRACE("(%p) : returning\n", This);
4824 return WINED3D_OK;
4827 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4829 int j;
4830 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4831 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4832 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4833 return WINED3DERR_INVALIDCALL;
4835 for (j = 0; j < 256; ++j) {
4836 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4837 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4838 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4839 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4841 TRACE("(%p) : returning\n", This);
4842 return WINED3D_OK;
4845 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4847 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4848 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4849 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4850 return WINED3DERR_INVALIDCALL;
4852 /*TODO: stateblocks */
4853 This->currentPalette = PaletteNumber;
4854 TRACE("(%p) : returning\n", This);
4855 return WINED3D_OK;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4860 if (PaletteNumber == NULL) {
4861 WARN("(%p) : returning Invalid Call\n", This);
4862 return WINED3DERR_INVALIDCALL;
4864 /*TODO: stateblocks */
4865 *PaletteNumber = This->currentPalette;
4866 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4867 return WINED3D_OK;
4870 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4872 static BOOL showFixmes = TRUE;
4873 if (showFixmes) {
4874 FIXME("(%p) : stub\n", This);
4875 showFixmes = FALSE;
4878 This->softwareVertexProcessing = bSoftware;
4879 return WINED3D_OK;
4883 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4885 static BOOL showFixmes = TRUE;
4886 if (showFixmes) {
4887 FIXME("(%p) : stub\n", This);
4888 showFixmes = FALSE;
4890 return This->softwareVertexProcessing;
4894 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4896 IWineD3DSwapChain *swapChain;
4897 HRESULT hr;
4899 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4901 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4902 if(hr == WINED3D_OK){
4903 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4904 IWineD3DSwapChain_Release(swapChain);
4905 }else{
4906 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4908 return hr;
4912 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4914 static BOOL showfixmes = TRUE;
4915 if(nSegments != 0.0f) {
4916 if( showfixmes) {
4917 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4918 showfixmes = FALSE;
4921 return WINED3D_OK;
4924 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4926 static BOOL showfixmes = TRUE;
4927 if( showfixmes) {
4928 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4929 showfixmes = FALSE;
4931 return 0.0f;
4934 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4936 /** TODO: remove casts to IWineD3DSurfaceImpl
4937 * NOTE: move code to surface to accomplish this
4938 ****************************************/
4939 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4940 int srcWidth, srcHeight;
4941 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4942 WINED3DFORMAT destFormat, srcFormat;
4943 UINT destSize;
4944 int srcLeft, destLeft, destTop;
4945 WINED3DPOOL srcPool, destPool;
4946 int offset = 0;
4947 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4948 glDescriptor *glDescription = NULL;
4950 WINED3DSURFACE_DESC winedesc;
4952 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4953 memset(&winedesc, 0, sizeof(winedesc));
4954 winedesc.Width = &srcSurfaceWidth;
4955 winedesc.Height = &srcSurfaceHeight;
4956 winedesc.Pool = &srcPool;
4957 winedesc.Format = &srcFormat;
4959 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4961 winedesc.Width = &destSurfaceWidth;
4962 winedesc.Height = &destSurfaceHeight;
4963 winedesc.Pool = &destPool;
4964 winedesc.Format = &destFormat;
4965 winedesc.Size = &destSize;
4967 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4969 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4970 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4971 return WINED3DERR_INVALIDCALL;
4974 if (destFormat == WINED3DFMT_UNKNOWN) {
4975 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4976 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4978 /* Get the update surface description */
4979 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4982 ENTER_GL();
4984 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4986 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4987 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4988 checkGLcall("glActiveTextureARB");
4991 /* Make sure the surface is loaded and up to date */
4992 IWineD3DSurface_PreLoad(pDestinationSurface);
4994 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4996 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4997 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4998 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4999 srcLeft = pSourceRect ? pSourceRect->left : 0;
5000 destLeft = pDestPoint ? pDestPoint->x : 0;
5001 destTop = pDestPoint ? pDestPoint->y : 0;
5004 /* This function doesn't support compressed textures
5005 the pitch is just bytesPerPixel * width */
5006 if(srcWidth != srcSurfaceWidth || srcLeft ){
5007 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5008 offset += srcLeft * pSrcSurface->bytesPerPixel;
5009 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5011 /* TODO DXT formats */
5013 if(pSourceRect != NULL && pSourceRect->top != 0){
5014 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5016 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5017 ,This
5018 ,glDescription->level
5019 ,destLeft
5020 ,destTop
5021 ,srcWidth
5022 ,srcHeight
5023 ,glDescription->glFormat
5024 ,glDescription->glType
5025 ,IWineD3DSurface_GetData(pSourceSurface)
5028 /* Sanity check */
5029 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5031 /* need to lock the surface to get the data */
5032 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5035 /* TODO: Cube and volume support */
5036 if(rowoffset != 0){
5037 /* not a whole row so we have to do it a line at a time */
5038 int j;
5040 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5041 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5043 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5045 glTexSubImage2D(glDescription->target
5046 ,glDescription->level
5047 ,destLeft
5049 ,srcWidth
5051 ,glDescription->glFormat
5052 ,glDescription->glType
5053 ,data /* could be quicker using */
5055 data += rowoffset;
5058 } else { /* Full width, so just write out the whole texture */
5060 if (WINED3DFMT_DXT1 == destFormat ||
5061 WINED3DFMT_DXT2 == destFormat ||
5062 WINED3DFMT_DXT3 == destFormat ||
5063 WINED3DFMT_DXT4 == destFormat ||
5064 WINED3DFMT_DXT5 == destFormat) {
5065 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5066 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5067 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5068 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5069 } if (destFormat != srcFormat) {
5070 FIXME("Updating mixed format compressed texture is not curretly support\n");
5071 } else {
5072 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5073 glDescription->level,
5074 glDescription->glFormatInternal,
5075 srcWidth,
5076 srcHeight,
5078 destSize,
5079 IWineD3DSurface_GetData(pSourceSurface));
5081 } else {
5082 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5086 } else {
5087 glTexSubImage2D(glDescription->target
5088 ,glDescription->level
5089 ,destLeft
5090 ,destTop
5091 ,srcWidth
5092 ,srcHeight
5093 ,glDescription->glFormat
5094 ,glDescription->glType
5095 ,IWineD3DSurface_GetData(pSourceSurface)
5099 checkGLcall("glTexSubImage2D");
5101 LEAVE_GL();
5103 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5104 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5107 return WINED3D_OK;
5110 /* Implementation details at http://developer.nvidia.com/attach/6494
5112 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5113 hmm.. no longer supported use
5114 OpenGL evaluators or tessellate surfaces within your application.
5117 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5118 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5121 FIXME("(%p) : Stub\n", This);
5122 return WINED3D_OK;
5126 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5127 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5129 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5130 FIXME("(%p) : Stub\n", This);
5131 return WINED3D_OK;
5134 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 TRACE("(%p) Handle(%d)\n", This, Handle);
5137 FIXME("(%p) : Stub\n", This);
5138 return WINED3D_OK;
5141 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5142 HRESULT hr;
5143 IWineD3DSwapChain *swapchain;
5145 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5146 if (SUCCEEDED(hr)) {
5147 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5148 return swapchain;
5151 return NULL;
5154 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5157 if (!*fbo) {
5158 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5159 checkGLcall("glGenFramebuffersEXT()");
5161 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5162 checkGLcall("glBindFramebuffer()");
5165 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5166 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5167 IWineD3DBaseTextureImpl *texture_impl;
5168 GLenum texttarget, target;
5169 GLint old_binding;
5171 texttarget = surface_impl->glDescription.target;
5172 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5173 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5175 IWineD3DSurface_PreLoad(surface);
5177 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5178 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5179 glBindTexture(target, old_binding);
5181 /* Update base texture states array */
5182 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5183 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5184 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5185 if (texture_impl->baseTexture.bindCount) {
5186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5189 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5192 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5194 checkGLcall("attach_surface_fbo");
5197 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5199 IWineD3DSwapChain *swapchain;
5201 swapchain = get_swapchain(surface);
5202 if (swapchain) {
5203 GLenum buffer;
5205 TRACE("Surface %p is onscreen\n", surface);
5207 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5208 buffer = surface_get_gl_buffer(surface, swapchain);
5209 glDrawBuffer(buffer);
5210 checkGLcall("glDrawBuffer()");
5211 } else {
5212 TRACE("Surface %p is offscreen\n", surface);
5213 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5214 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5217 if (rect) {
5218 glEnable(GL_SCISSOR_TEST);
5219 if(!swapchain) {
5220 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5221 } else {
5222 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5223 rect->x2 - rect->x1, rect->y2 - rect->y1);
5225 checkGLcall("glScissor");
5226 } else {
5227 glDisable(GL_SCISSOR_TEST);
5229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5231 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5234 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5235 glClear(GL_COLOR_BUFFER_BIT);
5236 checkGLcall("glClear");
5238 if (This->render_offscreen) {
5239 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5240 } else {
5241 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5242 checkGLcall("glBindFramebuffer()");
5245 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5246 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5247 glDrawBuffer(GL_BACK);
5248 checkGLcall("glDrawBuffer()");
5252 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5254 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5255 WINEDDBLTFX BltFx;
5256 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5258 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5259 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5260 return WINED3DERR_INVALIDCALL;
5263 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5264 color_fill_fbo(iface, pSurface, pRect, color);
5265 return WINED3D_OK;
5266 } else {
5267 /* Just forward this to the DirectDraw blitting engine */
5268 memset(&BltFx, 0, sizeof(BltFx));
5269 BltFx.dwSize = sizeof(BltFx);
5270 BltFx.u5.dwFillColor = color;
5271 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5275 /* rendertarget and deptth stencil functions */
5276 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5279 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5280 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5281 return WINED3DERR_INVALIDCALL;
5284 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5285 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5286 /* Note inc ref on returned surface */
5287 if(*ppRenderTarget != NULL)
5288 IWineD3DSurface_AddRef(*ppRenderTarget);
5289 return WINED3D_OK;
5292 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5294 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5295 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5296 IWineD3DSwapChainImpl *Swapchain;
5297 HRESULT hr;
5299 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5301 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5302 if(hr != WINED3D_OK) {
5303 ERR("Can't get the swapchain\n");
5304 return hr;
5307 /* Make sure to release the swapchain */
5308 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5310 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5311 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5312 return WINED3DERR_INVALIDCALL;
5314 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5315 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5316 return WINED3DERR_INVALIDCALL;
5319 if(Swapchain->frontBuffer != Front) {
5320 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5322 if(Swapchain->frontBuffer)
5323 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5324 Swapchain->frontBuffer = Front;
5326 if(Swapchain->frontBuffer) {
5327 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5331 if(Back && !Swapchain->backBuffer) {
5332 /* We need memory for the back buffer array - only one back buffer this way */
5333 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5334 if(!Swapchain->backBuffer) {
5335 ERR("Out of memory\n");
5336 return E_OUTOFMEMORY;
5340 if(Swapchain->backBuffer[0] != Back) {
5341 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5343 /* What to do about the context here in the case of multithreading? Not sure.
5344 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5346 ENTER_GL();
5347 if(!Swapchain->backBuffer[0]) {
5348 /* GL was told to draw to the front buffer at creation,
5349 * undo that
5351 glDrawBuffer(GL_BACK);
5352 checkGLcall("glDrawBuffer(GL_BACK)");
5353 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5354 Swapchain->presentParms.BackBufferCount = 1;
5355 } else if (!Back) {
5356 /* That makes problems - disable for now */
5357 /* glDrawBuffer(GL_FRONT); */
5358 checkGLcall("glDrawBuffer(GL_FRONT)");
5359 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5360 Swapchain->presentParms.BackBufferCount = 0;
5362 LEAVE_GL();
5364 if(Swapchain->backBuffer[0])
5365 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5366 Swapchain->backBuffer[0] = Back;
5368 if(Swapchain->backBuffer[0]) {
5369 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5370 } else {
5371 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5376 return WINED3D_OK;
5379 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5381 *ppZStencilSurface = This->depthStencilBuffer;
5382 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5384 if(*ppZStencilSurface != NULL) {
5385 /* Note inc ref on returned surface */
5386 IWineD3DSurface_AddRef(*ppZStencilSurface);
5388 return WINED3D_OK;
5391 /* TODO: Handle stencil attachments */
5392 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5394 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5396 TRACE("Set depth stencil to %p\n", depth_stencil);
5398 if (depth_stencil_impl) {
5399 if (depth_stencil_impl->current_renderbuffer) {
5400 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5401 checkGLcall("glFramebufferRenderbufferEXT()");
5402 } else {
5403 IWineD3DBaseTextureImpl *texture_impl;
5404 GLenum texttarget, target;
5405 GLint old_binding = 0;
5407 texttarget = depth_stencil_impl->glDescription.target;
5408 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5409 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5411 IWineD3DSurface_PreLoad(depth_stencil);
5413 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5414 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5415 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5416 glBindTexture(target, old_binding);
5418 /* Update base texture states array */
5419 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5420 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5421 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5422 if (texture_impl->baseTexture.bindCount) {
5423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5426 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5429 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5430 checkGLcall("glFramebufferTexture2DEXT()");
5432 } else {
5433 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5434 checkGLcall("glFramebufferTexture2DEXT()");
5438 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5440 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5442 TRACE("Set render target %u to %p\n", idx, render_target);
5444 if (rtimpl) {
5445 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5446 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5447 } else {
5448 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5449 checkGLcall("glFramebufferTexture2DEXT()");
5451 This->draw_buffers[idx] = GL_NONE;
5455 static void check_fbo_status(IWineD3DDevice *iface) {
5456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5457 GLenum status;
5459 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5460 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5461 TRACE("FBO complete\n");
5462 } else {
5463 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5465 /* Dump the FBO attachments */
5466 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5467 IWineD3DSurfaceImpl *attachment;
5468 int i;
5470 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5471 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5472 if (attachment) {
5473 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5474 attachment->pow2Width, attachment->pow2Height);
5477 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5478 if (attachment) {
5479 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5480 attachment->pow2Width, attachment->pow2Height);
5486 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5488 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5489 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5491 if (!ds_impl) return FALSE;
5493 if (ds_impl->current_renderbuffer) {
5494 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5495 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5498 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5499 rt_impl->pow2Height != ds_impl->pow2Height);
5502 void apply_fbo_state(IWineD3DDevice *iface) {
5503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5504 unsigned int i;
5506 if (This->render_offscreen) {
5507 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5509 /* Apply render targets */
5510 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5511 IWineD3DSurface *render_target = This->render_targets[i];
5512 if (This->fbo_color_attachments[i] != render_target) {
5513 set_render_target_fbo(iface, i, render_target);
5514 This->fbo_color_attachments[i] = render_target;
5518 /* Apply depth targets */
5519 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5520 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5521 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5523 if (This->stencilBufferTarget) {
5524 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5526 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5527 This->fbo_depth_attachment = This->stencilBufferTarget;
5530 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5531 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5532 checkGLcall("glDrawBuffers()");
5533 } else {
5534 glDrawBuffer(This->draw_buffers[0]);
5535 checkGLcall("glDrawBuffer()");
5537 } else {
5538 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5541 check_fbo_status(iface);
5544 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5545 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5547 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5548 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5549 GLenum gl_filter;
5551 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5552 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5553 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5554 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5556 switch (filter) {
5557 case WINED3DTEXF_LINEAR:
5558 gl_filter = GL_LINEAR;
5559 break;
5561 default:
5562 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5563 case WINED3DTEXF_NONE:
5564 case WINED3DTEXF_POINT:
5565 gl_filter = GL_NEAREST;
5566 break;
5569 /* Attach src surface to src fbo */
5570 src_swapchain = get_swapchain(src_surface);
5571 ENTER_GL();
5572 if (src_swapchain) {
5573 GLenum buffer;
5575 TRACE("Source surface %p is onscreen\n", src_surface);
5576 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5578 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5579 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5580 glReadBuffer(buffer);
5581 checkGLcall("glReadBuffer()");
5583 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5584 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5585 } else {
5586 TRACE("Source surface %p is offscreen\n", src_surface);
5587 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5588 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5589 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5590 checkGLcall("glReadBuffer()");
5593 /* Attach dst surface to dst fbo */
5594 dst_swapchain = get_swapchain(dst_surface);
5595 if (dst_swapchain) {
5596 GLenum buffer;
5598 TRACE("Destination surface %p is onscreen\n", dst_surface);
5599 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5601 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5602 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5603 glDrawBuffer(buffer);
5604 checkGLcall("glDrawBuffer()");
5606 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5607 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5608 } else {
5609 TRACE("Destination surface %p is offscreen\n", dst_surface);
5611 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5612 if(!src_swapchain) {
5613 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5616 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5617 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5618 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5619 checkGLcall("glDrawBuffer()");
5621 glDisable(GL_SCISSOR_TEST);
5622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5624 if (flip) {
5625 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5626 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5627 checkGLcall("glBlitFramebuffer()");
5628 } else {
5629 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5630 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5631 checkGLcall("glBlitFramebuffer()");
5634 if (This->render_offscreen) {
5635 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5636 } else {
5637 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5638 checkGLcall("glBindFramebuffer()");
5641 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5642 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5643 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5644 glDrawBuffer(GL_BACK);
5645 checkGLcall("glDrawBuffer()");
5647 LEAVE_GL();
5650 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5652 WINED3DVIEWPORT viewport;
5654 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5656 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5657 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5658 return WINED3DERR_INVALIDCALL;
5661 /* MSDN says that null disables the render target
5662 but a device must always be associated with a render target
5663 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5665 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5666 for more details
5668 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5669 FIXME("Trying to set render target 0 to NULL\n");
5670 return WINED3DERR_INVALIDCALL;
5672 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5673 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);
5674 return WINED3DERR_INVALIDCALL;
5677 /* If we are trying to set what we already have, don't bother */
5678 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5679 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5680 return WINED3D_OK;
5682 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5683 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5684 This->render_targets[RenderTargetIndex] = pRenderTarget;
5686 /* Render target 0 is special */
5687 if(RenderTargetIndex == 0) {
5688 /* Finally, reset the viewport as the MSDN states. */
5689 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5690 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5691 viewport.X = 0;
5692 viewport.Y = 0;
5693 viewport.MaxZ = 1.0f;
5694 viewport.MinZ = 0.0f;
5695 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5696 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5697 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5701 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5702 * ctx properly.
5703 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5704 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5706 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5708 return WINED3D_OK;
5711 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 HRESULT hr = WINED3D_OK;
5714 IWineD3DSurface *tmp;
5716 TRACE("(%p) Swapping z-buffer\n",This);
5718 if (pNewZStencil == This->stencilBufferTarget) {
5719 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5720 } else {
5721 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5722 * depending on the renter target implementation being used.
5723 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5724 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5725 * stencil buffer and incure an extra memory overhead
5726 ******************************************************/
5728 tmp = This->stencilBufferTarget;
5729 This->stencilBufferTarget = pNewZStencil;
5730 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5731 /* should we be calling the parent or the wined3d surface? */
5732 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5733 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5734 hr = WINED3D_OK;
5736 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5737 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5739 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5744 return hr;
5747 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5748 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5750 /* TODO: the use of Impl is deprecated. */
5751 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5752 WINED3DLOCKED_RECT lockedRect;
5754 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5756 /* some basic validation checks */
5757 if(This->cursorTexture) {
5758 ENTER_GL();
5759 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5760 glDeleteTextures(1, &This->cursorTexture);
5761 LEAVE_GL();
5762 This->cursorTexture = 0;
5765 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5766 This->haveHardwareCursor = TRUE;
5767 else
5768 This->haveHardwareCursor = FALSE;
5770 if(pCursorBitmap) {
5771 WINED3DLOCKED_RECT rect;
5773 /* MSDN: Cursor must be A8R8G8B8 */
5774 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5775 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5776 return WINED3DERR_INVALIDCALL;
5779 /* MSDN: Cursor must be smaller than the display mode */
5780 if(pSur->currentDesc.Width > This->ddraw_width ||
5781 pSur->currentDesc.Height > This->ddraw_height) {
5782 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);
5783 return WINED3DERR_INVALIDCALL;
5786 if (!This->haveHardwareCursor) {
5787 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5789 /* Do not store the surface's pointer because the application may
5790 * release it after setting the cursor image. Windows doesn't
5791 * addref the set surface, so we can't do this either without
5792 * creating circular refcount dependencies. Copy out the gl texture
5793 * instead.
5795 This->cursorWidth = pSur->currentDesc.Width;
5796 This->cursorHeight = pSur->currentDesc.Height;
5797 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5799 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5800 char *mem, *bits = (char *)rect.pBits;
5801 GLint intfmt = tableEntry->glInternal;
5802 GLint format = tableEntry->glFormat;
5803 GLint type = tableEntry->glType;
5804 INT height = This->cursorHeight;
5805 INT width = This->cursorWidth;
5806 INT bpp = tableEntry->bpp;
5807 INT i;
5809 /* Reformat the texture memory (pitch and width can be
5810 * different) */
5811 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5812 for(i = 0; i < height; i++)
5813 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5814 IWineD3DSurface_UnlockRect(pCursorBitmap);
5815 ENTER_GL();
5817 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5818 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5819 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5822 /* Make sure that a proper texture unit is selected */
5823 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5824 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5825 checkGLcall("glActiveTextureARB");
5827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5828 /* Create a new cursor texture */
5829 glGenTextures(1, &This->cursorTexture);
5830 checkGLcall("glGenTextures");
5831 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5832 checkGLcall("glBindTexture");
5833 /* Copy the bitmap memory into the cursor texture */
5834 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5835 HeapFree(GetProcessHeap(), 0, mem);
5836 checkGLcall("glTexImage2D");
5838 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5839 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5840 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5843 LEAVE_GL();
5845 else
5847 FIXME("A cursor texture was not returned.\n");
5848 This->cursorTexture = 0;
5851 else
5853 /* Draw a hardware cursor */
5854 ICONINFO cursorInfo;
5855 HCURSOR cursor;
5856 /* Create and clear maskBits because it is not needed for
5857 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5858 * chunks. */
5859 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5860 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5861 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5862 WINED3DLOCK_NO_DIRTY_UPDATE |
5863 WINED3DLOCK_READONLY
5865 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5866 pSur->currentDesc.Height);
5868 cursorInfo.fIcon = FALSE;
5869 cursorInfo.xHotspot = XHotSpot;
5870 cursorInfo.yHotspot = YHotSpot;
5871 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5872 pSur->currentDesc.Height, 1,
5873 1, &maskBits);
5874 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5875 pSur->currentDesc.Height, 1,
5876 32, lockedRect.pBits);
5877 IWineD3DSurface_UnlockRect(pCursorBitmap);
5878 /* Create our cursor and clean up. */
5879 cursor = CreateIconIndirect(&cursorInfo);
5880 SetCursor(cursor);
5881 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5882 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5883 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5884 This->hardwareCursor = cursor;
5885 HeapFree(GetProcessHeap(), 0, maskBits);
5889 This->xHotSpot = XHotSpot;
5890 This->yHotSpot = YHotSpot;
5891 return WINED3D_OK;
5894 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5896 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5898 This->xScreenSpace = XScreenSpace;
5899 This->yScreenSpace = YScreenSpace;
5901 return;
5905 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5907 BOOL oldVisible = This->bCursorVisible;
5908 POINT pt;
5910 TRACE("(%p) : visible(%d)\n", This, bShow);
5913 * When ShowCursor is first called it should make the cursor appear at the OS's last
5914 * known cursor position. Because of this, some applications just repetitively call
5915 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5917 GetCursorPos(&pt);
5918 This->xScreenSpace = pt.x;
5919 This->yScreenSpace = pt.y;
5921 if (This->haveHardwareCursor) {
5922 This->bCursorVisible = bShow;
5923 if (bShow)
5924 SetCursor(This->hardwareCursor);
5925 else
5926 SetCursor(NULL);
5928 else
5930 if (This->cursorTexture)
5931 This->bCursorVisible = bShow;
5934 return oldVisible;
5937 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5939 TRACE("(%p) : state (%u)\n", This, This->state);
5940 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5941 switch (This->state) {
5942 case WINED3D_OK:
5943 return WINED3D_OK;
5944 case WINED3DERR_DEVICELOST:
5946 ResourceList *resourceList = This->resources;
5947 while (NULL != resourceList) {
5948 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5949 return WINED3DERR_DEVICENOTRESET;
5950 resourceList = resourceList->next;
5952 return WINED3DERR_DEVICELOST;
5954 case WINED3DERR_DRIVERINTERNALERROR:
5955 return WINED3DERR_DRIVERINTERNALERROR;
5958 /* Unknown state */
5959 return WINED3DERR_DRIVERINTERNALERROR;
5963 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5965 /** FIXME: Resource tracking needs to be done,
5966 * The closes we can do to this is set the priorities of all managed textures low
5967 * and then reset them.
5968 ***********************************************************/
5969 FIXME("(%p) : stub\n", This);
5970 return WINED3D_OK;
5973 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5974 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5976 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5977 if(surface->Flags & SFLAG_DIBSECTION) {
5978 /* Release the DC */
5979 SelectObject(surface->hDC, surface->dib.holdbitmap);
5980 DeleteDC(surface->hDC);
5981 /* Release the DIB section */
5982 DeleteObject(surface->dib.DIBsection);
5983 surface->dib.bitmap_data = NULL;
5984 surface->resource.allocatedMemory = NULL;
5985 surface->Flags &= ~SFLAG_DIBSECTION;
5987 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5988 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5989 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5990 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5991 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5992 } else {
5993 surface->pow2Width = surface->pow2Height = 1;
5994 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5995 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5997 if(surface->glDescription.textureName) {
5998 ENTER_GL();
5999 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6000 glDeleteTextures(1, &surface->glDescription.textureName);
6001 LEAVE_GL();
6002 surface->glDescription.textureName = 0;
6003 surface->Flags &= ~SFLAG_CLIENT;
6005 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6006 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6007 surface->Flags |= SFLAG_NONPOW2;
6008 } else {
6009 surface->Flags &= ~SFLAG_NONPOW2;
6011 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6012 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6015 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6017 IWineD3DSwapChainImpl *swapchain;
6018 HRESULT hr;
6019 BOOL DisplayModeChanged = FALSE;
6020 WINED3DDISPLAYMODE mode;
6021 TRACE("(%p)\n", This);
6023 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6024 if(FAILED(hr)) {
6025 ERR("Failed to get the first implicit swapchain\n");
6026 return hr;
6029 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6030 * on an existing gl context, so there's no real need for recreation.
6032 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6034 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6036 TRACE("New params:\n");
6037 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6038 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6039 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6040 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6041 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6042 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6043 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6044 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6045 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6046 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6047 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6048 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6049 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6051 /* No special treatment of these parameters. Just store them */
6052 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6053 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6054 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6055 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6057 /* What to do about these? */
6058 if(pPresentationParameters->BackBufferCount != 0 &&
6059 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6060 ERR("Cannot change the back buffer count yet\n");
6062 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6063 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6064 ERR("Cannot change the back buffer format yet\n");
6066 if(pPresentationParameters->hDeviceWindow != NULL &&
6067 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6068 ERR("Cannot change the device window yet\n");
6070 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6071 ERR("What do do about a changed auto depth stencil parameter?\n");
6074 if(pPresentationParameters->Windowed) {
6075 mode.Width = swapchain->orig_width;
6076 mode.Height = swapchain->orig_height;
6077 mode.RefreshRate = 0;
6078 mode.Format = swapchain->presentParms.BackBufferFormat;
6079 } else {
6080 mode.Width = pPresentationParameters->BackBufferWidth;
6081 mode.Height = pPresentationParameters->BackBufferHeight;
6082 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6083 mode.Format = swapchain->presentParms.BackBufferFormat;
6086 /* Should Width == 800 && Height == 0 set 800x600? */
6087 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6088 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6089 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6091 WINED3DVIEWPORT vp;
6092 int i;
6094 vp.X = 0;
6095 vp.Y = 0;
6096 vp.Width = pPresentationParameters->BackBufferWidth;
6097 vp.Height = pPresentationParameters->BackBufferHeight;
6098 vp.MinZ = 0;
6099 vp.MaxZ = 1;
6101 if(!pPresentationParameters->Windowed) {
6102 DisplayModeChanged = TRUE;
6104 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6105 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6107 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6108 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6109 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6112 /* Now set the new viewport */
6113 IWineD3DDevice_SetViewport(iface, &vp);
6116 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6117 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6118 DisplayModeChanged) {
6120 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6121 if(!pPresentationParameters->Windowed) {
6122 IWineD3DDevice_SetFullscreen(iface, TRUE);
6125 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6127 /* Switching out of fullscreen mode? First set the original res, then change the window */
6128 if(pPresentationParameters->Windowed) {
6129 IWineD3DDevice_SetFullscreen(iface, FALSE);
6131 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6134 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6135 return WINED3D_OK;
6138 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6140 /** FIXME: always true at the moment **/
6141 if(!bEnableDialogs) {
6142 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6144 return WINED3D_OK;
6148 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6150 TRACE("(%p) : pParameters %p\n", This, pParameters);
6152 *pParameters = This->createParms;
6153 return WINED3D_OK;
6156 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6157 IWineD3DSwapChain *swapchain;
6158 HRESULT hrc = WINED3D_OK;
6160 TRACE("Relaying to swapchain\n");
6162 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6163 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6164 IWineD3DSwapChain_Release(swapchain);
6166 return;
6169 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6170 IWineD3DSwapChain *swapchain;
6171 HRESULT hrc = WINED3D_OK;
6173 TRACE("Relaying to swapchain\n");
6175 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6176 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6177 IWineD3DSwapChain_Release(swapchain);
6179 return;
6183 /** ********************************************************
6184 * Notification functions
6185 ** ********************************************************/
6186 /** This function must be called in the release of a resource when ref == 0,
6187 * the contents of resource must still be correct,
6188 * any handels to other resource held by the caller must be closed
6189 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6190 *****************************************************/
6191 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6193 ResourceList* resourceList;
6195 TRACE("(%p) : resource %p\n", This, resource);
6196 /* add a new texture to the frot of the linked list */
6197 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6198 resourceList->resource = resource;
6200 /* Get the old head */
6201 resourceList->next = This->resources;
6203 This->resources = resourceList;
6204 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6206 return;
6209 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6211 ResourceList* resourceList = NULL;
6212 ResourceList* previousResourceList = NULL;
6214 TRACE("(%p) : resource %p\n", This, resource);
6216 resourceList = This->resources;
6218 while (resourceList != NULL) {
6219 if(resourceList->resource == resource) break;
6220 previousResourceList = resourceList;
6221 resourceList = resourceList->next;
6224 if (resourceList == NULL) {
6225 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6226 return;
6227 } else {
6228 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6230 /* make sure we don't leave a hole in the list */
6231 if (previousResourceList != NULL) {
6232 previousResourceList->next = resourceList->next;
6233 } else {
6234 This->resources = resourceList->next;
6237 return;
6241 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6243 int counter;
6245 TRACE("(%p) : resource %p\n", This, resource);
6246 switch(IWineD3DResource_GetType(resource)){
6247 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6248 case WINED3DRTYPE_SURFACE: {
6249 unsigned int i;
6251 /* Cleanup any FBO attachments */
6252 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6253 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6254 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6255 set_render_target_fbo(iface, i, NULL);
6256 This->fbo_color_attachments[i] = NULL;
6259 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6260 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6261 set_depth_stencil_fbo(iface, NULL);
6262 This->fbo_depth_attachment = NULL;
6265 break;
6268 case WINED3DRTYPE_TEXTURE:
6269 case WINED3DRTYPE_CUBETEXTURE:
6270 case WINED3DRTYPE_VOLUMETEXTURE:
6271 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6272 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6273 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6274 This->stateBlock->textures[counter] = NULL;
6276 if (This->updateStateBlock != This->stateBlock ){
6277 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6278 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6279 This->updateStateBlock->textures[counter] = NULL;
6283 break;
6284 case WINED3DRTYPE_VOLUME:
6285 /* TODO: nothing really? */
6286 break;
6287 case WINED3DRTYPE_VERTEXBUFFER:
6288 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6290 int streamNumber;
6291 TRACE("Cleaning up stream pointers\n");
6293 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6294 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6295 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6297 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6298 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6299 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6300 This->updateStateBlock->streamSource[streamNumber] = 0;
6301 /* Set changed flag? */
6304 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) */
6305 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6306 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6307 This->stateBlock->streamSource[streamNumber] = 0;
6310 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6311 else { /* This shouldn't happen */
6312 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6314 #endif
6318 break;
6319 case WINED3DRTYPE_INDEXBUFFER:
6320 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6321 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6322 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6323 This->updateStateBlock->pIndexData = NULL;
6326 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6327 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6328 This->stateBlock->pIndexData = NULL;
6332 break;
6333 default:
6334 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6335 break;
6339 /* Remove the resoruce from the resourceStore */
6340 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6342 TRACE("Resource released\n");
6346 /**********************************************************
6347 * IWineD3DDevice VTbl follows
6348 **********************************************************/
6350 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6352 /*** IUnknown methods ***/
6353 IWineD3DDeviceImpl_QueryInterface,
6354 IWineD3DDeviceImpl_AddRef,
6355 IWineD3DDeviceImpl_Release,
6356 /*** IWineD3DDevice methods ***/
6357 IWineD3DDeviceImpl_GetParent,
6358 /*** Creation methods**/
6359 IWineD3DDeviceImpl_CreateVertexBuffer,
6360 IWineD3DDeviceImpl_CreateIndexBuffer,
6361 IWineD3DDeviceImpl_CreateStateBlock,
6362 IWineD3DDeviceImpl_CreateSurface,
6363 IWineD3DDeviceImpl_CreateTexture,
6364 IWineD3DDeviceImpl_CreateVolumeTexture,
6365 IWineD3DDeviceImpl_CreateVolume,
6366 IWineD3DDeviceImpl_CreateCubeTexture,
6367 IWineD3DDeviceImpl_CreateQuery,
6368 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6369 IWineD3DDeviceImpl_CreateVertexDeclaration,
6370 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6371 IWineD3DDeviceImpl_CreateVertexShader,
6372 IWineD3DDeviceImpl_CreatePixelShader,
6373 IWineD3DDeviceImpl_CreatePalette,
6374 /*** Odd functions **/
6375 IWineD3DDeviceImpl_Init3D,
6376 IWineD3DDeviceImpl_Uninit3D,
6377 IWineD3DDeviceImpl_SetFullscreen,
6378 IWineD3DDeviceImpl_SetMultithreaded,
6379 IWineD3DDeviceImpl_EvictManagedResources,
6380 IWineD3DDeviceImpl_GetAvailableTextureMem,
6381 IWineD3DDeviceImpl_GetBackBuffer,
6382 IWineD3DDeviceImpl_GetCreationParameters,
6383 IWineD3DDeviceImpl_GetDeviceCaps,
6384 IWineD3DDeviceImpl_GetDirect3D,
6385 IWineD3DDeviceImpl_GetDisplayMode,
6386 IWineD3DDeviceImpl_SetDisplayMode,
6387 IWineD3DDeviceImpl_GetHWND,
6388 IWineD3DDeviceImpl_SetHWND,
6389 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6390 IWineD3DDeviceImpl_GetRasterStatus,
6391 IWineD3DDeviceImpl_GetSwapChain,
6392 IWineD3DDeviceImpl_Reset,
6393 IWineD3DDeviceImpl_SetDialogBoxMode,
6394 IWineD3DDeviceImpl_SetCursorProperties,
6395 IWineD3DDeviceImpl_SetCursorPosition,
6396 IWineD3DDeviceImpl_ShowCursor,
6397 IWineD3DDeviceImpl_TestCooperativeLevel,
6398 /*** Getters and setters **/
6399 IWineD3DDeviceImpl_SetClipPlane,
6400 IWineD3DDeviceImpl_GetClipPlane,
6401 IWineD3DDeviceImpl_SetClipStatus,
6402 IWineD3DDeviceImpl_GetClipStatus,
6403 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6404 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6405 IWineD3DDeviceImpl_SetDepthStencilSurface,
6406 IWineD3DDeviceImpl_GetDepthStencilSurface,
6407 IWineD3DDeviceImpl_SetFVF,
6408 IWineD3DDeviceImpl_GetFVF,
6409 IWineD3DDeviceImpl_SetGammaRamp,
6410 IWineD3DDeviceImpl_GetGammaRamp,
6411 IWineD3DDeviceImpl_SetIndices,
6412 IWineD3DDeviceImpl_GetIndices,
6413 IWineD3DDeviceImpl_SetBaseVertexIndex,
6414 IWineD3DDeviceImpl_GetBaseVertexIndex,
6415 IWineD3DDeviceImpl_SetLight,
6416 IWineD3DDeviceImpl_GetLight,
6417 IWineD3DDeviceImpl_SetLightEnable,
6418 IWineD3DDeviceImpl_GetLightEnable,
6419 IWineD3DDeviceImpl_SetMaterial,
6420 IWineD3DDeviceImpl_GetMaterial,
6421 IWineD3DDeviceImpl_SetNPatchMode,
6422 IWineD3DDeviceImpl_GetNPatchMode,
6423 IWineD3DDeviceImpl_SetPaletteEntries,
6424 IWineD3DDeviceImpl_GetPaletteEntries,
6425 IWineD3DDeviceImpl_SetPixelShader,
6426 IWineD3DDeviceImpl_GetPixelShader,
6427 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6428 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6429 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6430 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6431 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6432 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6433 IWineD3DDeviceImpl_SetRenderState,
6434 IWineD3DDeviceImpl_GetRenderState,
6435 IWineD3DDeviceImpl_SetRenderTarget,
6436 IWineD3DDeviceImpl_GetRenderTarget,
6437 IWineD3DDeviceImpl_SetFrontBackBuffers,
6438 IWineD3DDeviceImpl_SetSamplerState,
6439 IWineD3DDeviceImpl_GetSamplerState,
6440 IWineD3DDeviceImpl_SetScissorRect,
6441 IWineD3DDeviceImpl_GetScissorRect,
6442 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6443 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6444 IWineD3DDeviceImpl_SetStreamSource,
6445 IWineD3DDeviceImpl_GetStreamSource,
6446 IWineD3DDeviceImpl_SetStreamSourceFreq,
6447 IWineD3DDeviceImpl_GetStreamSourceFreq,
6448 IWineD3DDeviceImpl_SetTexture,
6449 IWineD3DDeviceImpl_GetTexture,
6450 IWineD3DDeviceImpl_SetTextureStageState,
6451 IWineD3DDeviceImpl_GetTextureStageState,
6452 IWineD3DDeviceImpl_SetTransform,
6453 IWineD3DDeviceImpl_GetTransform,
6454 IWineD3DDeviceImpl_SetVertexDeclaration,
6455 IWineD3DDeviceImpl_GetVertexDeclaration,
6456 IWineD3DDeviceImpl_SetVertexShader,
6457 IWineD3DDeviceImpl_GetVertexShader,
6458 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6459 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6460 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6461 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6462 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6463 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6464 IWineD3DDeviceImpl_SetViewport,
6465 IWineD3DDeviceImpl_GetViewport,
6466 IWineD3DDeviceImpl_MultiplyTransform,
6467 IWineD3DDeviceImpl_ValidateDevice,
6468 IWineD3DDeviceImpl_ProcessVertices,
6469 /*** State block ***/
6470 IWineD3DDeviceImpl_BeginStateBlock,
6471 IWineD3DDeviceImpl_EndStateBlock,
6472 /*** Scene management ***/
6473 IWineD3DDeviceImpl_BeginScene,
6474 IWineD3DDeviceImpl_EndScene,
6475 IWineD3DDeviceImpl_Present,
6476 IWineD3DDeviceImpl_Clear,
6477 /*** Drawing ***/
6478 IWineD3DDeviceImpl_DrawPrimitive,
6479 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6480 IWineD3DDeviceImpl_DrawPrimitiveUP,
6481 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6482 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6483 IWineD3DDeviceImpl_DrawRectPatch,
6484 IWineD3DDeviceImpl_DrawTriPatch,
6485 IWineD3DDeviceImpl_DeletePatch,
6486 IWineD3DDeviceImpl_ColorFill,
6487 IWineD3DDeviceImpl_UpdateTexture,
6488 IWineD3DDeviceImpl_UpdateSurface,
6489 IWineD3DDeviceImpl_GetFrontBufferData,
6490 /*** object tracking ***/
6491 IWineD3DDeviceImpl_ResourceReleased
6495 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6496 WINED3DRS_ALPHABLENDENABLE ,
6497 WINED3DRS_ALPHAFUNC ,
6498 WINED3DRS_ALPHAREF ,
6499 WINED3DRS_ALPHATESTENABLE ,
6500 WINED3DRS_BLENDOP ,
6501 WINED3DRS_COLORWRITEENABLE ,
6502 WINED3DRS_DESTBLEND ,
6503 WINED3DRS_DITHERENABLE ,
6504 WINED3DRS_FILLMODE ,
6505 WINED3DRS_FOGDENSITY ,
6506 WINED3DRS_FOGEND ,
6507 WINED3DRS_FOGSTART ,
6508 WINED3DRS_LASTPIXEL ,
6509 WINED3DRS_SHADEMODE ,
6510 WINED3DRS_SRCBLEND ,
6511 WINED3DRS_STENCILENABLE ,
6512 WINED3DRS_STENCILFAIL ,
6513 WINED3DRS_STENCILFUNC ,
6514 WINED3DRS_STENCILMASK ,
6515 WINED3DRS_STENCILPASS ,
6516 WINED3DRS_STENCILREF ,
6517 WINED3DRS_STENCILWRITEMASK ,
6518 WINED3DRS_STENCILZFAIL ,
6519 WINED3DRS_TEXTUREFACTOR ,
6520 WINED3DRS_WRAP0 ,
6521 WINED3DRS_WRAP1 ,
6522 WINED3DRS_WRAP2 ,
6523 WINED3DRS_WRAP3 ,
6524 WINED3DRS_WRAP4 ,
6525 WINED3DRS_WRAP5 ,
6526 WINED3DRS_WRAP6 ,
6527 WINED3DRS_WRAP7 ,
6528 WINED3DRS_ZENABLE ,
6529 WINED3DRS_ZFUNC ,
6530 WINED3DRS_ZWRITEENABLE
6533 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6534 WINED3DTSS_ADDRESSW ,
6535 WINED3DTSS_ALPHAARG0 ,
6536 WINED3DTSS_ALPHAARG1 ,
6537 WINED3DTSS_ALPHAARG2 ,
6538 WINED3DTSS_ALPHAOP ,
6539 WINED3DTSS_BUMPENVLOFFSET ,
6540 WINED3DTSS_BUMPENVLSCALE ,
6541 WINED3DTSS_BUMPENVMAT00 ,
6542 WINED3DTSS_BUMPENVMAT01 ,
6543 WINED3DTSS_BUMPENVMAT10 ,
6544 WINED3DTSS_BUMPENVMAT11 ,
6545 WINED3DTSS_COLORARG0 ,
6546 WINED3DTSS_COLORARG1 ,
6547 WINED3DTSS_COLORARG2 ,
6548 WINED3DTSS_COLOROP ,
6549 WINED3DTSS_RESULTARG ,
6550 WINED3DTSS_TEXCOORDINDEX ,
6551 WINED3DTSS_TEXTURETRANSFORMFLAGS
6554 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6555 WINED3DSAMP_ADDRESSU ,
6556 WINED3DSAMP_ADDRESSV ,
6557 WINED3DSAMP_ADDRESSW ,
6558 WINED3DSAMP_BORDERCOLOR ,
6559 WINED3DSAMP_MAGFILTER ,
6560 WINED3DSAMP_MINFILTER ,
6561 WINED3DSAMP_MIPFILTER ,
6562 WINED3DSAMP_MIPMAPLODBIAS ,
6563 WINED3DSAMP_MAXMIPLEVEL ,
6564 WINED3DSAMP_MAXANISOTROPY ,
6565 WINED3DSAMP_SRGBTEXTURE ,
6566 WINED3DSAMP_ELEMENTINDEX
6569 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6570 WINED3DRS_AMBIENT ,
6571 WINED3DRS_AMBIENTMATERIALSOURCE ,
6572 WINED3DRS_CLIPPING ,
6573 WINED3DRS_CLIPPLANEENABLE ,
6574 WINED3DRS_COLORVERTEX ,
6575 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6576 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6577 WINED3DRS_FOGDENSITY ,
6578 WINED3DRS_FOGEND ,
6579 WINED3DRS_FOGSTART ,
6580 WINED3DRS_FOGTABLEMODE ,
6581 WINED3DRS_FOGVERTEXMODE ,
6582 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6583 WINED3DRS_LIGHTING ,
6584 WINED3DRS_LOCALVIEWER ,
6585 WINED3DRS_MULTISAMPLEANTIALIAS ,
6586 WINED3DRS_MULTISAMPLEMASK ,
6587 WINED3DRS_NORMALIZENORMALS ,
6588 WINED3DRS_PATCHEDGESTYLE ,
6589 WINED3DRS_POINTSCALE_A ,
6590 WINED3DRS_POINTSCALE_B ,
6591 WINED3DRS_POINTSCALE_C ,
6592 WINED3DRS_POINTSCALEENABLE ,
6593 WINED3DRS_POINTSIZE ,
6594 WINED3DRS_POINTSIZE_MAX ,
6595 WINED3DRS_POINTSIZE_MIN ,
6596 WINED3DRS_POINTSPRITEENABLE ,
6597 WINED3DRS_RANGEFOGENABLE ,
6598 WINED3DRS_SPECULARMATERIALSOURCE ,
6599 WINED3DRS_TWEENFACTOR ,
6600 WINED3DRS_VERTEXBLEND
6603 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6604 WINED3DTSS_TEXCOORDINDEX ,
6605 WINED3DTSS_TEXTURETRANSFORMFLAGS
6608 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6609 WINED3DSAMP_DMAPOFFSET
6612 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6613 DWORD rep = StateTable[state].representative;
6614 DWORD idx;
6615 BYTE shift;
6616 UINT i;
6617 WineD3DContext *context;
6619 if(!rep) return;
6620 for(i = 0; i < This->numContexts; i++) {
6621 context = This->contexts[i];
6622 if(isStateDirty(context, rep)) continue;
6624 context->dirtyArray[context->numDirtyEntries++] = rep;
6625 idx = rep >> 5;
6626 shift = rep & 0x1f;
6627 context->isStateDirty[idx] |= (1 << shift);