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