wined3d: Unset the StreamIsUP flag in ProcessVertices.
[wine/dibdrv.git] / dlls / wined3d / device.c
blob1bf959f6f54cc759453f6ae4b868063b9ef604ba
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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 WINED3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 static inline Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* static function declarations */
74 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
76 /* helper macros */
77 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
79 #define D3DCREATEOBJECTINSTANCE(object, type) { \
80 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
81 D3DMEMCHECK(object, pp##type); \
82 object->lpVtbl = &IWineD3D##type##_Vtbl; \
83 object->wineD3DDevice = This; \
84 object->parent = parent; \
85 object->ref = 1; \
86 *pp##type = (IWineD3D##type *) object; \
89 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
90 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
91 D3DMEMCHECK(object, pp##type); \
92 object->lpVtbl = &IWineD3D##type##_Vtbl; \
93 object->parent = parent; \
94 object->ref = 1; \
95 object->baseShader.device = (IWineD3DDevice*) This; \
96 list_init(&object->baseShader.linked_programs); \
97 *pp##type = (IWineD3D##type *) object; \
100 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
101 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
102 D3DMEMCHECK(object, pp##type); \
103 object->lpVtbl = &IWineD3D##type##_Vtbl; \
104 object->resource.wineD3DDevice = This; \
105 object->resource.parent = parent; \
106 object->resource.resourceType = d3dtype; \
107 object->resource.ref = 1; \
108 object->resource.pool = Pool; \
109 object->resource.format = Format; \
110 object->resource.usage = Usage; \
111 object->resource.size = _size; \
112 /* Check that we have enough video ram left */ \
113 if (Pool == WINED3DPOOL_DEFAULT) { \
114 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
115 WARN("Out of 'bogus' video memory\n"); \
116 HeapFree(GetProcessHeap(), 0, object); \
117 *pp##type = NULL; \
118 return WINED3DERR_OUTOFVIDEOMEMORY; \
120 globalChangeGlRam(_size); \
122 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
123 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
124 FIXME("Out of memory!\n"); \
125 HeapFree(GetProcessHeap(), 0, object); \
126 *pp##type = NULL; \
127 return WINED3DERR_OUTOFVIDEOMEMORY; \
129 *pp##type = (IWineD3D##type *) object; \
130 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
131 TRACE("(%p) : Created resource %p\n", This, object); \
134 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
135 _basetexture.levels = Levels; \
136 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
137 _basetexture.LOD = 0; \
138 _basetexture.dirty = TRUE; \
141 /**********************************************************
142 * Global variable / Constants follow
143 **********************************************************/
144 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
146 /**********************************************************
147 * IUnknown parts follows
148 **********************************************************/
150 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
155 if (IsEqualGUID(riid, &IID_IUnknown)
156 || IsEqualGUID(riid, &IID_IWineD3DBase)
157 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
158 IUnknown_AddRef(iface);
159 *ppobj = This;
160 return S_OK;
162 *ppobj = NULL;
163 return E_NOINTERFACE;
166 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
168 ULONG refCount = InterlockedIncrement(&This->ref);
170 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
171 return refCount;
174 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
176 ULONG refCount = InterlockedDecrement(&This->ref);
178 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
180 if (!refCount) {
181 if (This->fbo) {
182 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
184 if (This->src_fbo) {
185 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
187 if (This->dst_fbo) {
188 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
191 HeapFree(GetProcessHeap(), 0, This->render_targets);
192 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
193 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
195 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
197 /* TODO: Clean up all the surfaces and textures! */
198 /* NOTE: You must release the parent if the object was created via a callback
199 ** ***************************/
201 /* Release the update stateblock */
202 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
203 if(This->updateStateBlock != This->stateBlock)
204 FIXME("(%p) Something's still holding the Update stateblock\n",This);
206 This->updateStateBlock = NULL;
207 { /* because were not doing proper internal refcounts releasing the primary state block
208 causes recursion with the extra checks in ResourceReleased, to avoid this we have
209 to set this->stateBlock = NULL; first */
210 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
211 This->stateBlock = NULL;
213 /* Release the stateblock */
214 if(IWineD3DStateBlock_Release(stateBlock) > 0){
215 FIXME("(%p) Something's still holding the Update stateblock\n",This);
219 if (This->resources != NULL ) {
220 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
221 dumpResources(This->resources);
224 if(This->contexts) ERR("Context array not freed!\n");
226 IWineD3D_Release(This->wineD3D);
227 This->wineD3D = NULL;
228 HeapFree(GetProcessHeap(), 0, This);
229 TRACE("Freed device %p\n", This);
230 This = NULL;
232 return refCount;
235 /**********************************************************
236 * IWineD3DDevice implementation follows
237 **********************************************************/
238 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
240 *pParent = This->parent;
241 IUnknown_AddRef(This->parent);
242 return WINED3D_OK;
245 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
246 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
247 GLenum error, glUsage;
248 DWORD vboUsage = object->resource.usage;
249 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
250 WARN("Creating a vbo failed once, not trying again\n");
251 return;
254 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
256 ENTER_GL();
257 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
258 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
260 /* Make sure that the gl error is cleared. Do not use checkGLcall
261 * here because checkGLcall just prints a fixme and continues. However,
262 * if an error during VBO creation occurs we can fall back to non-vbo operation
263 * with full functionality(but performance loss)
265 while(glGetError() != GL_NO_ERROR);
267 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
268 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
269 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
270 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
271 * to check if the rhw and color values are in the correct format.
274 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
275 error = glGetError();
276 if(object->vbo == 0 || error != GL_NO_ERROR) {
277 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
278 goto error;
281 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
282 error = glGetError();
283 if(error != GL_NO_ERROR) {
284 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
285 goto error;
288 /* Don't use static, because dx apps tend to update the buffer
289 * quite often even if they specify 0 usage. Because we always keep the local copy
290 * we never read from the vbo and can create a write only opengl buffer.
292 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
293 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
294 case WINED3DUSAGE_DYNAMIC:
295 TRACE("Gl usage = GL_STREAM_DRAW\n");
296 glUsage = GL_STREAM_DRAW_ARB;
297 break;
298 case WINED3DUSAGE_WRITEONLY:
299 default:
300 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
301 glUsage = GL_DYNAMIC_DRAW_ARB;
302 break;
305 /* Reserve memory for the buffer. The amount of data won't change
306 * so we are safe with calling glBufferData once with a NULL ptr and
307 * calling glBufferSubData on updates
309 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
310 error = glGetError();
311 if(error != GL_NO_ERROR) {
312 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
313 goto error;
316 LEAVE_GL();
318 return;
319 error:
320 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
321 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
322 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
323 object->vbo = 0;
324 object->Flags |= VBFLAG_VBOCREATEFAIL;
325 LEAVE_GL();
326 return;
329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
330 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
331 IUnknown *parent) {
332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
333 IWineD3DVertexBufferImpl *object;
334 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
335 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
336 BOOL conv;
338 if(Size == 0) {
339 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
340 *ppVertexBuffer = NULL;
341 return WINED3DERR_INVALIDCALL;
344 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
346 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
347 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
349 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
350 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
352 object->fvf = FVF;
354 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
355 * drawStridedFast (half-life 2).
357 * Basically converting the vertices in the buffer is quite expensive, and observations
358 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
359 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
361 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
362 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
363 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
364 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
365 * dx7 apps.
366 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
367 * more. In this call we can convert dx7 buffers too.
369 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
370 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
371 (dxVersion > 7 || !conv) ) {
372 CreateVBO(object);
374 return WINED3D_OK;
377 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
378 GLenum error, glUsage;
379 TRACE("Creating VBO for Index Buffer %p\n", object);
381 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
382 * restored on the next draw
384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
386 ENTER_GL();
387 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
388 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
390 while(glGetError());
392 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
393 error = glGetError();
394 if(error != GL_NO_ERROR || object->vbo == 0) {
395 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
396 goto out;
399 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
400 error = glGetError();
401 if(error != GL_NO_ERROR) {
402 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
403 goto out;
406 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
407 * copy no readback will be needed
409 glUsage = GL_STATIC_DRAW_ARB;
410 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
411 error = glGetError();
412 if(error != GL_NO_ERROR) {
413 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
414 goto out;
416 LEAVE_GL();
417 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
418 return;
420 out:
421 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
422 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
423 LEAVE_GL();
424 object->vbo = 0;
427 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
428 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
429 HANDLE *sharedHandle, IUnknown *parent) {
430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
431 IWineD3DIndexBufferImpl *object;
432 TRACE("(%p) Creating index buffer\n", This);
434 /* Allocate the storage for the device */
435 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
437 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
438 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
441 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
442 CreateIndexBufferVBO(This, object);
445 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
446 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
447 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
449 return WINED3D_OK;
452 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
455 IWineD3DStateBlockImpl *object;
456 int i, j;
457 HRESULT temp_result;
459 D3DCREATEOBJECTINSTANCE(object, StateBlock)
460 object->blockType = Type;
462 for(i = 0; i < LIGHTMAP_SIZE; i++) {
463 list_init(&object->lightMap[i]);
466 /* Special case - Used during initialization to produce a placeholder stateblock
467 so other functions called can update a state block */
468 if (Type == WINED3DSBT_INIT) {
469 /* Don't bother increasing the reference count otherwise a device will never
470 be freed due to circular dependencies */
471 return WINED3D_OK;
474 temp_result = allocate_shader_constants(object);
475 if (WINED3D_OK != temp_result)
476 return temp_result;
478 /* Otherwise, might as well set the whole state block to the appropriate values */
479 if (This->stateBlock != NULL)
480 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
481 else
482 memset(object->streamFreq, 1, sizeof(object->streamFreq));
484 /* Reset the ref and type after kludging it */
485 object->wineD3DDevice = This;
486 object->ref = 1;
487 object->blockType = Type;
489 TRACE("Updating changed flags appropriate for type %d\n", Type);
491 if (Type == WINED3DSBT_ALL) {
493 TRACE("ALL => Pretend everything has changed\n");
494 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
496 /* Lights are not part of the changed / set structure */
497 for(j = 0; j < LIGHTMAP_SIZE; j++) {
498 struct list *e;
499 LIST_FOR_EACH(e, &object->lightMap[j]) {
500 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
501 light->changed = TRUE;
502 light->enabledChanged = TRUE;
505 } else if (Type == WINED3DSBT_PIXELSTATE) {
507 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
508 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
510 object->changed.pixelShader = TRUE;
512 /* Pixel Shader Constants */
513 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
514 object->changed.pixelShaderConstantsF[i] = TRUE;
515 for (i = 0; i < MAX_CONST_B; ++i)
516 object->changed.pixelShaderConstantsB[i] = TRUE;
517 for (i = 0; i < MAX_CONST_I; ++i)
518 object->changed.pixelShaderConstantsI[i] = TRUE;
520 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
521 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
523 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
524 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
525 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
528 for (j = 0 ; j < 16; j++) {
529 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
531 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
535 } else if (Type == WINED3DSBT_VERTEXSTATE) {
537 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
538 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
540 object->changed.vertexShader = TRUE;
542 /* Vertex Shader Constants */
543 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
544 object->changed.vertexShaderConstantsF[i] = TRUE;
545 for (i = 0; i < MAX_CONST_B; ++i)
546 object->changed.vertexShaderConstantsB[i] = TRUE;
547 for (i = 0; i < MAX_CONST_I; ++i)
548 object->changed.vertexShaderConstantsI[i] = TRUE;
550 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
551 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
553 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
554 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
555 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
558 for (j = 0 ; j < 16; j++){
559 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
560 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
564 for(j = 0; j < LIGHTMAP_SIZE; j++) {
565 struct list *e;
566 LIST_FOR_EACH(e, &object->lightMap[j]) {
567 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
568 light->changed = TRUE;
569 light->enabledChanged = TRUE;
572 } else {
573 FIXME("Unrecognized state block type %d\n", Type);
576 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
577 return WINED3D_OK;
581 /* ************************************
582 MSDN:
583 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
585 Discard
586 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
588 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.
590 ******************************** */
592 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) {
593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
594 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
595 unsigned int pow2Width, pow2Height;
596 unsigned int Size = 1;
597 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
598 TRACE("(%p) Create surface\n",This);
600 /** FIXME: Check ranges on the inputs are valid
601 * MSDN
602 * MultisampleQuality
603 * [in] Quality level. The valid range is between zero and one less than the level
604 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
605 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
606 * values of paired render targets, depth stencil surfaces, and the MultiSample type
607 * must all match.
608 *******************************/
612 * TODO: Discard MSDN
613 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
615 * If this flag is set, the contents of the depth stencil buffer will be
616 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
617 * with a different depth surface.
619 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
620 ***************************/
622 if(MultisampleQuality < 0) {
623 FIXME("Invalid multisample level %d\n", MultisampleQuality);
624 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
627 if(MultisampleQuality > 0) {
628 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
629 MultisampleQuality=0;
632 /** FIXME: Check that the format is supported
633 * by the device.
634 *******************************/
636 /* Non-power2 support */
637 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
638 pow2Width = Width;
639 pow2Height = Height;
640 } else {
641 /* Find the nearest pow2 match */
642 pow2Width = pow2Height = 1;
643 while (pow2Width < Width) pow2Width <<= 1;
644 while (pow2Height < Height) pow2Height <<= 1;
647 if (pow2Width > Width || pow2Height > Height) {
648 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
649 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
650 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
651 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
652 This, Width, Height);
653 return WINED3DERR_NOTAVAILABLE;
657 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
658 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
659 * space!
660 *********************************/
661 if (WINED3DFMT_UNKNOWN == Format) {
662 Size = 0;
663 } else if (Format == WINED3DFMT_DXT1) {
664 /* DXT1 is half byte per pixel */
665 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
667 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
668 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
669 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
670 } else {
671 /* The pitch is a multiple of 4 bytes */
672 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
673 Size *= Height;
676 /** Create and initialise the surface resource **/
677 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
678 /* "Standalone" surface */
679 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
681 object->currentDesc.Width = Width;
682 object->currentDesc.Height = Height;
683 object->currentDesc.MultiSampleType = MultiSample;
684 object->currentDesc.MultiSampleQuality = MultisampleQuality;
686 /* Setup some glformat defaults */
687 object->glDescription.glFormat = tableEntry->glFormat;
688 object->glDescription.glFormatInternal = tableEntry->glInternal;
689 object->glDescription.glType = tableEntry->glType;
691 object->glDescription.textureName = 0;
692 object->glDescription.level = Level;
693 object->glDescription.target = GL_TEXTURE_2D;
695 /* Internal data */
696 object->pow2Width = pow2Width;
697 object->pow2Height = pow2Height;
699 /* Flags */
700 object->Flags = SFLAG_DYNLOCK;
701 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
702 object->Flags |= Discard ? SFLAG_DISCARD : 0;
703 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
704 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
707 if (WINED3DFMT_UNKNOWN != Format) {
708 object->bytesPerPixel = tableEntry->bpp;
709 } else {
710 object->bytesPerPixel = 0;
713 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
715 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
717 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
718 * this function is too deep to need to care about things like this.
719 * Levels need to be checked too, and possibly Type since they all affect what can be done.
720 * ****************************************/
721 switch(Pool) {
722 case WINED3DPOOL_SCRATCH:
723 if(!Lockable)
724 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
725 "which are mutually exclusive, setting lockable to TRUE\n");
726 Lockable = TRUE;
727 break;
728 case WINED3DPOOL_SYSTEMMEM:
729 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
730 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
731 case WINED3DPOOL_MANAGED:
732 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
733 "Usage of DYNAMIC which are mutually exclusive, not doing "
734 "anything just telling you.\n");
735 break;
736 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
737 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
738 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
739 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
740 break;
741 default:
742 FIXME("(%p) Unknown pool %d\n", This, Pool);
743 break;
746 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
747 FIXME("Trying to create a render target that isn't in the default pool\n");
750 /* mark the texture as dirty so that it gets loaded first time around*/
751 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
752 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
753 This, Width, Height, Format, debug_d3dformat(Format),
754 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
756 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
757 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
758 This->ddraw_primary = (IWineD3DSurface *) object;
760 /* Look at the implementation and set the correct Vtable */
761 switch(Impl) {
762 case SURFACE_OPENGL:
763 /* Nothing to do, it's set already */
764 break;
766 case SURFACE_GDI:
767 object->lpVtbl = &IWineGDISurface_Vtbl;
768 break;
770 default:
771 /* To be sure to catch this */
772 ERR("Unknown requested surface implementation %d!\n", Impl);
773 IWineD3DSurface_Release((IWineD3DSurface *) object);
774 return WINED3DERR_INVALIDCALL;
777 list_init(&object->renderbuffers);
779 /* Call the private setup routine */
780 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
784 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
785 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
786 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
787 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
790 IWineD3DTextureImpl *object;
791 unsigned int i;
792 UINT tmpW;
793 UINT tmpH;
794 HRESULT hr;
795 unsigned int pow2Width;
796 unsigned int pow2Height;
799 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
800 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
801 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
803 /* TODO: It should only be possible to create textures for formats
804 that are reported as supported */
805 if (WINED3DFMT_UNKNOWN >= Format) {
806 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
807 return WINED3DERR_INVALIDCALL;
810 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
811 D3DINITIALIZEBASETEXTURE(object->baseTexture);
812 object->width = Width;
813 object->height = Height;
815 /** Non-power2 support **/
816 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
817 pow2Width = Width;
818 pow2Height = Height;
819 } else {
820 /* Find the nearest pow2 match */
821 pow2Width = pow2Height = 1;
822 while (pow2Width < Width) pow2Width <<= 1;
823 while (pow2Height < Height) pow2Height <<= 1;
826 /** FIXME: add support for real non-power-two if it's provided by the video card **/
827 /* Precalculated scaling for 'faked' non power of two texture coords */
828 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
829 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
830 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
832 /* Calculate levels for mip mapping */
833 if (Levels == 0) {
834 TRACE("calculating levels %d\n", object->baseTexture.levels);
835 object->baseTexture.levels++;
836 tmpW = Width;
837 tmpH = Height;
838 while (tmpW > 1 || tmpH > 1) {
839 tmpW = max(1, tmpW >> 1);
840 tmpH = max(1, tmpH >> 1);
841 object->baseTexture.levels++;
843 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
846 /* Generate all the surfaces */
847 tmpW = Width;
848 tmpH = Height;
849 for (i = 0; i < object->baseTexture.levels; i++)
851 /* use the callback to create the texture surface */
852 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
853 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
854 FIXME("Failed to create surface %p\n", object);
855 /* clean up */
856 object->surfaces[i] = NULL;
857 IWineD3DTexture_Release((IWineD3DTexture *)object);
859 *ppTexture = NULL;
860 return hr;
863 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
864 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
865 /* calculate the next mipmap level */
866 tmpW = max(1, tmpW >> 1);
867 tmpH = max(1, tmpH >> 1);
870 TRACE("(%p) : Created texture %p\n", This, object);
871 return WINED3D_OK;
874 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
875 UINT Width, UINT Height, UINT Depth,
876 UINT Levels, DWORD Usage,
877 WINED3DFORMAT Format, WINED3DPOOL Pool,
878 IWineD3DVolumeTexture **ppVolumeTexture,
879 HANDLE *pSharedHandle, IUnknown *parent,
880 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
883 IWineD3DVolumeTextureImpl *object;
884 unsigned int i;
885 UINT tmpW;
886 UINT tmpH;
887 UINT tmpD;
889 /* TODO: It should only be possible to create textures for formats
890 that are reported as supported */
891 if (WINED3DFMT_UNKNOWN >= Format) {
892 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
893 return WINED3DERR_INVALIDCALL;
896 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
897 D3DINITIALIZEBASETEXTURE(object->baseTexture);
899 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
900 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
902 object->width = Width;
903 object->height = Height;
904 object->depth = Depth;
906 /* Calculate levels for mip mapping */
907 if (Levels == 0) {
908 object->baseTexture.levels++;
909 tmpW = Width;
910 tmpH = Height;
911 tmpD = Depth;
912 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
913 tmpW = max(1, tmpW >> 1);
914 tmpH = max(1, tmpH >> 1);
915 tmpD = max(1, tmpD >> 1);
916 object->baseTexture.levels++;
918 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
921 /* Generate all the surfaces */
922 tmpW = Width;
923 tmpH = Height;
924 tmpD = Depth;
926 for (i = 0; i < object->baseTexture.levels; i++)
928 HRESULT hr;
929 /* Create the volume */
930 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
931 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
933 if(FAILED(hr)) {
934 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
935 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
936 *ppVolumeTexture = NULL;
937 return hr;
940 /* Set its container to this object */
941 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
943 /* calcualte the next mipmap level */
944 tmpW = max(1, tmpW >> 1);
945 tmpH = max(1, tmpH >> 1);
946 tmpD = max(1, tmpD >> 1);
949 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
950 TRACE("(%p) : Created volume texture %p\n", This, object);
951 return WINED3D_OK;
954 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
955 UINT Width, UINT Height, UINT Depth,
956 DWORD Usage,
957 WINED3DFORMAT Format, WINED3DPOOL Pool,
958 IWineD3DVolume** ppVolume,
959 HANDLE* pSharedHandle, IUnknown *parent) {
961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
962 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
963 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
965 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
967 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
968 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
970 object->currentDesc.Width = Width;
971 object->currentDesc.Height = Height;
972 object->currentDesc.Depth = Depth;
973 object->bytesPerPixel = formatDesc->bpp;
975 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
976 object->lockable = TRUE;
977 object->locked = FALSE;
978 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
979 object->dirty = TRUE;
981 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
984 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
985 UINT Levels, DWORD Usage,
986 WINED3DFORMAT Format, WINED3DPOOL Pool,
987 IWineD3DCubeTexture **ppCubeTexture,
988 HANDLE *pSharedHandle, IUnknown *parent,
989 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
992 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
993 unsigned int i, j;
994 UINT tmpW;
995 HRESULT hr;
996 unsigned int pow2EdgeLength = EdgeLength;
998 /* TODO: It should only be possible to create textures for formats
999 that are reported as supported */
1000 if (WINED3DFMT_UNKNOWN >= Format) {
1001 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1002 return WINED3DERR_INVALIDCALL;
1005 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1006 WARN("(%p) : Tried to create not supported cube texture\n", This);
1007 return WINED3DERR_INVALIDCALL;
1010 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1011 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1013 TRACE("(%p) Create Cube Texture\n", This);
1015 /** Non-power2 support **/
1017 /* Find the nearest pow2 match */
1018 pow2EdgeLength = 1;
1019 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1021 object->edgeLength = EdgeLength;
1022 /* TODO: support for native non-power 2 */
1023 /* Precalculated scaling for 'faked' non power of two texture coords */
1024 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1026 /* Calculate levels for mip mapping */
1027 if (Levels == 0) {
1028 object->baseTexture.levels++;
1029 tmpW = EdgeLength;
1030 while (tmpW > 1) {
1031 tmpW = max(1, tmpW >> 1);
1032 object->baseTexture.levels++;
1034 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1037 /* Generate all the surfaces */
1038 tmpW = EdgeLength;
1039 for (i = 0; i < object->baseTexture.levels; i++) {
1041 /* Create the 6 faces */
1042 for (j = 0; j < 6; j++) {
1044 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1045 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1047 if(hr!= WINED3D_OK) {
1048 /* clean up */
1049 int k;
1050 int l;
1051 for (l = 0; l < j; l++) {
1052 IWineD3DSurface_Release(object->surfaces[j][i]);
1054 for (k = 0; k < i; k++) {
1055 for (l = 0; l < 6; l++) {
1056 IWineD3DSurface_Release(object->surfaces[l][j]);
1060 FIXME("(%p) Failed to create surface\n",object);
1061 HeapFree(GetProcessHeap(),0,object);
1062 *ppCubeTexture = NULL;
1063 return hr;
1065 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1066 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1068 tmpW = max(1, tmpW >> 1);
1071 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1072 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1073 return WINED3D_OK;
1076 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1078 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1079 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1081 /* Just a check to see if we support this type of query */
1082 switch(Type) {
1083 case WINED3DQUERYTYPE_OCCLUSION:
1084 TRACE("(%p) occlusion query\n", This);
1085 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1086 hr = WINED3D_OK;
1087 else
1088 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1089 break;
1091 case WINED3DQUERYTYPE_EVENT:
1092 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1093 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1094 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1096 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1098 hr = WINED3D_OK;
1099 break;
1101 case WINED3DQUERYTYPE_VCACHE:
1102 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1103 case WINED3DQUERYTYPE_VERTEXSTATS:
1104 case WINED3DQUERYTYPE_TIMESTAMP:
1105 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1106 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1107 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1108 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1109 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1110 case WINED3DQUERYTYPE_PIXELTIMINGS:
1111 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1112 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1113 default:
1114 FIXME("(%p) Unhandled query type %d\n", This, Type);
1116 if(NULL == ppQuery || hr != WINED3D_OK) {
1117 return hr;
1120 D3DCREATEOBJECTINSTANCE(object, Query)
1121 object->type = Type;
1122 /* allocated the 'extended' data based on the type of query requested */
1123 switch(Type){
1124 case WINED3DQUERYTYPE_OCCLUSION:
1125 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1126 TRACE("(%p) Allocating data for an occlusion query\n", This);
1127 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1128 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1129 break;
1131 case WINED3DQUERYTYPE_EVENT:
1132 /* TODO: GL_APPLE_fence */
1133 if(GL_SUPPORT(APPLE_FENCE)) {
1134 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1135 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1136 checkGLcall("glGenFencesAPPLE");
1137 } else if(GL_SUPPORT(NV_FENCE)) {
1138 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1139 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1140 checkGLcall("glGenFencesNV");
1142 break;
1144 case WINED3DQUERYTYPE_VCACHE:
1145 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1146 case WINED3DQUERYTYPE_VERTEXSTATS:
1147 case WINED3DQUERYTYPE_TIMESTAMP:
1148 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1149 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1150 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1151 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1152 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1153 case WINED3DQUERYTYPE_PIXELTIMINGS:
1154 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1155 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1156 default:
1157 object->extendedData = 0;
1158 FIXME("(%p) Unhandled query type %d\n",This , Type);
1160 TRACE("(%p) : Created Query %p\n", This, object);
1161 return WINED3D_OK;
1164 /*****************************************************************************
1165 * IWineD3DDeviceImpl_SetupFullscreenWindow
1167 * Helper function that modifies a HWND's Style and ExStyle for proper
1168 * fullscreen use.
1170 * Params:
1171 * iface: Pointer to the IWineD3DDevice interface
1172 * window: Window to setup
1174 *****************************************************************************/
1175 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1178 LONG style, exStyle;
1179 /* Don't do anything if an original style is stored.
1180 * That shouldn't happen
1182 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1183 if (This->style || This->exStyle) {
1184 ERR("(%p): Want to change the window parameters of HWND %p, but "
1185 "another style is stored for restoration afterwards\n", This, window);
1188 /* Get the parameters and save them */
1189 style = GetWindowLongW(window, GWL_STYLE);
1190 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1191 This->style = style;
1192 This->exStyle = exStyle;
1194 /* Filter out window decorations */
1195 style &= ~WS_CAPTION;
1196 style &= ~WS_THICKFRAME;
1197 exStyle &= ~WS_EX_WINDOWEDGE;
1198 exStyle &= ~WS_EX_CLIENTEDGE;
1200 /* Make sure the window is managed, otherwise we won't get keyboard input */
1201 style |= WS_POPUP | WS_SYSMENU;
1203 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1204 This->style, This->exStyle, style, exStyle);
1206 SetWindowLongW(window, GWL_STYLE, style);
1207 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1209 /* Inform the window about the update. */
1210 SetWindowPos(window, HWND_TOP, 0, 0,
1211 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1212 ShowWindow(window, SW_NORMAL);
1215 /*****************************************************************************
1216 * IWineD3DDeviceImpl_RestoreWindow
1218 * Helper function that restores a windows' properties when taking it out
1219 * of fullscreen mode
1221 * Params:
1222 * iface: Pointer to the IWineD3DDevice interface
1223 * window: Window to setup
1225 *****************************************************************************/
1226 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1229 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1230 * switch, do nothing
1232 if (!This->style && !This->exStyle) return;
1234 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1235 This, window, This->style, This->exStyle);
1237 SetWindowLongW(window, GWL_STYLE, This->style);
1238 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1240 /* Delete the old values */
1241 This->style = 0;
1242 This->exStyle = 0;
1244 /* Inform the window about the update */
1245 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1246 0, 0, 0, 0, /* Pos, Size, ignored */
1247 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1250 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1251 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1252 IUnknown* parent,
1253 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1254 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1257 HDC hDc;
1258 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1259 HRESULT hr = WINED3D_OK;
1260 IUnknown *bufferParent;
1261 Display *display;
1263 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1265 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1266 * does a device hold a reference to a swap chain giving them a lifetime of the device
1267 * or does the swap chain notify the device of its destruction.
1268 *******************************/
1270 /* Check the params */
1271 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1272 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1273 return WINED3DERR_INVALIDCALL;
1274 } else if (pPresentationParameters->BackBufferCount > 1) {
1275 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");
1278 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1280 /*********************
1281 * Lookup the window Handle and the relating X window handle
1282 ********************/
1284 /* Setup hwnd we are using, plus which display this equates to */
1285 object->win_handle = pPresentationParameters->hDeviceWindow;
1286 if (!object->win_handle) {
1287 object->win_handle = This->createParms.hFocusWindow;
1290 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1291 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1292 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1293 return WINED3DERR_NOTAVAILABLE;
1295 hDc = GetDC(object->win_handle);
1296 display = get_display(hDc);
1297 ReleaseDC(object->win_handle, hDc);
1298 TRACE("Using a display of %p %p\n", display, hDc);
1300 if (NULL == display || NULL == hDc) {
1301 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1302 return WINED3DERR_NOTAVAILABLE;
1305 if (object->win == 0) {
1306 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1307 return WINED3DERR_NOTAVAILABLE;
1310 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1311 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1312 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1314 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1315 * then the corresponding dimension of the client area of the hDeviceWindow
1316 * (or the focus window, if hDeviceWindow is NULL) is taken.
1317 **********************/
1319 if (pPresentationParameters->Windowed &&
1320 ((pPresentationParameters->BackBufferWidth == 0) ||
1321 (pPresentationParameters->BackBufferHeight == 0))) {
1323 RECT Rect;
1324 GetClientRect(object->win_handle, &Rect);
1326 if (pPresentationParameters->BackBufferWidth == 0) {
1327 pPresentationParameters->BackBufferWidth = Rect.right;
1328 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1330 if (pPresentationParameters->BackBufferHeight == 0) {
1331 pPresentationParameters->BackBufferHeight = Rect.bottom;
1332 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1336 /* Put the correct figures in the presentation parameters */
1337 TRACE("Copying across presentation parameters\n");
1338 object->presentParms = *pPresentationParameters;
1340 TRACE("calling rendertarget CB\n");
1341 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1342 parent,
1343 object->presentParms.BackBufferWidth,
1344 object->presentParms.BackBufferHeight,
1345 object->presentParms.BackBufferFormat,
1346 object->presentParms.MultiSampleType,
1347 object->presentParms.MultiSampleQuality,
1348 TRUE /* Lockable */,
1349 &object->frontBuffer,
1350 NULL /* pShared (always null)*/);
1351 if (object->frontBuffer != NULL) {
1352 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1353 } else {
1354 ERR("Failed to create the front buffer\n");
1355 goto error;
1359 * Create an opengl context for the display visual
1360 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1361 * use different properties after that point in time. FIXME: How to handle when requested format
1362 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1363 * it chooses is identical to the one already being used!
1364 **********************************/
1365 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1367 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1368 if(!object->context) {
1370 object->num_contexts = 1;
1372 ENTER_GL();
1373 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1374 LEAVE_GL();
1376 if (!object->context) {
1377 ERR("Failed to create a new context\n");
1378 hr = WINED3DERR_NOTAVAILABLE;
1379 goto error;
1380 } else {
1381 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1382 object->win_handle, object->context[0]->glCtx, object->win);
1385 /*********************
1386 * Windowed / Fullscreen
1387 *******************/
1390 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1391 * so we should really check to see if there is a fullscreen swapchain already
1392 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1393 **************************************/
1395 if (!pPresentationParameters->Windowed) {
1397 DEVMODEW devmode;
1398 HDC hdc;
1399 int bpp = 0;
1400 RECT clip_rc;
1402 /* Get info on the current display setup */
1403 hdc = GetDC(0);
1404 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1405 ReleaseDC(0, hdc);
1407 /* Change the display settings */
1408 memset(&devmode, 0, sizeof(DEVMODEW));
1409 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1410 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1411 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1412 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1413 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1414 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1416 /* For GetDisplayMode */
1417 This->ddraw_width = devmode.dmPelsWidth;
1418 This->ddraw_height = devmode.dmPelsHeight;
1419 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1421 IWineD3DDevice_SetFullscreen(iface, TRUE);
1423 /* And finally clip mouse to our screen */
1424 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1425 ClipCursor(&clip_rc);
1428 /*********************
1429 * Create the back, front and stencil buffers
1430 *******************/
1431 if(object->presentParms.BackBufferCount > 0) {
1432 int i;
1434 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1435 if(!object->backBuffer) {
1436 ERR("Out of memory\n");
1437 hr = E_OUTOFMEMORY;
1438 goto error;
1441 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1442 TRACE("calling rendertarget CB\n");
1443 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1444 parent,
1445 object->presentParms.BackBufferWidth,
1446 object->presentParms.BackBufferHeight,
1447 object->presentParms.BackBufferFormat,
1448 object->presentParms.MultiSampleType,
1449 object->presentParms.MultiSampleQuality,
1450 TRUE /* Lockable */,
1451 &object->backBuffer[i],
1452 NULL /* pShared (always null)*/);
1453 if(hr == WINED3D_OK && object->backBuffer[i]) {
1454 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1455 } else {
1456 ERR("Cannot create new back buffer\n");
1457 goto error;
1459 ENTER_GL();
1460 glDrawBuffer(GL_BACK);
1461 checkGLcall("glDrawBuffer(GL_BACK)");
1462 LEAVE_GL();
1464 } else {
1465 object->backBuffer = NULL;
1467 /* Single buffering - draw to front buffer */
1468 ENTER_GL();
1469 glDrawBuffer(GL_FRONT);
1470 checkGLcall("glDrawBuffer(GL_FRONT)");
1471 LEAVE_GL();
1474 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1475 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1476 TRACE("Creating depth stencil buffer\n");
1477 if (This->depthStencilBuffer == NULL ) {
1478 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1479 parent,
1480 object->presentParms.BackBufferWidth,
1481 object->presentParms.BackBufferHeight,
1482 object->presentParms.AutoDepthStencilFormat,
1483 object->presentParms.MultiSampleType,
1484 object->presentParms.MultiSampleQuality,
1485 FALSE /* FIXME: Discard */,
1486 &This->depthStencilBuffer,
1487 NULL /* pShared (always null)*/ );
1488 if (This->depthStencilBuffer != NULL)
1489 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1492 /** TODO: A check on width, height and multisample types
1493 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1494 ****************************/
1495 object->wantsDepthStencilBuffer = TRUE;
1496 } else {
1497 object->wantsDepthStencilBuffer = FALSE;
1500 TRACE("Created swapchain %p\n", object);
1501 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1502 return WINED3D_OK;
1504 error:
1505 if (object->backBuffer) {
1506 int i;
1507 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1508 if(object->backBuffer[i]) {
1509 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1510 IUnknown_Release(bufferParent); /* once for the get parent */
1511 if (IUnknown_Release(bufferParent) > 0) {
1512 FIXME("(%p) Something's still holding the back buffer\n",This);
1516 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1517 object->backBuffer = NULL;
1519 if(object->context) {
1520 DestroyContext(This, object->context[0]);
1522 if(object->frontBuffer) {
1523 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1524 IUnknown_Release(bufferParent); /* once for the get parent */
1525 if (IUnknown_Release(bufferParent) > 0) {
1526 FIXME("(%p) Something's still holding the front buffer\n",This);
1529 HeapFree(GetProcessHeap(), 0, object);
1530 return hr;
1533 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1534 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1536 TRACE("(%p)\n", This);
1538 return This->NumberOfSwapChains;
1541 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1543 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1545 if(iSwapChain < This->NumberOfSwapChains) {
1546 *pSwapChain = This->swapchains[iSwapChain];
1547 IWineD3DSwapChain_AddRef(*pSwapChain);
1548 TRACE("(%p) returning %p\n", This, *pSwapChain);
1549 return WINED3D_OK;
1550 } else {
1551 TRACE("Swapchain out of range\n");
1552 *pSwapChain = NULL;
1553 return WINED3DERR_INVALIDCALL;
1557 /*****
1558 * Vertex Declaration
1559 *****/
1560 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1561 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1563 IWineD3DVertexDeclarationImpl *object = NULL;
1564 HRESULT hr = WINED3D_OK;
1566 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1567 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1569 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1571 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1573 return hr;
1576 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1578 unsigned int idx, idx2;
1579 unsigned int offset;
1580 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1581 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1582 BOOL has_blend_idx = has_blend &&
1583 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1584 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1585 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1586 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1587 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1588 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1589 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1591 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1592 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1594 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1595 WINED3DVERTEXELEMENT *elements = NULL;
1597 unsigned int size;
1598 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1599 if (has_blend_idx) num_blends--;
1601 /* Compute declaration size */
1602 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1603 has_psize + has_diffuse + has_specular + num_textures + 1;
1605 /* convert the declaration */
1606 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1607 if (!elements)
1608 return 0;
1610 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1611 idx = 0;
1612 if (has_pos) {
1613 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1614 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1615 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1617 else {
1618 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1619 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1621 elements[idx].UsageIndex = 0;
1622 idx++;
1624 if (has_blend && (num_blends > 0)) {
1625 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1626 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1627 else
1628 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1629 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1630 elements[idx].UsageIndex = 0;
1631 idx++;
1633 if (has_blend_idx) {
1634 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1635 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1636 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1637 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1638 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1639 else
1640 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1641 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1642 elements[idx].UsageIndex = 0;
1643 idx++;
1645 if (has_normal) {
1646 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1647 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1648 elements[idx].UsageIndex = 0;
1649 idx++;
1651 if (has_psize) {
1652 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1653 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1654 elements[idx].UsageIndex = 0;
1655 idx++;
1657 if (has_diffuse) {
1658 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1659 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1660 elements[idx].UsageIndex = 0;
1661 idx++;
1663 if (has_specular) {
1664 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1665 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1666 elements[idx].UsageIndex = 1;
1667 idx++;
1669 for (idx2 = 0; idx2 < num_textures; idx2++) {
1670 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1671 switch (numcoords) {
1672 case WINED3DFVF_TEXTUREFORMAT1:
1673 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1674 break;
1675 case WINED3DFVF_TEXTUREFORMAT2:
1676 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1677 break;
1678 case WINED3DFVF_TEXTUREFORMAT3:
1679 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1680 break;
1681 case WINED3DFVF_TEXTUREFORMAT4:
1682 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1683 break;
1685 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1686 elements[idx].UsageIndex = idx2;
1687 idx++;
1690 /* Now compute offsets, and initialize the rest of the fields */
1691 for (idx = 0, offset = 0; idx < size-1; idx++) {
1692 elements[idx].Stream = 0;
1693 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1694 elements[idx].Offset = offset;
1695 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1698 *ppVertexElements = elements;
1699 return size;
1702 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1703 WINED3DVERTEXELEMENT* elements = NULL;
1704 size_t size;
1705 DWORD hr;
1707 size = ConvertFvfToDeclaration(Fvf, &elements);
1708 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1710 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1711 HeapFree(GetProcessHeap(), 0, elements);
1712 if (hr != S_OK) return hr;
1714 return WINED3D_OK;
1717 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1718 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1720 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1721 HRESULT hr = WINED3D_OK;
1722 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1723 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1725 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1727 if (vertex_declaration) {
1728 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1731 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1733 if (WINED3D_OK != hr) {
1734 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1735 IWineD3DVertexShader_Release(*ppVertexShader);
1736 return WINED3DERR_INVALIDCALL;
1739 return WINED3D_OK;
1742 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1744 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1745 HRESULT hr = WINED3D_OK;
1747 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1748 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1749 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1750 if (WINED3D_OK == hr) {
1751 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1752 } else {
1753 WARN("(%p) : Failed to create pixel shader\n", This);
1756 return hr;
1759 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1761 IWineD3DPaletteImpl *object;
1762 HRESULT hr;
1763 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1765 /* Create the new object */
1766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1767 if(!object) {
1768 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1769 return E_OUTOFMEMORY;
1772 object->lpVtbl = &IWineD3DPalette_Vtbl;
1773 object->ref = 1;
1774 object->Flags = Flags;
1775 object->parent = Parent;
1776 object->wineD3DDevice = This;
1777 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1779 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1781 if(!object->hpal) {
1782 HeapFree( GetProcessHeap(), 0, object);
1783 return E_OUTOFMEMORY;
1786 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1787 if(FAILED(hr)) {
1788 IWineD3DPalette_Release((IWineD3DPalette *) object);
1789 return hr;
1792 *Palette = (IWineD3DPalette *) object;
1794 return WINED3D_OK;
1797 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1799 IWineD3DSwapChainImpl *swapchain;
1800 DWORD state;
1802 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1803 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1805 /* TODO: Test if OpenGL is compiled in and loaded */
1807 /* Initialize the texture unit mapping to a 1:1 mapping */
1808 for(state = 0; state < MAX_SAMPLERS; state++) {
1809 This->texUnitMap[state] = state;
1811 This->oneToOneTexUnitMap = TRUE;
1813 /* Setup the implicit swapchain */
1814 TRACE("Creating implicit swapchain\n");
1815 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1816 WARN("Failed to create implicit swapchain\n");
1817 return WINED3DERR_INVALIDCALL;
1820 This->NumberOfSwapChains = 1;
1821 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1822 if(!This->swapchains) {
1823 ERR("Out of memory!\n");
1824 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1825 return E_OUTOFMEMORY;
1827 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1829 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1831 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1832 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1833 This->render_targets[0] = swapchain->backBuffer[0];
1834 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1836 else {
1837 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1838 This->render_targets[0] = swapchain->frontBuffer;
1839 This->lastActiveRenderTarget = swapchain->frontBuffer;
1841 IWineD3DSurface_AddRef(This->render_targets[0]);
1842 This->activeContext = swapchain->context[0];
1844 /* Depth Stencil support */
1845 This->stencilBufferTarget = This->depthStencilBuffer;
1846 if (NULL != This->stencilBufferTarget) {
1847 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1850 /* Set up some starting GL setup */
1851 ENTER_GL();
1853 * Initialize openGL extension related variables
1854 * with Default values
1857 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1858 /* Setup all the devices defaults */
1859 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1860 #if 0
1861 IWineD3DImpl_CheckGraphicsMemory();
1862 #endif
1864 { /* Set a default viewport */
1865 WINED3DVIEWPORT vp;
1866 vp.X = 0;
1867 vp.Y = 0;
1868 vp.Width = pPresentationParameters->BackBufferWidth;
1869 vp.Height = pPresentationParameters->BackBufferHeight;
1870 vp.MinZ = 0.0f;
1871 vp.MaxZ = 1.0f;
1872 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1875 /* Initialize the current view state */
1876 This->view_ident = 1;
1877 This->contexts[0]->last_was_rhw = 0;
1878 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1879 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1881 switch(wined3d_settings.offscreen_rendering_mode) {
1882 case ORM_FBO:
1883 case ORM_PBUFFER:
1884 This->offscreenBuffer = GL_BACK;
1885 break;
1887 case ORM_BACKBUFFER:
1889 if(GL_LIMITS(aux_buffers) > 0) {
1890 TRACE("Using auxilliary buffer for offscreen rendering\n");
1891 This->offscreenBuffer = GL_AUX0;
1892 } else {
1893 TRACE("Using back buffer for offscreen rendering\n");
1894 This->offscreenBuffer = GL_BACK;
1899 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1900 LEAVE_GL();
1902 /* Clear the screen */
1903 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1904 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1905 0x00, 1.0, 0);
1907 This->d3d_initialized = TRUE;
1908 return WINED3D_OK;
1911 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1913 int sampler;
1914 uint i;
1915 TRACE("(%p)\n", This);
1917 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1919 ENTER_GL();
1920 /* I don't think that the interface guarants that the device is destroyed from the same thread
1921 * it was created. Thus make sure a context is active for the glDelete* calls
1923 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1924 LEAVE_GL();
1926 /* Delete the pbuffer context if there is any */
1927 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1929 /* Delete the mouse cursor texture */
1930 if(This->cursorTexture) {
1931 ENTER_GL();
1932 glDeleteTextures(1, &This->cursorTexture);
1933 LEAVE_GL();
1934 This->cursorTexture = 0;
1937 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1938 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1941 /* Release the buffers (with sanity checks)*/
1942 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1943 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1944 if(This->depthStencilBuffer != This->stencilBufferTarget)
1945 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1947 This->stencilBufferTarget = NULL;
1949 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1950 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1951 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1953 TRACE("Setting rendertarget to NULL\n");
1954 This->render_targets[0] = NULL;
1956 if (This->depthStencilBuffer) {
1957 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1958 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1960 This->depthStencilBuffer = NULL;
1963 for(i=0; i < This->NumberOfSwapChains; i++) {
1964 TRACE("Releasing the implicit swapchain %d\n", i);
1965 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1966 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1970 HeapFree(GetProcessHeap(), 0, This->swapchains);
1971 This->swapchains = NULL;
1972 This->NumberOfSwapChains = 0;
1974 This->d3d_initialized = FALSE;
1975 return WINED3D_OK;
1978 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1980 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1982 /* Setup the window for fullscreen mode */
1983 if(fullscreen && !This->ddraw_fullscreen) {
1984 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1985 } else if(!fullscreen && This->ddraw_fullscreen) {
1986 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1989 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1990 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1991 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1992 * separately.
1994 This->ddraw_fullscreen = fullscreen;
1997 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1998 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1999 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2001 * There is no way to deactivate thread safety once it is enabled
2003 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2005 FIXME("No thread safety in wined3d yet\n");
2007 /*For now just store the flag(needed in case of ddraw) */
2008 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2010 return;
2013 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2014 DEVMODEW devmode;
2015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2016 LONG ret;
2017 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2018 RECT clip_rc;
2020 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2022 /* Resize the screen even without a window:
2023 * The app could have unset it with SetCooperativeLevel, but not called
2024 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2025 * but we don't have any hwnd
2028 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2029 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2030 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2031 devmode.dmPelsWidth = pMode->Width;
2032 devmode.dmPelsHeight = pMode->Height;
2034 devmode.dmDisplayFrequency = pMode->RefreshRate;
2035 if (pMode->RefreshRate != 0) {
2036 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2039 /* Only change the mode if necessary */
2040 if( (This->ddraw_width == pMode->Width) &&
2041 (This->ddraw_height == pMode->Height) &&
2042 (This->ddraw_format == pMode->Format) &&
2043 (pMode->RefreshRate == 0) ) {
2044 return WINED3D_OK;
2047 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2048 if (ret != DISP_CHANGE_SUCCESSFUL) {
2049 if(devmode.dmDisplayFrequency != 0) {
2050 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2051 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2052 devmode.dmDisplayFrequency = 0;
2053 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2055 if(ret != DISP_CHANGE_SUCCESSFUL) {
2056 return WINED3DERR_NOTAVAILABLE;
2060 /* Store the new values */
2061 This->ddraw_width = pMode->Width;
2062 This->ddraw_height = pMode->Height;
2063 This->ddraw_format = pMode->Format;
2065 /* Only do this with a window of course */
2066 if(This->ddraw_window)
2067 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2069 /* And finally clip mouse to our screen */
2070 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2071 ClipCursor(&clip_rc);
2073 return WINED3D_OK;
2076 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2078 *ppD3D= This->wineD3D;
2079 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2080 IWineD3D_AddRef(*ppD3D);
2081 return WINED3D_OK;
2084 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2085 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2086 * into the video ram as possible and seeing how many fit
2087 * you can also get the correct initial value from nvidia and ATI's driver via X
2088 * texture memory is video memory + AGP memory
2089 *******************/
2090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2091 static BOOL showfixmes = TRUE;
2092 if (showfixmes) {
2093 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2094 (wined3d_settings.emulated_textureram/(1024*1024)),
2095 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2096 showfixmes = FALSE;
2098 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2099 (wined3d_settings.emulated_textureram/(1024*1024)),
2100 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2101 /* return simulated texture memory left */
2102 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2107 /*****
2108 * Get / Set FVF
2109 *****/
2110 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2113 /* Update the current state block */
2114 This->updateStateBlock->changed.fvf = TRUE;
2115 This->updateStateBlock->set.fvf = TRUE;
2117 if(This->updateStateBlock->fvf == fvf) {
2118 TRACE("Application is setting the old fvf over, nothing to do\n");
2119 return WINED3D_OK;
2122 This->updateStateBlock->fvf = fvf;
2123 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2125 return WINED3D_OK;
2129 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2131 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2132 *pfvf = This->stateBlock->fvf;
2133 return WINED3D_OK;
2136 /*****
2137 * Get / Set Stream Source
2138 *****/
2139 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2141 IWineD3DVertexBuffer *oldSrc;
2143 if (StreamNumber >= MAX_STREAMS) {
2144 WARN("Stream out of range %d\n", StreamNumber);
2145 return WINED3DERR_INVALIDCALL;
2148 oldSrc = This->stateBlock->streamSource[StreamNumber];
2149 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2151 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2152 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2154 if(oldSrc == pStreamData &&
2155 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2156 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2157 TRACE("Application is setting the old values over, nothing to do\n");
2158 return WINED3D_OK;
2161 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2162 if (pStreamData) {
2163 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2164 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2167 /* Handle recording of state blocks */
2168 if (This->isRecordingState) {
2169 TRACE("Recording... not performing anything\n");
2170 return WINED3D_OK;
2173 /* Need to do a getParent and pass the reffs up */
2174 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2175 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2176 so for now, just count internally */
2177 if (pStreamData != NULL) {
2178 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2179 InterlockedIncrement(&vbImpl->bindCount);
2181 if (oldSrc != NULL) {
2182 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2187 return WINED3D_OK;
2190 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2193 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2194 This->stateBlock->streamSource[StreamNumber],
2195 This->stateBlock->streamOffset[StreamNumber],
2196 This->stateBlock->streamStride[StreamNumber]);
2198 if (StreamNumber >= MAX_STREAMS) {
2199 WARN("Stream out of range %d\n", StreamNumber);
2200 return WINED3DERR_INVALIDCALL;
2202 *pStream = This->stateBlock->streamSource[StreamNumber];
2203 *pStride = This->stateBlock->streamStride[StreamNumber];
2204 if (pOffset) {
2205 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2208 if (*pStream != NULL) {
2209 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2211 return WINED3D_OK;
2214 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2216 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2217 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2219 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2220 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2222 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2223 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2224 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2226 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2227 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2231 return WINED3D_OK;
2234 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2237 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2238 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2240 TRACE("(%p) : returning %d\n", This, *Divider);
2242 return WINED3D_OK;
2245 /*****
2246 * Get / Set & Multiply Transform
2247 *****/
2248 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2251 /* Most of this routine, comments included copied from ddraw tree initially: */
2252 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2254 /* Handle recording of state blocks */
2255 if (This->isRecordingState) {
2256 TRACE("Recording... not performing anything\n");
2257 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2258 This->updateStateBlock->set.transform[d3dts] = TRUE;
2259 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2260 return WINED3D_OK;
2264 * If the new matrix is the same as the current one,
2265 * we cut off any further processing. this seems to be a reasonable
2266 * optimization because as was noticed, some apps (warcraft3 for example)
2267 * tend towards setting the same matrix repeatedly for some reason.
2269 * From here on we assume that the new matrix is different, wherever it matters.
2271 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2272 TRACE("The app is setting the same matrix over again\n");
2273 return WINED3D_OK;
2274 } else {
2275 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2279 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2280 where ViewMat = Camera space, WorldMat = world space.
2282 In OpenGL, camera and world space is combined into GL_MODELVIEW
2283 matrix. The Projection matrix stay projection matrix.
2286 /* Capture the times we can just ignore the change for now */
2287 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2288 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2289 /* Handled by the state manager */
2292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2293 return WINED3D_OK;
2296 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2298 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2299 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2300 return WINED3D_OK;
2303 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2304 WINED3DMATRIX *mat = NULL;
2305 WINED3DMATRIX temp;
2307 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2308 * below means it will be recorded in a state block change, but it
2309 * works regardless where it is recorded.
2310 * If this is found to be wrong, change to StateBlock.
2312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2313 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2315 if (State < HIGHEST_TRANSFORMSTATE)
2317 mat = &This->updateStateBlock->transforms[State];
2318 } else {
2319 FIXME("Unhandled transform state!!\n");
2322 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2324 /* Apply change via set transform - will reapply to eg. lights this way */
2325 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2328 /*****
2329 * Get / Set Light
2330 *****/
2331 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2332 you can reference any indexes you want as long as that number max are enabled at any
2333 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2334 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2335 but when recording, just build a chain pretty much of commands to be replayed. */
2337 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2338 float rho;
2339 PLIGHTINFOEL *object = NULL;
2340 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2341 struct list *e;
2343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2344 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2346 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2347 * the gl driver.
2349 if(!pLight) {
2350 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2351 return WINED3DERR_INVALIDCALL;
2354 switch(pLight->Type) {
2355 case WINED3DLIGHT_POINT:
2356 case WINED3DLIGHT_SPOT:
2357 case WINED3DLIGHT_PARALLELPOINT:
2358 case WINED3DLIGHT_GLSPOT:
2359 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2360 * most wanted
2362 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2363 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2364 return WINED3DERR_INVALIDCALL;
2366 break;
2368 case WINED3DLIGHT_DIRECTIONAL:
2369 /* Ignores attenuation */
2370 break;
2372 default:
2373 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2374 return WINED3DERR_INVALIDCALL;
2377 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2378 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2379 if(object->OriginalIndex == Index) break;
2380 object = NULL;
2383 if(!object) {
2384 TRACE("Adding new light\n");
2385 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2386 if(!object) {
2387 ERR("Out of memory error when allocating a light\n");
2388 return E_OUTOFMEMORY;
2390 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2391 object->glIndex = -1;
2392 object->OriginalIndex = Index;
2393 object->changed = TRUE;
2396 /* Initialize the object */
2397 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,
2398 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2399 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2400 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2401 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2402 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2403 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2405 /* Save away the information */
2406 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2408 switch (pLight->Type) {
2409 case WINED3DLIGHT_POINT:
2410 /* Position */
2411 object->lightPosn[0] = pLight->Position.x;
2412 object->lightPosn[1] = pLight->Position.y;
2413 object->lightPosn[2] = pLight->Position.z;
2414 object->lightPosn[3] = 1.0f;
2415 object->cutoff = 180.0f;
2416 /* FIXME: Range */
2417 break;
2419 case WINED3DLIGHT_DIRECTIONAL:
2420 /* Direction */
2421 object->lightPosn[0] = -pLight->Direction.x;
2422 object->lightPosn[1] = -pLight->Direction.y;
2423 object->lightPosn[2] = -pLight->Direction.z;
2424 object->lightPosn[3] = 0.0;
2425 object->exponent = 0.0f;
2426 object->cutoff = 180.0f;
2427 break;
2429 case WINED3DLIGHT_SPOT:
2430 /* Position */
2431 object->lightPosn[0] = pLight->Position.x;
2432 object->lightPosn[1] = pLight->Position.y;
2433 object->lightPosn[2] = pLight->Position.z;
2434 object->lightPosn[3] = 1.0;
2436 /* Direction */
2437 object->lightDirn[0] = pLight->Direction.x;
2438 object->lightDirn[1] = pLight->Direction.y;
2439 object->lightDirn[2] = pLight->Direction.z;
2440 object->lightDirn[3] = 1.0;
2443 * opengl-ish and d3d-ish spot lights use too different models for the
2444 * light "intensity" as a function of the angle towards the main light direction,
2445 * so we only can approximate very roughly.
2446 * however spot lights are rather rarely used in games (if ever used at all).
2447 * furthermore if still used, probably nobody pays attention to such details.
2449 if (pLight->Falloff == 0) {
2450 rho = 6.28f;
2451 } else {
2452 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2454 if (rho < 0.0001) rho = 0.0001f;
2455 object->exponent = -0.3/log(cos(rho/2));
2456 if (object->exponent > 128.0) {
2457 object->exponent = 128.0;
2459 object->cutoff = pLight->Phi*90/M_PI;
2461 /* FIXME: Range */
2462 break;
2464 default:
2465 FIXME("Unrecognized light type %d\n", pLight->Type);
2468 /* Update the live definitions if the light is currently assigned a glIndex */
2469 if (object->glIndex != -1 && !This->isRecordingState) {
2470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2472 return WINED3D_OK;
2475 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2476 PLIGHTINFOEL *lightInfo = NULL;
2477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2478 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2479 struct list *e;
2480 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2482 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2483 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2484 if(lightInfo->OriginalIndex == Index) break;
2485 lightInfo = NULL;
2488 if (lightInfo == NULL) {
2489 TRACE("Light information requested but light not defined\n");
2490 return WINED3DERR_INVALIDCALL;
2493 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2494 return WINED3D_OK;
2497 /*****
2498 * Get / Set Light Enable
2499 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2500 *****/
2501 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2502 PLIGHTINFOEL *lightInfo = NULL;
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2505 struct list *e;
2506 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2508 /* Tests show true = 128...not clear why */
2509 Enable = Enable? 128: 0;
2511 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2512 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2513 if(lightInfo->OriginalIndex == Index) break;
2514 lightInfo = NULL;
2516 TRACE("Found light: %p\n", lightInfo);
2518 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2519 if (lightInfo == NULL) {
2521 TRACE("Light enabled requested but light not defined, so defining one!\n");
2522 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2524 /* Search for it again! Should be fairly quick as near head of list */
2525 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2526 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2527 if(lightInfo->OriginalIndex == Index) break;
2528 lightInfo = NULL;
2530 if (lightInfo == NULL) {
2531 FIXME("Adding default lights has failed dismally\n");
2532 return WINED3DERR_INVALIDCALL;
2536 lightInfo->enabledChanged = TRUE;
2537 if(!Enable) {
2538 if(lightInfo->glIndex != -1) {
2539 if(!This->isRecordingState) {
2540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2543 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2544 lightInfo->glIndex = -1;
2545 } else {
2546 TRACE("Light already disabled, nothing to do\n");
2548 } else {
2549 if (lightInfo->glIndex != -1) {
2550 /* nop */
2551 TRACE("Nothing to do as light was enabled\n");
2552 } else {
2553 int i;
2554 /* Find a free gl light */
2555 for(i = 0; i < This->maxConcurrentLights; i++) {
2556 if(This->stateBlock->activeLights[i] == NULL) {
2557 This->stateBlock->activeLights[i] = lightInfo;
2558 lightInfo->glIndex = i;
2559 break;
2562 if(lightInfo->glIndex == -1) {
2563 ERR("Too many concurrently active lights\n");
2564 return WINED3DERR_INVALIDCALL;
2567 /* i == lightInfo->glIndex */
2568 if(!This->isRecordingState) {
2569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2574 return WINED3D_OK;
2577 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2579 PLIGHTINFOEL *lightInfo = NULL;
2580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2581 struct list *e;
2582 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2583 TRACE("(%p) : for idx(%d)\n", This, Index);
2585 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2586 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2587 if(lightInfo->OriginalIndex == Index) break;
2588 lightInfo = NULL;
2591 if (lightInfo == NULL) {
2592 TRACE("Light enabled state requested but light not defined\n");
2593 return WINED3DERR_INVALIDCALL;
2595 /* true is 128 according to SetLightEnable */
2596 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2597 return WINED3D_OK;
2600 /*****
2601 * Get / Set Clip Planes
2602 *****/
2603 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2605 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2607 /* Validate Index */
2608 if (Index >= GL_LIMITS(clipplanes)) {
2609 TRACE("Application has requested clipplane this device doesn't support\n");
2610 return WINED3DERR_INVALIDCALL;
2613 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2614 This->updateStateBlock->set.clipplane[Index] = TRUE;
2616 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2617 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2618 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2619 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2620 TRACE("Application is setting old values over, nothing to do\n");
2621 return WINED3D_OK;
2624 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2625 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2626 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2627 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2629 /* Handle recording of state blocks */
2630 if (This->isRecordingState) {
2631 TRACE("Recording... not performing anything\n");
2632 return WINED3D_OK;
2635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2637 return WINED3D_OK;
2640 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2642 TRACE("(%p) : for idx %d\n", This, Index);
2644 /* Validate Index */
2645 if (Index >= GL_LIMITS(clipplanes)) {
2646 TRACE("Application has requested clipplane this device doesn't support\n");
2647 return WINED3DERR_INVALIDCALL;
2650 pPlane[0] = This->stateBlock->clipplane[Index][0];
2651 pPlane[1] = This->stateBlock->clipplane[Index][1];
2652 pPlane[2] = This->stateBlock->clipplane[Index][2];
2653 pPlane[3] = This->stateBlock->clipplane[Index][3];
2654 return WINED3D_OK;
2657 /*****
2658 * Get / Set Clip Plane Status
2659 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2660 *****/
2661 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2663 FIXME("(%p) : stub\n", This);
2664 if (NULL == pClipStatus) {
2665 return WINED3DERR_INVALIDCALL;
2667 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2668 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2669 return WINED3D_OK;
2672 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2674 FIXME("(%p) : stub\n", This);
2675 if (NULL == pClipStatus) {
2676 return WINED3DERR_INVALIDCALL;
2678 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2679 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2680 return WINED3D_OK;
2683 /*****
2684 * Get / Set Material
2685 *****/
2686 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 This->updateStateBlock->changed.material = TRUE;
2690 This->updateStateBlock->set.material = TRUE;
2691 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2693 /* Handle recording of state blocks */
2694 if (This->isRecordingState) {
2695 TRACE("Recording... not performing anything\n");
2696 return WINED3D_OK;
2699 ENTER_GL();
2700 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2701 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2702 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2703 pMaterial->Ambient.b, pMaterial->Ambient.a);
2704 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2705 pMaterial->Specular.b, pMaterial->Specular.a);
2706 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2707 pMaterial->Emissive.b, pMaterial->Emissive.a);
2708 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2710 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2711 checkGLcall("glMaterialfv(GL_AMBIENT)");
2712 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2713 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2715 /* Only change material color if specular is enabled, otherwise it is set to black */
2716 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2717 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2718 checkGLcall("glMaterialfv(GL_SPECULAR");
2719 } else {
2720 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2721 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2722 checkGLcall("glMaterialfv(GL_SPECULAR");
2724 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2725 checkGLcall("glMaterialfv(GL_EMISSION)");
2726 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2727 checkGLcall("glMaterialf(GL_SHININESS");
2729 LEAVE_GL();
2730 return WINED3D_OK;
2733 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2736 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2737 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2738 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2739 pMaterial->Ambient.b, pMaterial->Ambient.a);
2740 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2741 pMaterial->Specular.b, pMaterial->Specular.a);
2742 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2743 pMaterial->Emissive.b, pMaterial->Emissive.a);
2744 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2746 return WINED3D_OK;
2749 /*****
2750 * Get / Set Indices
2751 *****/
2752 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2753 UINT BaseVertexIndex) {
2754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 IWineD3DIndexBuffer *oldIdxs;
2756 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2758 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2759 oldIdxs = This->updateStateBlock->pIndexData;
2761 This->updateStateBlock->changed.indices = TRUE;
2762 This->updateStateBlock->set.indices = TRUE;
2763 This->updateStateBlock->pIndexData = pIndexData;
2764 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2766 /* Handle recording of state blocks */
2767 if (This->isRecordingState) {
2768 TRACE("Recording... not performing anything\n");
2769 return WINED3D_OK;
2772 /* The base vertex index affects the stream sources, while
2773 * The index buffer is a seperate index buffer state
2775 if(BaseVertexIndex != oldBaseIndex) {
2776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2778 if(oldIdxs != pIndexData) {
2779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2781 return WINED3D_OK;
2784 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 *ppIndexData = This->stateBlock->pIndexData;
2789 /* up ref count on ppindexdata */
2790 if (*ppIndexData) {
2791 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2792 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2793 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2794 }else{
2795 TRACE("(%p) No index data set\n", This);
2797 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2799 return WINED3D_OK;
2802 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2803 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2805 TRACE("(%p)->(%d)\n", This, BaseIndex);
2807 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2808 TRACE("Application is setting the old value over, nothing to do\n");
2809 return WINED3D_OK;
2812 This->updateStateBlock->baseVertexIndex = BaseIndex;
2814 if (This->isRecordingState) {
2815 TRACE("Recording... not performing anything\n");
2816 return WINED3D_OK;
2818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2819 return WINED3D_OK;
2822 /*****
2823 * Get / Set Viewports
2824 *****/
2825 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2826 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 TRACE("(%p)\n", This);
2829 This->updateStateBlock->changed.viewport = TRUE;
2830 This->updateStateBlock->set.viewport = TRUE;
2831 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2833 /* Handle recording of state blocks */
2834 if (This->isRecordingState) {
2835 TRACE("Recording... not performing anything\n");
2836 return WINED3D_OK;
2839 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2840 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2843 return WINED3D_OK;
2847 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 TRACE("(%p)\n", This);
2850 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2851 return WINED3D_OK;
2854 /*****
2855 * Get / Set Render States
2856 * TODO: Verify against dx9 definitions
2857 *****/
2858 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2861 DWORD oldValue = This->stateBlock->renderState[State];
2863 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2865 This->updateStateBlock->changed.renderState[State] = TRUE;
2866 This->updateStateBlock->set.renderState[State] = TRUE;
2867 This->updateStateBlock->renderState[State] = Value;
2869 /* Handle recording of state blocks */
2870 if (This->isRecordingState) {
2871 TRACE("Recording... not performing anything\n");
2872 return WINED3D_OK;
2875 /* Compared here and not before the assignment to allow proper stateblock recording */
2876 if(Value == oldValue) {
2877 TRACE("Application is setting the old value over, nothing to do\n");
2878 } else {
2879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2882 return WINED3D_OK;
2885 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2887 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2888 *pValue = This->stateBlock->renderState[State];
2889 return WINED3D_OK;
2892 /*****
2893 * Get / Set Sampler States
2894 * TODO: Verify against dx9 definitions
2895 *****/
2897 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2899 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2902 * SetSampler is designed to allow for more than the standard up to 8 textures
2903 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2904 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2906 * http://developer.nvidia.com/object/General_FAQ.html#t6
2908 * There are two new settings for GForce
2909 * the sampler one:
2910 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2911 * and the texture one:
2912 * GL_MAX_TEXTURE_COORDS_ARB.
2913 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2914 ******************/
2916 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2917 debug_d3dsamplerstate(Type), Type, Value);
2918 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2919 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2920 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2922 /* Handle recording of state blocks */
2923 if (This->isRecordingState) {
2924 TRACE("Recording... not performing anything\n");
2925 return WINED3D_OK;
2928 if(oldValue == Value) {
2929 TRACE("Application is setting the old value over, nothing to do\n");
2930 return WINED3D_OK;
2933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2935 return WINED3D_OK;
2938 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 *Value = This->stateBlock->samplerState[Sampler][Type];
2941 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2943 return WINED3D_OK;
2946 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2949 This->updateStateBlock->set.scissorRect = TRUE;
2950 This->updateStateBlock->changed.scissorRect = TRUE;
2951 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2952 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2953 return WINED3D_OK;
2955 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2957 if(This->isRecordingState) {
2958 TRACE("Recording... not performing anything\n");
2959 return WINED3D_OK;
2962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2964 return WINED3D_OK;
2967 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2971 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2972 return WINED3D_OK;
2975 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2977 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2979 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2981 This->updateStateBlock->vertexDecl = pDecl;
2982 This->updateStateBlock->changed.vertexDecl = TRUE;
2983 This->updateStateBlock->set.vertexDecl = TRUE;
2985 if (This->isRecordingState) {
2986 TRACE("Recording... not performing anything\n");
2987 return WINED3D_OK;
2988 } else if(pDecl == oldDecl) {
2989 /* Checked after the assignment to allow proper stateblock recording */
2990 TRACE("Application is setting the old declaration over, nothing to do\n");
2991 return WINED3D_OK;
2994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2995 return WINED3D_OK;
2998 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3003 *ppDecl = This->stateBlock->vertexDecl;
3004 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3005 return WINED3D_OK;
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3012 This->updateStateBlock->vertexShader = pShader;
3013 This->updateStateBlock->changed.vertexShader = TRUE;
3014 This->updateStateBlock->set.vertexShader = TRUE;
3016 if (This->isRecordingState) {
3017 TRACE("Recording... not performing anything\n");
3018 return WINED3D_OK;
3019 } else if(oldShader == pShader) {
3020 /* Checked here to allow proper stateblock recording */
3021 TRACE("App is setting the old shader over, nothing to do\n");
3022 return WINED3D_OK;
3025 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3029 return WINED3D_OK;
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3035 if (NULL == ppShader) {
3036 return WINED3DERR_INVALIDCALL;
3038 *ppShader = This->stateBlock->vertexShader;
3039 if( NULL != *ppShader)
3040 IWineD3DVertexShader_AddRef(*ppShader);
3042 TRACE("(%p) : returning %p\n", This, *ppShader);
3043 return WINED3D_OK;
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3047 IWineD3DDevice *iface,
3048 UINT start,
3049 CONST BOOL *srcData,
3050 UINT count) {
3052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 int i, cnt = min(count, MAX_CONST_B - start);
3055 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3056 iface, srcData, start, count);
3058 if (srcData == NULL || cnt < 0)
3059 return WINED3DERR_INVALIDCALL;
3061 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3062 for (i = 0; i < cnt; i++)
3063 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3065 for (i = start; i < cnt + start; ++i) {
3066 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3067 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3072 return WINED3D_OK;
3075 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3076 IWineD3DDevice *iface,
3077 UINT start,
3078 BOOL *dstData,
3079 UINT count) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3082 int cnt = min(count, MAX_CONST_B - start);
3084 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3085 iface, dstData, start, count);
3087 if (dstData == NULL || cnt < 0)
3088 return WINED3DERR_INVALIDCALL;
3090 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3091 return WINED3D_OK;
3094 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3095 IWineD3DDevice *iface,
3096 UINT start,
3097 CONST int *srcData,
3098 UINT count) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 int i, cnt = min(count, MAX_CONST_I - start);
3103 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3104 iface, srcData, start, count);
3106 if (srcData == NULL || cnt < 0)
3107 return WINED3DERR_INVALIDCALL;
3109 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3110 for (i = 0; i < cnt; i++)
3111 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3112 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3114 for (i = start; i < cnt + start; ++i) {
3115 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3116 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3121 return WINED3D_OK;
3124 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3125 IWineD3DDevice *iface,
3126 UINT start,
3127 int *dstData,
3128 UINT count) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 int cnt = min(count, MAX_CONST_I - start);
3133 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3134 iface, dstData, start, count);
3136 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3137 return WINED3DERR_INVALIDCALL;
3139 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3140 return WINED3D_OK;
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3144 IWineD3DDevice *iface,
3145 UINT start,
3146 CONST float *srcData,
3147 UINT count) {
3149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 int i;
3152 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3153 iface, srcData, start, count);
3155 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3156 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3157 return WINED3DERR_INVALIDCALL;
3159 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3160 if(TRACE_ON(d3d)) {
3161 for (i = 0; i < count; i++)
3162 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3163 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3166 for (i = start; i < count + start; ++i) {
3167 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3168 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3169 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3170 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3171 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3173 ptr->idx[ptr->count++] = i;
3174 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3176 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3179 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3181 return WINED3D_OK;
3184 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3185 IWineD3DDevice *iface,
3186 UINT start,
3187 float *dstData,
3188 UINT count) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3193 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3194 iface, dstData, start, count);
3196 if (dstData == NULL || cnt < 0)
3197 return WINED3DERR_INVALIDCALL;
3199 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3200 return WINED3D_OK;
3203 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3204 DWORD i;
3205 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3210 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3211 DWORD i, tex;
3212 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3213 * it is never called.
3215 * Rules are:
3216 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3217 * that would be really messy and require shader recompilation
3218 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3219 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3220 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3221 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3223 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3224 if(This->oneToOneTexUnitMap) {
3225 TRACE("Not touching 1:1 map\n");
3226 return;
3228 TRACE("Restoring 1:1 texture unit mapping\n");
3229 /* Restore a 1:1 mapping */
3230 for(i = 0; i < MAX_SAMPLERS; i++) {
3231 if(This->texUnitMap[i] != i) {
3232 This->texUnitMap[i] = i;
3233 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3234 markTextureStagesDirty(This, i);
3237 This->oneToOneTexUnitMap = TRUE;
3238 return;
3239 } else {
3240 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3241 * First, see if we can succeed at all
3243 tex = 0;
3244 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3245 if(This->stateBlock->textures[i] == NULL) tex++;
3248 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3249 FIXME("Too many bound textures to support the combiner settings\n");
3250 return;
3253 /* Now work out the mapping */
3254 tex = 0;
3255 This->oneToOneTexUnitMap = FALSE;
3256 WARN("Non 1:1 mapping UNTESTED!\n");
3257 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3258 /* Skip NULL textures */
3259 if (!This->stateBlock->textures[i]) {
3260 /* Map to -1, so the check below doesn't fail if a non-NULL
3261 * texture is set on this stage */
3262 TRACE("Mapping texture stage %d to -1\n", i);
3263 This->texUnitMap[i] = -1;
3265 continue;
3268 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3269 if(This->texUnitMap[i] != tex) {
3270 This->texUnitMap[i] = tex;
3271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3272 markTextureStagesDirty(This, i);
3275 ++tex;
3280 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3283 This->updateStateBlock->pixelShader = pShader;
3284 This->updateStateBlock->changed.pixelShader = TRUE;
3285 This->updateStateBlock->set.pixelShader = TRUE;
3287 /* Handle recording of state blocks */
3288 if (This->isRecordingState) {
3289 TRACE("Recording... not performing anything\n");
3292 if (This->isRecordingState) {
3293 TRACE("Recording... not performing anything\n");
3294 return WINED3D_OK;
3297 if(pShader == oldShader) {
3298 TRACE("App is setting the old pixel shader over, nothing to do\n");
3299 return WINED3D_OK;
3302 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3305 /* Rebuild the texture unit mapping if nvrc's are supported */
3306 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3307 IWineD3DDeviceImpl_FindTexUnitMap(This);
3310 return WINED3D_OK;
3313 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3316 if (NULL == ppShader) {
3317 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3318 return WINED3DERR_INVALIDCALL;
3321 *ppShader = This->stateBlock->pixelShader;
3322 if (NULL != *ppShader) {
3323 IWineD3DPixelShader_AddRef(*ppShader);
3325 TRACE("(%p) : returning %p\n", This, *ppShader);
3326 return WINED3D_OK;
3329 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3330 IWineD3DDevice *iface,
3331 UINT start,
3332 CONST BOOL *srcData,
3333 UINT count) {
3335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3336 int i, cnt = min(count, MAX_CONST_B - start);
3338 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3339 iface, srcData, start, count);
3341 if (srcData == NULL || cnt < 0)
3342 return WINED3DERR_INVALIDCALL;
3344 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3345 for (i = 0; i < cnt; i++)
3346 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3348 for (i = start; i < cnt + start; ++i) {
3349 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3350 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3355 return WINED3D_OK;
3358 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3359 IWineD3DDevice *iface,
3360 UINT start,
3361 BOOL *dstData,
3362 UINT count) {
3364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3365 int cnt = min(count, MAX_CONST_B - start);
3367 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3368 iface, dstData, start, count);
3370 if (dstData == NULL || cnt < 0)
3371 return WINED3DERR_INVALIDCALL;
3373 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3374 return WINED3D_OK;
3377 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3378 IWineD3DDevice *iface,
3379 UINT start,
3380 CONST int *srcData,
3381 UINT count) {
3383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3384 int i, cnt = min(count, MAX_CONST_I - start);
3386 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3387 iface, srcData, start, count);
3389 if (srcData == NULL || cnt < 0)
3390 return WINED3DERR_INVALIDCALL;
3392 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3393 for (i = 0; i < cnt; i++)
3394 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3395 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3397 for (i = start; i < cnt + start; ++i) {
3398 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3399 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3404 return WINED3D_OK;
3407 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3408 IWineD3DDevice *iface,
3409 UINT start,
3410 int *dstData,
3411 UINT count) {
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 int cnt = min(count, MAX_CONST_I - start);
3416 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3417 iface, dstData, start, count);
3419 if (dstData == NULL || cnt < 0)
3420 return WINED3DERR_INVALIDCALL;
3422 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3427 IWineD3DDevice *iface,
3428 UINT start,
3429 CONST float *srcData,
3430 UINT count) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int i;
3435 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3436 iface, srcData, start, count);
3438 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3439 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3440 return WINED3DERR_INVALIDCALL;
3442 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3443 if(TRACE_ON(d3d)) {
3444 for (i = 0; i < count; i++)
3445 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3446 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3449 for (i = start; i < count + start; ++i) {
3450 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3451 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3452 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3453 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3454 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3456 ptr->idx[ptr->count++] = i;
3457 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3459 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3464 return WINED3D_OK;
3467 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3468 IWineD3DDevice *iface,
3469 UINT start,
3470 float *dstData,
3471 UINT count) {
3473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3474 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3476 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3477 iface, dstData, start, count);
3479 if (dstData == NULL || cnt < 0)
3480 return WINED3DERR_INVALIDCALL;
3482 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3483 return WINED3D_OK;
3486 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3487 static HRESULT
3488 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3489 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3490 unsigned int i;
3491 DWORD DestFVF = dest->fvf;
3492 WINED3DVIEWPORT vp;
3493 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3494 BOOL doClip;
3495 int numTextures;
3497 if (lpStrideData->u.s.normal.lpData) {
3498 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3501 if (lpStrideData->u.s.position.lpData == NULL) {
3502 ERR("Source has no position mask\n");
3503 return WINED3DERR_INVALIDCALL;
3506 /* We might access VBOs from this code, so hold the lock */
3507 ENTER_GL();
3509 if (dest->resource.allocatedMemory == NULL) {
3510 /* This may happen if we do direct locking into a vbo. Unlikely,
3511 * but theoretically possible(ddraw processvertices test)
3513 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3514 if(!dest->resource.allocatedMemory) {
3515 LEAVE_GL();
3516 ERR("Out of memory\n");
3517 return E_OUTOFMEMORY;
3519 if(dest->vbo) {
3520 void *src;
3521 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3522 checkGLcall("glBindBufferARB");
3523 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3524 if(src) {
3525 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3527 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3528 checkGLcall("glUnmapBufferARB");
3532 /* Get a pointer into the destination vbo(create one if none exists) and
3533 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3535 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3536 CreateVBO(dest);
3539 if(dest->vbo) {
3540 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3541 if(!dest_conv_addr) {
3542 ERR("Out of memory\n");
3543 /* Continue without storing converted vertices */
3545 dest_conv = dest_conv_addr;
3548 /* Should I clip?
3549 * a) WINED3DRS_CLIPPING is enabled
3550 * b) WINED3DVOP_CLIP is passed
3552 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3553 static BOOL warned = FALSE;
3555 * The clipping code is not quite correct. Some things need
3556 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3557 * so disable clipping for now.
3558 * (The graphics in Half-Life are broken, and my processvertices
3559 * test crashes with IDirect3DDevice3)
3560 doClip = TRUE;
3562 doClip = FALSE;
3563 if(!warned) {
3564 warned = TRUE;
3565 FIXME("Clipping is broken and disabled for now\n");
3567 } else doClip = FALSE;
3568 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3570 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3571 WINED3DTS_VIEW,
3572 &view_mat);
3573 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3574 WINED3DTS_PROJECTION,
3575 &proj_mat);
3576 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3577 WINED3DTS_WORLDMATRIX(0),
3578 &world_mat);
3580 TRACE("View mat:\n");
3581 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);
3582 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);
3583 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);
3584 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);
3586 TRACE("Proj mat:\n");
3587 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);
3588 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);
3589 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);
3590 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);
3592 TRACE("World mat:\n");
3593 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);
3594 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);
3595 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);
3596 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);
3598 /* Get the viewport */
3599 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3600 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3601 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3603 multiply_matrix(&mat,&view_mat,&world_mat);
3604 multiply_matrix(&mat,&proj_mat,&mat);
3606 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3608 for (i = 0; i < dwCount; i+= 1) {
3609 unsigned int tex_index;
3611 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3612 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3613 /* The position first */
3614 float *p =
3615 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3616 float x, y, z, rhw;
3617 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3619 /* Multiplication with world, view and projection matrix */
3620 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);
3621 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);
3622 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);
3623 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);
3625 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3627 /* WARNING: The following things are taken from d3d7 and were not yet checked
3628 * against d3d8 or d3d9!
3631 /* Clipping conditions: From
3632 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3634 * A vertex is clipped if it does not match the following requirements
3635 * -rhw < x <= rhw
3636 * -rhw < y <= rhw
3637 * 0 < z <= rhw
3638 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3640 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3641 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3645 if( !doClip ||
3646 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3647 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3648 ( rhw > eps ) ) ) {
3650 /* "Normal" viewport transformation (not clipped)
3651 * 1) The values are divided by rhw
3652 * 2) The y axis is negative, so multiply it with -1
3653 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3654 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3655 * 4) Multiply x with Width/2 and add Width/2
3656 * 5) The same for the height
3657 * 6) Add the viewpoint X and Y to the 2D coordinates and
3658 * The minimum Z value to z
3659 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3661 * Well, basically it's simply a linear transformation into viewport
3662 * coordinates
3665 x /= rhw;
3666 y /= rhw;
3667 z /= rhw;
3669 y *= -1;
3671 x *= vp.Width / 2;
3672 y *= vp.Height / 2;
3673 z *= vp.MaxZ - vp.MinZ;
3675 x += vp.Width / 2 + vp.X;
3676 y += vp.Height / 2 + vp.Y;
3677 z += vp.MinZ;
3679 rhw = 1 / rhw;
3680 } else {
3681 /* That vertex got clipped
3682 * Contrary to OpenGL it is not dropped completely, it just
3683 * undergoes a different calculation.
3685 TRACE("Vertex got clipped\n");
3686 x += rhw;
3687 y += rhw;
3689 x /= 2;
3690 y /= 2;
3692 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3693 * outside of the main vertex buffer memory. That needs some more
3694 * investigation...
3698 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3701 ( (float *) dest_ptr)[0] = x;
3702 ( (float *) dest_ptr)[1] = y;
3703 ( (float *) dest_ptr)[2] = z;
3704 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3706 dest_ptr += 3 * sizeof(float);
3708 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3709 dest_ptr += sizeof(float);
3712 if(dest_conv) {
3713 float w = 1 / rhw;
3714 ( (float *) dest_conv)[0] = x * w;
3715 ( (float *) dest_conv)[1] = y * w;
3716 ( (float *) dest_conv)[2] = z * w;
3717 ( (float *) dest_conv)[3] = w;
3719 dest_conv += 3 * sizeof(float);
3721 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3722 dest_conv += sizeof(float);
3726 if (DestFVF & WINED3DFVF_PSIZE) {
3727 dest_ptr += sizeof(DWORD);
3728 if(dest_conv) dest_conv += sizeof(DWORD);
3730 if (DestFVF & WINED3DFVF_NORMAL) {
3731 float *normal =
3732 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3733 /* AFAIK this should go into the lighting information */
3734 FIXME("Didn't expect the destination to have a normal\n");
3735 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3736 if(dest_conv) {
3737 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3741 if (DestFVF & WINED3DFVF_DIFFUSE) {
3742 DWORD *color_d =
3743 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3744 if(!color_d) {
3745 static BOOL warned = FALSE;
3747 if(!warned) {
3748 ERR("No diffuse color in source, but destination has one\n");
3749 warned = TRUE;
3752 *( (DWORD *) dest_ptr) = 0xffffffff;
3753 dest_ptr += sizeof(DWORD);
3755 if(dest_conv) {
3756 *( (DWORD *) dest_conv) = 0xffffffff;
3757 dest_conv += sizeof(DWORD);
3760 else {
3761 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3762 if(dest_conv) {
3763 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3764 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3765 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3766 dest_conv += sizeof(DWORD);
3771 if (DestFVF & WINED3DFVF_SPECULAR) {
3772 /* What's the color value in the feedback buffer? */
3773 DWORD *color_s =
3774 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3775 if(!color_s) {
3776 static BOOL warned = FALSE;
3778 if(!warned) {
3779 ERR("No specular color in source, but destination has one\n");
3780 warned = TRUE;
3783 *( (DWORD *) dest_ptr) = 0xFF000000;
3784 dest_ptr += sizeof(DWORD);
3786 if(dest_conv) {
3787 *( (DWORD *) dest_conv) = 0xFF000000;
3788 dest_conv += sizeof(DWORD);
3791 else {
3792 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3793 if(dest_conv) {
3794 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3795 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3796 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3797 dest_conv += sizeof(DWORD);
3802 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3803 float *tex_coord =
3804 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3805 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3806 if(!tex_coord) {
3807 ERR("No source texture, but destination requests one\n");
3808 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3809 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3811 else {
3812 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3813 if(dest_conv) {
3814 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3820 if(dest_conv) {
3821 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3822 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3823 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3824 dwCount * get_flexible_vertex_size(DestFVF),
3825 dest_conv_addr));
3826 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3827 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3830 LEAVE_GL();
3832 return WINED3D_OK;
3834 #undef copy_and_next
3836 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3838 WineDirect3DVertexStridedData strided;
3839 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3840 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3842 if(pVertexDecl) {
3843 ERR("Output vertex declaration not implemented yet\n");
3846 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3847 * and this call is quite performance critical, so don't call needlessly
3849 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3850 ENTER_GL();
3851 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3852 LEAVE_GL();
3855 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3856 * control the streamIsUP flag, thus restore it afterwards.
3858 This->stateBlock->streamIsUP = FALSE;
3859 memset(&strided, 0, sizeof(strided));
3860 if(This->stateBlock->vertexDecl) {
3861 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3862 } else {
3863 primitiveConvertToStridedData(iface, &strided, &vbo);
3865 This->stateBlock->streamIsUP = streamWasUP;
3867 if(vbo || SrcStartIndex) {
3868 unsigned int i;
3869 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3870 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3872 * Also get the start index in, but only loop over all elements if there's something to add at all.
3874 for(i=0; i < 16; i++) {
3875 if(strided.u.input[i].VBO) {
3876 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.input[i].streamNo];
3878 /* The vertex buffer is supposed to have a system memory copy */
3879 strided.u.input[i].VBO = 0;
3880 strided.u.input[i].lpData = (BYTE *) ((unsigned long) strided.u.input[i].lpData + (unsigned long) vb->resource.allocatedMemory);
3881 ENTER_GL();
3882 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo));
3883 vb->vbo = 0;
3884 LEAVE_GL();
3886 /* To be safe. An app could technically draw, then call ProcessVertices, then draw again without ever changing the stream sources */
3887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3889 if(strided.u.input[i].lpData) {
3890 strided.u.input[i].lpData += strided.u.input[i].dwStride * SrcStartIndex;
3895 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3898 /*****
3899 * Get / Set Texture Stage States
3900 * TODO: Verify against dx9 definitions
3901 *****/
3902 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3904 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3906 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3908 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3910 if (Stage >= MAX_TEXTURES) {
3911 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3912 return WINED3D_OK;
3915 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3916 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3917 This->updateStateBlock->textureState[Stage][Type] = Value;
3919 if (This->isRecordingState) {
3920 TRACE("Recording... not performing anything\n");
3921 return WINED3D_OK;
3924 /* Checked after the assignments to allow proper stateblock recording */
3925 if(oldValue == Value) {
3926 TRACE("App is setting the old value over, nothing to do\n");
3927 return WINED3D_OK;
3930 if(Stage > This->stateBlock->lowest_disabled_stage &&
3931 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3932 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3933 * Changes in other states are important on disabled stages too
3935 return WINED3D_OK;
3938 if(Type == WINED3DTSS_COLOROP) {
3939 int i;
3941 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3942 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3943 * they have to be disabled
3945 * The current stage is dirtified below.
3947 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3948 TRACE("Additionally dirtifying stage %d\n", i);
3949 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3951 This->stateBlock->lowest_disabled_stage = Stage;
3952 TRACE("New lowest disabled: %d\n", Stage);
3953 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3954 /* Previously disabled stage enabled. Stages above it may need enabling
3955 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3956 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3958 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3961 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3962 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3963 break;
3965 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3968 This->stateBlock->lowest_disabled_stage = i;
3969 TRACE("New lowest disabled: %d\n", i);
3971 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3972 /* TODO: Built a stage -> texture unit mapping for register combiners */
3976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3978 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3979 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3980 * will call FindTexUnitMap too.
3982 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3983 IWineD3DDeviceImpl_FindTexUnitMap(This);
3985 return WINED3D_OK;
3988 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3990 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3991 *pValue = This->updateStateBlock->textureState[Stage][Type];
3992 return WINED3D_OK;
3995 /*****
3996 * Get / Set Texture
3997 *****/
3998 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4001 IWineD3DBaseTexture *oldTexture;
4003 oldTexture = This->updateStateBlock->textures[Stage];
4004 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4006 #if 0 /* TODO: check so vertex textures */
4007 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4008 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4009 return WINED3D_OK;
4011 #endif
4013 if(pTexture != NULL) {
4014 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4016 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4017 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4018 return WINED3DERR_INVALIDCALL;
4020 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4023 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4024 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4026 This->updateStateBlock->set.textures[Stage] = TRUE;
4027 This->updateStateBlock->changed.textures[Stage] = TRUE;
4028 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4029 This->updateStateBlock->textures[Stage] = pTexture;
4031 /* Handle recording of state blocks */
4032 if (This->isRecordingState) {
4033 TRACE("Recording... not performing anything\n");
4034 return WINED3D_OK;
4037 if(oldTexture == pTexture) {
4038 TRACE("App is setting the same texture again, nothing to do\n");
4039 return WINED3D_OK;
4042 /** NOTE: MSDN says that setTexture increases the reference count,
4043 * and the the application nust set the texture back to null (or have a leaky application),
4044 * This means we should pass the refcount up to the parent
4045 *******************************/
4046 if (NULL != This->updateStateBlock->textures[Stage]) {
4047 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4048 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4050 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4051 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4052 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4053 * so the COLOROP and ALPHAOP have to be dirtified.
4055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4058 if(bindCount == 1) {
4059 new->baseTexture.sampler = Stage;
4061 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4065 if (NULL != oldTexture) {
4066 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4067 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4069 IWineD3DBaseTexture_Release(oldTexture);
4070 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4075 if(bindCount && old->baseTexture.sampler == Stage) {
4076 int i;
4077 /* Have to do a search for the other sampler(s) where the texture is bound to
4078 * Shouldn't happen as long as apps bind a texture only to one stage
4080 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4081 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4082 if(This->updateStateBlock->textures[i] == oldTexture) {
4083 old->baseTexture.sampler = i;
4084 break;
4090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4092 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4093 * pixel shader is used
4095 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4096 IWineD3DDeviceImpl_FindTexUnitMap(This);
4099 return WINED3D_OK;
4102 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4104 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4106 *ppTexture=This->stateBlock->textures[Stage];
4107 if (*ppTexture)
4108 IWineD3DBaseTexture_AddRef(*ppTexture);
4110 return WINED3D_OK;
4113 /*****
4114 * Get Back Buffer
4115 *****/
4116 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4117 IWineD3DSurface **ppBackBuffer) {
4118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4119 IWineD3DSwapChain *swapChain;
4120 HRESULT hr;
4122 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4124 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4125 if (hr == WINED3D_OK) {
4126 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4127 IWineD3DSwapChain_Release(swapChain);
4128 } else {
4129 *ppBackBuffer = NULL;
4131 return hr;
4134 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4136 WARN("(%p) : stub, calling idirect3d for now\n", This);
4137 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4140 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4142 IWineD3DSwapChain *swapChain;
4143 HRESULT hr;
4145 if(iSwapChain > 0) {
4146 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4147 if (hr == WINED3D_OK) {
4148 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4149 IWineD3DSwapChain_Release(swapChain);
4150 } else {
4151 FIXME("(%p) Error getting display mode\n", This);
4153 } else {
4154 /* Don't read the real display mode,
4155 but return the stored mode instead. X11 can't change the color
4156 depth, and some apps are pretty angry if they SetDisplayMode from
4157 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4159 Also don't relay to the swapchain because with ddraw it's possible
4160 that there isn't a swapchain at all */
4161 pMode->Width = This->ddraw_width;
4162 pMode->Height = This->ddraw_height;
4163 pMode->Format = This->ddraw_format;
4164 pMode->RefreshRate = 0;
4165 hr = WINED3D_OK;
4168 return hr;
4171 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4173 TRACE("(%p)->(%p)\n", This, hWnd);
4175 if(This->ddraw_fullscreen) {
4176 if(This->ddraw_window && This->ddraw_window != hWnd) {
4177 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4179 if(hWnd && This->ddraw_window != hWnd) {
4180 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4184 This->ddraw_window = hWnd;
4185 return WINED3D_OK;
4188 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4190 TRACE("(%p)->(%p)\n", This, hWnd);
4192 *hWnd = This->ddraw_window;
4193 return WINED3D_OK;
4196 /*****
4197 * Stateblock related functions
4198 *****/
4200 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4202 IWineD3DStateBlockImpl *object;
4203 HRESULT temp_result;
4204 int i;
4206 TRACE("(%p)\n", This);
4208 if (This->isRecordingState) {
4209 return WINED3DERR_INVALIDCALL;
4212 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4213 if (NULL == object ) {
4214 FIXME("(%p)Error allocating memory for stateblock\n", This);
4215 return E_OUTOFMEMORY;
4217 TRACE("(%p) created object %p\n", This, object);
4218 object->wineD3DDevice= This;
4219 /** FIXME: object->parent = parent; **/
4220 object->parent = NULL;
4221 object->blockType = WINED3DSBT_ALL;
4222 object->ref = 1;
4223 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4225 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4226 list_init(&object->lightMap[i]);
4229 temp_result = allocate_shader_constants(object);
4230 if (WINED3D_OK != temp_result)
4231 return temp_result;
4233 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4234 This->updateStateBlock = object;
4235 This->isRecordingState = TRUE;
4237 TRACE("(%p) recording stateblock %p\n",This , object);
4238 return WINED3D_OK;
4241 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4244 if (!This->isRecordingState) {
4245 FIXME("(%p) not recording! returning error\n", This);
4246 *ppStateBlock = NULL;
4247 return WINED3DERR_INVALIDCALL;
4250 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4251 This->isRecordingState = FALSE;
4252 This->updateStateBlock = This->stateBlock;
4253 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4254 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4255 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4256 return WINED3D_OK;
4259 /*****
4260 * Scene related functions
4261 *****/
4262 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4263 /* At the moment we have no need for any functionality at the beginning
4264 of a scene */
4265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4266 TRACE("(%p)\n", This);
4268 if(This->inScene) {
4269 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4270 return WINED3DERR_INVALIDCALL;
4272 This->inScene = TRUE;
4273 return WINED3D_OK;
4276 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4278 TRACE("(%p)\n", This);
4280 if(!This->inScene) {
4281 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4282 return WINED3DERR_INVALIDCALL;
4285 ENTER_GL();
4286 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4287 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4289 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4290 glFlush();
4291 checkGLcall("glFlush");
4292 LEAVE_GL();
4294 This->inScene = FALSE;
4295 return WINED3D_OK;
4298 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4299 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4300 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4302 IWineD3DSwapChain *swapChain = NULL;
4303 int i;
4304 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4306 TRACE("(%p) Presenting the frame\n", This);
4308 for(i = 0 ; i < swapchains ; i ++) {
4310 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4311 TRACE("presentinng chain %d, %p\n", i, swapChain);
4312 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4313 IWineD3DSwapChain_Release(swapChain);
4316 return WINED3D_OK;
4319 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4320 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4322 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4324 GLbitfield glMask = 0;
4325 unsigned int i;
4326 CONST WINED3DRECT* curRect;
4328 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4329 Count, pRects, Flags, Z, Stencil);
4331 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4332 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4333 /* TODO: What about depth stencil buffers without stencil bits? */
4334 return WINED3DERR_INVALIDCALL;
4337 ENTER_GL();
4338 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4339 * and not the last active one.
4342 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4343 apply_fbo_state(iface);
4346 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4348 glEnable(GL_SCISSOR_TEST);
4349 checkGLcall("glEnable GL_SCISSOR_TEST");
4350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4353 if (Count > 0 && pRects) {
4354 curRect = pRects;
4355 } else {
4356 curRect = NULL;
4359 /* Only set the values up once, as they are not changing */
4360 if (Flags & WINED3DCLEAR_STENCIL) {
4361 glClearStencil(Stencil);
4362 checkGLcall("glClearStencil");
4363 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4364 glStencilMask(0xFFFFFFFF);
4367 if (Flags & WINED3DCLEAR_ZBUFFER) {
4368 glDepthMask(GL_TRUE);
4369 glClearDepth(Z);
4370 checkGLcall("glClearDepth");
4371 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4375 if (Flags & WINED3DCLEAR_TARGET) {
4376 TRACE("Clearing screen with glClear to color %x\n", Color);
4377 glClearColor(D3DCOLOR_R(Color),
4378 D3DCOLOR_G(Color),
4379 D3DCOLOR_B(Color),
4380 D3DCOLOR_A(Color));
4381 checkGLcall("glClearColor");
4383 /* Clear ALL colors! */
4384 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4385 glMask = glMask | GL_COLOR_BUFFER_BIT;
4388 if (!curRect) {
4389 /* In drawable flag is set below */
4391 glScissor(This->stateBlock->viewport.X,
4392 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4393 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4394 This->stateBlock->viewport.Width,
4395 This->stateBlock->viewport.Height);
4396 checkGLcall("glScissor");
4397 glClear(glMask);
4398 checkGLcall("glClear");
4399 } else {
4400 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4401 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4403 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4404 curRect[0].x2 < target->currentDesc.Width ||
4405 curRect[0].y2 < target->currentDesc.Height) {
4406 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4407 blt_to_drawable(This, target);
4411 /* Now process each rect in turn */
4412 for (i = 0; i < Count; i++) {
4413 /* Note gl uses lower left, width/height */
4414 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4415 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4416 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4417 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4419 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4420 * The rectangle is not cleared, no error is returned, but further rectanlges are
4421 * still cleared if they are valid
4423 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4424 TRACE("Rectangle with negative dimensions, ignoring\n");
4425 continue;
4428 if(This->render_offscreen) {
4429 glScissor(curRect[i].x1, curRect[i].y1,
4430 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4431 } else {
4432 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4433 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4435 checkGLcall("glScissor");
4437 glClear(glMask);
4438 checkGLcall("glClear");
4442 /* Restore the old values (why..?) */
4443 if (Flags & WINED3DCLEAR_STENCIL) {
4444 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4446 if (Flags & WINED3DCLEAR_TARGET) {
4447 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4448 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4449 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4450 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4451 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4454 LEAVE_GL();
4456 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4457 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4459 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4460 target->Flags |= SFLAG_INTEXTURE;
4461 target->Flags &= ~SFLAG_INSYSMEM;
4462 } else {
4463 target->Flags |= SFLAG_INDRAWABLE;
4464 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4466 return WINED3D_OK;
4469 /*****
4470 * Drawing functions
4471 *****/
4472 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4473 UINT PrimitiveCount) {
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4477 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4478 debug_d3dprimitivetype(PrimitiveType),
4479 StartVertex, PrimitiveCount);
4481 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4482 if(This->stateBlock->streamIsUP) {
4483 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4484 This->stateBlock->streamIsUP = FALSE;
4487 if(This->stateBlock->loadBaseVertexIndex != 0) {
4488 This->stateBlock->loadBaseVertexIndex = 0;
4489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4491 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4492 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4493 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4494 return WINED3D_OK;
4497 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4498 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4499 WINED3DPRIMITIVETYPE PrimitiveType,
4500 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 UINT idxStride = 2;
4504 IWineD3DIndexBuffer *pIB;
4505 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4506 GLuint vbo;
4508 if(This->stateBlock->streamIsUP) {
4509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4510 This->stateBlock->streamIsUP = FALSE;
4512 pIB = This->stateBlock->pIndexData;
4513 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4515 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4516 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4517 minIndex, NumVertices, startIndex, primCount);
4519 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4520 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4521 idxStride = 2;
4522 } else {
4523 idxStride = 4;
4526 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4527 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4531 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4532 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4534 return WINED3D_OK;
4537 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4538 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4539 UINT VertexStreamZeroStride) {
4540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4543 debug_d3dprimitivetype(PrimitiveType),
4544 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4546 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4547 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4548 This->stateBlock->streamOffset[0] = 0;
4549 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4550 This->stateBlock->streamIsUP = TRUE;
4551 This->stateBlock->loadBaseVertexIndex = 0;
4553 /* TODO: Only mark dirty if drawing from a different UP address */
4554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4556 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4557 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4559 /* MSDN specifies stream zero settings must be set to NULL */
4560 This->stateBlock->streamStride[0] = 0;
4561 This->stateBlock->streamSource[0] = NULL;
4563 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4564 * the new stream sources or use UP drawing again
4566 return WINED3D_OK;
4569 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4570 UINT MinVertexIndex, UINT NumVertices,
4571 UINT PrimitiveCount, CONST void* pIndexData,
4572 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4573 UINT VertexStreamZeroStride) {
4574 int idxStride;
4575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4577 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4578 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4579 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4580 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4582 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4583 idxStride = 2;
4584 } else {
4585 idxStride = 4;
4588 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4589 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4590 This->stateBlock->streamIsUP = TRUE;
4591 This->stateBlock->streamOffset[0] = 0;
4592 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4594 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4595 This->stateBlock->baseVertexIndex = 0;
4596 This->stateBlock->loadBaseVertexIndex = 0;
4597 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4601 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4603 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4604 This->stateBlock->streamSource[0] = NULL;
4605 This->stateBlock->streamStride[0] = 0;
4606 This->stateBlock->pIndexData = NULL;
4607 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4608 * SetStreamSource to specify a vertex buffer
4611 return WINED3D_OK;
4614 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4617 /* Mark the state dirty until we have nicer tracking
4618 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4619 * that value.
4621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4623 This->stateBlock->baseVertexIndex = 0;
4624 This->up_strided = DrawPrimStrideData;
4625 This->stateBlock->streamIsUP = TRUE;
4626 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4627 This->up_strided = NULL;
4628 return WINED3D_OK;
4630 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4631 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 HRESULT hr = WINED3D_OK;
4634 WINED3DRESOURCETYPE sourceType;
4635 WINED3DRESOURCETYPE destinationType;
4636 int i ,levels;
4638 /* TODO: think about moving the code into IWineD3DBaseTexture */
4640 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4642 /* verify that the source and destination textures aren't NULL */
4643 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4644 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4645 This, pSourceTexture, pDestinationTexture);
4646 hr = WINED3DERR_INVALIDCALL;
4649 if (pSourceTexture == pDestinationTexture) {
4650 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4651 This, pSourceTexture, pDestinationTexture);
4652 hr = WINED3DERR_INVALIDCALL;
4654 /* Verify that the source and destination textures are the same type */
4655 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4656 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4658 if (sourceType != destinationType) {
4659 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4660 This);
4661 hr = WINED3DERR_INVALIDCALL;
4664 /* check that both textures have the identical numbers of levels */
4665 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4666 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4667 hr = WINED3DERR_INVALIDCALL;
4670 if (WINED3D_OK == hr) {
4672 /* Make sure that the destination texture is loaded */
4673 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4675 /* Update every surface level of the texture */
4676 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4678 switch (sourceType) {
4679 case WINED3DRTYPE_TEXTURE:
4681 IWineD3DSurface *srcSurface;
4682 IWineD3DSurface *destSurface;
4684 for (i = 0 ; i < levels ; ++i) {
4685 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4686 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4687 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4688 IWineD3DSurface_Release(srcSurface);
4689 IWineD3DSurface_Release(destSurface);
4690 if (WINED3D_OK != hr) {
4691 WARN("(%p) : Call to update surface failed\n", This);
4692 return hr;
4696 break;
4697 case WINED3DRTYPE_CUBETEXTURE:
4699 IWineD3DSurface *srcSurface;
4700 IWineD3DSurface *destSurface;
4701 WINED3DCUBEMAP_FACES faceType;
4703 for (i = 0 ; i < levels ; ++i) {
4704 /* Update each cube face */
4705 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4706 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4707 if (WINED3D_OK != hr) {
4708 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4709 } else {
4710 TRACE("Got srcSurface %p\n", srcSurface);
4712 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4713 if (WINED3D_OK != hr) {
4714 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4715 } else {
4716 TRACE("Got desrSurface %p\n", destSurface);
4718 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4719 IWineD3DSurface_Release(srcSurface);
4720 IWineD3DSurface_Release(destSurface);
4721 if (WINED3D_OK != hr) {
4722 WARN("(%p) : Call to update surface failed\n", This);
4723 return hr;
4728 break;
4729 #if 0 /* TODO: Add support for volume textures */
4730 case WINED3DRTYPE_VOLUMETEXTURE:
4732 IWineD3DVolume srcVolume = NULL;
4733 IWineD3DSurface destVolume = NULL;
4735 for (i = 0 ; i < levels ; ++i) {
4736 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4737 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4738 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4739 IWineD3DVolume_Release(srcSurface);
4740 IWineD3DVolume_Release(destSurface);
4741 if (WINED3D_OK != hr) {
4742 WARN("(%p) : Call to update volume failed\n", This);
4743 return hr;
4747 break;
4748 #endif
4749 default:
4750 FIXME("(%p) : Unsupported source and destination type\n", This);
4751 hr = WINED3DERR_INVALIDCALL;
4755 return hr;
4758 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4759 IWineD3DSwapChain *swapChain;
4760 HRESULT hr;
4761 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4762 if(hr == WINED3D_OK) {
4763 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4764 IWineD3DSwapChain_Release(swapChain);
4766 return hr;
4769 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4771 /* return a sensible default */
4772 *pNumPasses = 1;
4773 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4774 FIXME("(%p) : stub\n", This);
4775 return WINED3D_OK;
4778 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 int j;
4781 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4782 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4783 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4784 return WINED3DERR_INVALIDCALL;
4786 for (j = 0; j < 256; ++j) {
4787 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4788 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4789 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4790 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4792 TRACE("(%p) : returning\n", This);
4793 return WINED3D_OK;
4796 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798 int j;
4799 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4800 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4801 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4802 return WINED3DERR_INVALIDCALL;
4804 for (j = 0; j < 256; ++j) {
4805 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4806 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4807 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4808 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4810 TRACE("(%p) : returning\n", This);
4811 return WINED3D_OK;
4814 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4816 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4817 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4818 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4819 return WINED3DERR_INVALIDCALL;
4821 /*TODO: stateblocks */
4822 This->currentPalette = PaletteNumber;
4823 TRACE("(%p) : returning\n", This);
4824 return WINED3D_OK;
4827 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4829 if (PaletteNumber == NULL) {
4830 WARN("(%p) : returning Invalid Call\n", This);
4831 return WINED3DERR_INVALIDCALL;
4833 /*TODO: stateblocks */
4834 *PaletteNumber = This->currentPalette;
4835 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4836 return WINED3D_OK;
4839 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 static BOOL showFixmes = TRUE;
4842 if (showFixmes) {
4843 FIXME("(%p) : stub\n", This);
4844 showFixmes = FALSE;
4847 This->softwareVertexProcessing = bSoftware;
4848 return WINED3D_OK;
4852 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4854 static BOOL showFixmes = TRUE;
4855 if (showFixmes) {
4856 FIXME("(%p) : stub\n", This);
4857 showFixmes = FALSE;
4859 return This->softwareVertexProcessing;
4863 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 IWineD3DSwapChain *swapChain;
4866 HRESULT hr;
4868 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4870 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4871 if(hr == WINED3D_OK){
4872 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4873 IWineD3DSwapChain_Release(swapChain);
4874 }else{
4875 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4877 return hr;
4881 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4883 static BOOL showfixmes = TRUE;
4884 if(nSegments != 0.0f) {
4885 if( showfixmes) {
4886 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4887 showfixmes = FALSE;
4890 return WINED3D_OK;
4893 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4895 static BOOL showfixmes = TRUE;
4896 if( showfixmes) {
4897 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4898 showfixmes = FALSE;
4900 return 0.0f;
4903 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4905 /** TODO: remove casts to IWineD3DSurfaceImpl
4906 * NOTE: move code to surface to accomplish this
4907 ****************************************/
4908 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4909 int srcWidth, srcHeight;
4910 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4911 WINED3DFORMAT destFormat, srcFormat;
4912 UINT destSize;
4913 int srcLeft, destLeft, destTop;
4914 WINED3DPOOL srcPool, destPool;
4915 int offset = 0;
4916 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4917 glDescriptor *glDescription = NULL;
4919 WINED3DSURFACE_DESC winedesc;
4921 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4922 memset(&winedesc, 0, sizeof(winedesc));
4923 winedesc.Width = &srcSurfaceWidth;
4924 winedesc.Height = &srcSurfaceHeight;
4925 winedesc.Pool = &srcPool;
4926 winedesc.Format = &srcFormat;
4928 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4930 winedesc.Width = &destSurfaceWidth;
4931 winedesc.Height = &destSurfaceHeight;
4932 winedesc.Pool = &destPool;
4933 winedesc.Format = &destFormat;
4934 winedesc.Size = &destSize;
4936 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4938 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4939 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4940 return WINED3DERR_INVALIDCALL;
4943 if (destFormat == WINED3DFMT_UNKNOWN) {
4944 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4945 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4947 /* Get the update surface description */
4948 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4951 ENTER_GL();
4953 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4955 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4956 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4957 checkGLcall("glActiveTextureARB");
4960 /* Make sure the surface is loaded and up to date */
4961 IWineD3DSurface_PreLoad(pDestinationSurface);
4963 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4965 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4966 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4967 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4968 srcLeft = pSourceRect ? pSourceRect->left : 0;
4969 destLeft = pDestPoint ? pDestPoint->x : 0;
4970 destTop = pDestPoint ? pDestPoint->y : 0;
4973 /* This function doesn't support compressed textures
4974 the pitch is just bytesPerPixel * width */
4975 if(srcWidth != srcSurfaceWidth || srcLeft ){
4976 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4977 offset += srcLeft * pSrcSurface->bytesPerPixel;
4978 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4980 /* TODO DXT formats */
4982 if(pSourceRect != NULL && pSourceRect->top != 0){
4983 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4985 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4986 ,This
4987 ,glDescription->level
4988 ,destLeft
4989 ,destTop
4990 ,srcWidth
4991 ,srcHeight
4992 ,glDescription->glFormat
4993 ,glDescription->glType
4994 ,IWineD3DSurface_GetData(pSourceSurface)
4997 /* Sanity check */
4998 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5000 /* need to lock the surface to get the data */
5001 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5004 /* TODO: Cube and volume support */
5005 if(rowoffset != 0){
5006 /* not a whole row so we have to do it a line at a time */
5007 int j;
5009 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5010 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5012 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5014 glTexSubImage2D(glDescription->target
5015 ,glDescription->level
5016 ,destLeft
5018 ,srcWidth
5020 ,glDescription->glFormat
5021 ,glDescription->glType
5022 ,data /* could be quicker using */
5024 data += rowoffset;
5027 } else { /* Full width, so just write out the whole texture */
5029 if (WINED3DFMT_DXT1 == destFormat ||
5030 WINED3DFMT_DXT2 == destFormat ||
5031 WINED3DFMT_DXT3 == destFormat ||
5032 WINED3DFMT_DXT4 == destFormat ||
5033 WINED3DFMT_DXT5 == destFormat) {
5034 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5035 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5036 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5037 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5038 } if (destFormat != srcFormat) {
5039 FIXME("Updating mixed format compressed texture is not curretly support\n");
5040 } else {
5041 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5042 glDescription->level,
5043 glDescription->glFormatInternal,
5044 srcWidth,
5045 srcHeight,
5047 destSize,
5048 IWineD3DSurface_GetData(pSourceSurface));
5050 } else {
5051 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5055 } else {
5056 glTexSubImage2D(glDescription->target
5057 ,glDescription->level
5058 ,destLeft
5059 ,destTop
5060 ,srcWidth
5061 ,srcHeight
5062 ,glDescription->glFormat
5063 ,glDescription->glType
5064 ,IWineD3DSurface_GetData(pSourceSurface)
5068 checkGLcall("glTexSubImage2D");
5070 LEAVE_GL();
5072 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5073 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5074 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5076 return WINED3D_OK;
5079 /* Implementation details at http://developer.nvidia.com/attach/6494
5081 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5082 hmm.. no longer supported use
5083 OpenGL evaluators or tessellate surfaces within your application.
5086 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5087 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5089 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5090 FIXME("(%p) : Stub\n", This);
5091 return WINED3D_OK;
5095 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5096 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5098 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5099 FIXME("(%p) : Stub\n", This);
5100 return WINED3D_OK;
5103 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5104 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5105 TRACE("(%p) Handle(%d)\n", This, Handle);
5106 FIXME("(%p) : Stub\n", This);
5107 return WINED3D_OK;
5110 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5111 HRESULT hr;
5112 IWineD3DSwapChain *swapchain;
5114 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5115 if (SUCCEEDED(hr)) {
5116 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5117 return swapchain;
5120 return NULL;
5123 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 if (!*fbo) {
5127 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5128 checkGLcall("glGenFramebuffersEXT()");
5130 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5131 checkGLcall("glBindFramebuffer()");
5134 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5135 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5136 GLenum texttarget, target;
5137 GLint old_binding;
5139 texttarget = surface_impl->glDescription.target;
5140 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5141 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5143 IWineD3DSurface_PreLoad(surface);
5145 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5146 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5147 glBindTexture(target, old_binding);
5149 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5151 checkGLcall("attach_surface_fbo");
5154 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5156 IWineD3DSwapChain *swapchain;
5158 swapchain = get_swapchain(surface);
5159 if (swapchain) {
5160 GLenum buffer;
5162 TRACE("Surface %p is onscreen\n", surface);
5164 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5165 buffer = surface_get_gl_buffer(surface, swapchain);
5166 glDrawBuffer(buffer);
5167 checkGLcall("glDrawBuffer()");
5168 } else {
5169 TRACE("Surface %p is offscreen\n", surface);
5170 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5171 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5174 if (rect) {
5175 glEnable(GL_SCISSOR_TEST);
5176 if(!swapchain) {
5177 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5178 } else {
5179 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5180 rect->x2 - rect->x1, rect->y2 - rect->y1);
5182 checkGLcall("glScissor");
5183 } else {
5184 glDisable(GL_SCISSOR_TEST);
5186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5188 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5191 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5192 glClear(GL_COLOR_BUFFER_BIT);
5193 checkGLcall("glClear");
5195 if (This->render_offscreen) {
5196 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5197 } else {
5198 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5199 checkGLcall("glBindFramebuffer()");
5202 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5203 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5204 glDrawBuffer(GL_BACK);
5205 checkGLcall("glDrawBuffer()");
5209 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5211 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5212 WINEDDBLTFX BltFx;
5213 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5215 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5216 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5217 return WINED3DERR_INVALIDCALL;
5220 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5221 color_fill_fbo(iface, pSurface, pRect, color);
5222 return WINED3D_OK;
5223 } else {
5224 /* Just forward this to the DirectDraw blitting engine */
5225 memset(&BltFx, 0, sizeof(BltFx));
5226 BltFx.dwSize = sizeof(BltFx);
5227 BltFx.u5.dwFillColor = color;
5228 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5232 /* rendertarget and deptth stencil functions */
5233 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5236 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5237 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5238 return WINED3DERR_INVALIDCALL;
5241 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5242 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5243 /* Note inc ref on returned surface */
5244 if(*ppRenderTarget != NULL)
5245 IWineD3DSurface_AddRef(*ppRenderTarget);
5246 return WINED3D_OK;
5249 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5251 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5252 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5253 IWineD3DSwapChainImpl *Swapchain;
5254 HRESULT hr;
5256 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5258 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5259 if(hr != WINED3D_OK) {
5260 ERR("Can't get the swapchain\n");
5261 return hr;
5264 /* Make sure to release the swapchain */
5265 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5267 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5268 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5269 return WINED3DERR_INVALIDCALL;
5271 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5272 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5273 return WINED3DERR_INVALIDCALL;
5276 if(Swapchain->frontBuffer != Front) {
5277 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5279 if(Swapchain->frontBuffer)
5280 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5281 Swapchain->frontBuffer = Front;
5283 if(Swapchain->frontBuffer) {
5284 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5288 if(Back && !Swapchain->backBuffer) {
5289 /* We need memory for the back buffer array - only one back buffer this way */
5290 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5291 if(!Swapchain->backBuffer) {
5292 ERR("Out of memory\n");
5293 return E_OUTOFMEMORY;
5297 if(Swapchain->backBuffer[0] != Back) {
5298 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5300 /* What to do about the context here in the case of multithreading? Not sure.
5301 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5303 ENTER_GL();
5304 if(!Swapchain->backBuffer[0]) {
5305 /* GL was told to draw to the front buffer at creation,
5306 * undo that
5308 glDrawBuffer(GL_BACK);
5309 checkGLcall("glDrawBuffer(GL_BACK)");
5310 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5311 Swapchain->presentParms.BackBufferCount = 1;
5312 } else if (!Back) {
5313 /* That makes problems - disable for now */
5314 /* glDrawBuffer(GL_FRONT); */
5315 checkGLcall("glDrawBuffer(GL_FRONT)");
5316 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5317 Swapchain->presentParms.BackBufferCount = 0;
5319 LEAVE_GL();
5321 if(Swapchain->backBuffer[0])
5322 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5323 Swapchain->backBuffer[0] = Back;
5325 if(Swapchain->backBuffer[0]) {
5326 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5327 } else {
5328 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5333 return WINED3D_OK;
5336 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 *ppZStencilSurface = This->depthStencilBuffer;
5339 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5341 if(*ppZStencilSurface != NULL) {
5342 /* Note inc ref on returned surface */
5343 IWineD3DSurface_AddRef(*ppZStencilSurface);
5345 return WINED3D_OK;
5348 /* TODO: Handle stencil attachments */
5349 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5351 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5353 TRACE("Set depth stencil to %p\n", depth_stencil);
5355 if (depth_stencil_impl) {
5356 if (depth_stencil_impl->current_renderbuffer) {
5357 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5358 checkGLcall("glFramebufferRenderbufferEXT()");
5359 } else {
5360 GLenum texttarget, target;
5361 GLint old_binding = 0;
5363 texttarget = depth_stencil_impl->glDescription.target;
5364 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5365 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5367 IWineD3DSurface_PreLoad(depth_stencil);
5369 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5370 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5371 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5372 glBindTexture(target, old_binding);
5374 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5375 checkGLcall("glFramebufferTexture2DEXT()");
5377 } else {
5378 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5379 checkGLcall("glFramebufferTexture2DEXT()");
5383 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5385 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5387 TRACE("Set render target %u to %p\n", idx, render_target);
5389 if (rtimpl) {
5390 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5391 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5392 } else {
5393 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5394 checkGLcall("glFramebufferTexture2DEXT()");
5396 This->draw_buffers[idx] = GL_NONE;
5400 static void check_fbo_status(IWineD3DDevice *iface) {
5401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5402 GLenum status;
5404 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5405 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5406 TRACE("FBO complete\n");
5407 } else {
5408 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5410 /* Dump the FBO attachments */
5411 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5412 IWineD3DSurfaceImpl *attachment;
5413 int i;
5415 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5416 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5417 if (attachment) {
5418 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5419 attachment->pow2Width, attachment->pow2Height);
5422 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5423 if (attachment) {
5424 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5425 attachment->pow2Width, attachment->pow2Height);
5431 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5433 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5434 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5436 if (!ds_impl) return FALSE;
5438 if (ds_impl->current_renderbuffer) {
5439 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5440 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5443 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5444 rt_impl->pow2Height != ds_impl->pow2Height);
5447 void apply_fbo_state(IWineD3DDevice *iface) {
5448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5449 unsigned int i;
5451 if (This->render_offscreen) {
5452 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5454 /* Apply render targets */
5455 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5456 IWineD3DSurface *render_target = This->render_targets[i];
5457 if (This->fbo_color_attachments[i] != render_target) {
5458 set_render_target_fbo(iface, i, render_target);
5459 This->fbo_color_attachments[i] = render_target;
5463 /* Apply depth targets */
5464 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5465 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5466 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5468 if (This->stencilBufferTarget) {
5469 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5471 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5472 This->fbo_depth_attachment = This->stencilBufferTarget;
5475 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5476 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5477 checkGLcall("glDrawBuffers()");
5478 } else {
5479 glDrawBuffer(This->draw_buffers[0]);
5480 checkGLcall("glDrawBuffer()");
5482 } else {
5483 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5486 check_fbo_status(iface);
5489 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5490 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5492 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5493 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5494 GLenum gl_filter;
5496 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5497 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5498 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5499 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5501 glDisable(GL_SCISSOR_TEST);
5502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5504 switch (filter) {
5505 case WINED3DTEXF_LINEAR:
5506 gl_filter = GL_LINEAR;
5507 break;
5509 default:
5510 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5511 case WINED3DTEXF_NONE:
5512 case WINED3DTEXF_POINT:
5513 gl_filter = GL_NEAREST;
5514 break;
5517 /* Attach src surface to src fbo */
5518 src_swapchain = get_swapchain(src_surface);
5519 if (src_swapchain) {
5520 GLenum buffer;
5522 TRACE("Source surface %p is onscreen\n", src_surface);
5524 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5525 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5526 glReadBuffer(buffer);
5527 checkGLcall("glReadBuffer()");
5529 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5530 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5531 } else {
5532 TRACE("Source surface %p is offscreen\n", src_surface);
5533 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5534 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5535 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5536 checkGLcall("glReadBuffer()");
5539 /* Attach dst surface to dst fbo */
5540 dst_swapchain = get_swapchain(dst_surface);
5541 if (dst_swapchain) {
5542 GLenum buffer;
5544 TRACE("Destination surface %p is onscreen\n", dst_surface);
5546 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5547 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5548 glDrawBuffer(buffer);
5549 checkGLcall("glDrawBuffer()");
5551 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5552 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5553 } else {
5554 TRACE("Destination surface %p is offscreen\n", dst_surface);
5555 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5556 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5557 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5558 checkGLcall("glDrawBuffer()");
5561 if (flip) {
5562 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5563 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5564 } else {
5565 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5566 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5569 if (This->render_offscreen) {
5570 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5571 } else {
5572 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5573 checkGLcall("glBindFramebuffer()");
5576 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5577 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5578 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5579 glDrawBuffer(GL_BACK);
5580 checkGLcall("glDrawBuffer()");
5584 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5586 WINED3DVIEWPORT viewport;
5588 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5590 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5591 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5592 return WINED3DERR_INVALIDCALL;
5595 /* MSDN says that null disables the render target
5596 but a device must always be associated with a render target
5597 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5599 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5600 for more details
5602 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5603 FIXME("Trying to set render target 0 to NULL\n");
5604 return WINED3DERR_INVALIDCALL;
5606 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5607 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);
5608 return WINED3DERR_INVALIDCALL;
5611 /* If we are trying to set what we already have, don't bother */
5612 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5613 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5614 return WINED3D_OK;
5616 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5617 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5618 This->render_targets[RenderTargetIndex] = pRenderTarget;
5620 /* Render target 0 is special */
5621 if(RenderTargetIndex == 0) {
5622 /* Finally, reset the viewport as the MSDN states. */
5623 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5624 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5625 viewport.X = 0;
5626 viewport.Y = 0;
5627 viewport.MaxZ = 1.0f;
5628 viewport.MinZ = 0.0f;
5629 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5630 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5631 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5635 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5636 * ctx properly.
5637 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5638 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5640 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5642 return WINED3D_OK;
5645 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 HRESULT hr = WINED3D_OK;
5648 IWineD3DSurface *tmp;
5650 TRACE("(%p) Swapping z-buffer\n",This);
5652 if (pNewZStencil == This->stencilBufferTarget) {
5653 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5654 } else {
5655 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5656 * depending on the renter target implementation being used.
5657 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5658 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5659 * stencil buffer and incure an extra memory overhead
5660 ******************************************************/
5662 tmp = This->stencilBufferTarget;
5663 This->stencilBufferTarget = pNewZStencil;
5664 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5665 /* should we be calling the parent or the wined3d surface? */
5666 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5667 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5668 hr = WINED3D_OK;
5670 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5671 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5678 return hr;
5681 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5682 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5684 /* TODO: the use of Impl is deprecated. */
5685 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5687 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5689 /* some basic validation checks */
5690 if(This->cursorTexture) {
5691 ENTER_GL();
5692 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5693 glDeleteTextures(1, &This->cursorTexture);
5694 LEAVE_GL();
5695 This->cursorTexture = 0;
5698 if(pCursorBitmap) {
5699 WINED3DLOCKED_RECT rect;
5701 /* MSDN: Cursor must be A8R8G8B8 */
5702 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5703 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5704 return WINED3DERR_INVALIDCALL;
5707 /* MSDN: Cursor must be smaller than the display mode */
5708 if(pSur->currentDesc.Width > This->ddraw_width ||
5709 pSur->currentDesc.Height > This->ddraw_height) {
5710 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);
5711 return WINED3DERR_INVALIDCALL;
5714 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5716 /* Do not store the surface's pointer because the application may release
5717 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5718 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5720 This->cursorWidth = pSur->currentDesc.Width;
5721 This->cursorHeight = pSur->currentDesc.Height;
5722 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5724 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5725 char *mem, *bits = (char *)rect.pBits;
5726 GLint intfmt = tableEntry->glInternal;
5727 GLint format = tableEntry->glFormat;
5728 GLint type = tableEntry->glType;
5729 INT height = This->cursorHeight;
5730 INT width = This->cursorWidth;
5731 INT bpp = tableEntry->bpp;
5732 INT i;
5734 /* Reformat the texture memory (pitch and width can be different) */
5735 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5736 for(i = 0; i < height; i++)
5737 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5738 IWineD3DSurface_UnlockRect(pCursorBitmap);
5739 ENTER_GL();
5741 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5742 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5743 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5746 /* Make sure that a proper texture unit is selected */
5747 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5748 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5749 checkGLcall("glActiveTextureARB");
5751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5752 /* Create a new cursor texture */
5753 glGenTextures(1, &This->cursorTexture);
5754 checkGLcall("glGenTextures");
5755 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5756 checkGLcall("glBindTexture");
5757 /* Copy the bitmap memory into the cursor texture */
5758 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5759 HeapFree(GetProcessHeap(), 0, mem);
5760 checkGLcall("glTexImage2D");
5762 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5763 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5764 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5767 LEAVE_GL();
5769 else
5771 FIXME("A cursor texture was not returned.\n");
5772 This->cursorTexture = 0;
5777 This->xHotSpot = XHotSpot;
5778 This->yHotSpot = YHotSpot;
5779 return WINED3D_OK;
5782 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5784 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5786 This->xScreenSpace = XScreenSpace;
5787 This->yScreenSpace = YScreenSpace;
5789 return;
5793 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5795 BOOL oldVisible = This->bCursorVisible;
5796 POINT pt;
5798 TRACE("(%p) : visible(%d)\n", This, bShow);
5800 if(This->cursorTexture)
5801 This->bCursorVisible = bShow;
5803 * When ShowCursor is first called it should make the cursor appear at the OS's last
5804 * known cursor position. Because of this, some applications just repetitively call
5805 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5807 GetCursorPos(&pt);
5808 This->xScreenSpace = pt.x;
5809 This->yScreenSpace = pt.y;
5811 return oldVisible;
5814 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5816 TRACE("(%p) : state (%u)\n", This, This->state);
5817 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5818 switch (This->state) {
5819 case WINED3D_OK:
5820 return WINED3D_OK;
5821 case WINED3DERR_DEVICELOST:
5823 ResourceList *resourceList = This->resources;
5824 while (NULL != resourceList) {
5825 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5826 return WINED3DERR_DEVICENOTRESET;
5827 resourceList = resourceList->next;
5829 return WINED3DERR_DEVICELOST;
5831 case WINED3DERR_DRIVERINTERNALERROR:
5832 return WINED3DERR_DRIVERINTERNALERROR;
5835 /* Unknown state */
5836 return WINED3DERR_DRIVERINTERNALERROR;
5840 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5842 /** FIXME: Resource tracking needs to be done,
5843 * The closes we can do to this is set the priorities of all managed textures low
5844 * and then reset them.
5845 ***********************************************************/
5846 FIXME("(%p) : stub\n", This);
5847 return WINED3D_OK;
5850 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5851 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5853 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5854 if(surface->Flags & SFLAG_DIBSECTION) {
5855 /* Release the DC */
5856 SelectObject(surface->hDC, surface->dib.holdbitmap);
5857 DeleteDC(surface->hDC);
5858 /* Release the DIB section */
5859 DeleteObject(surface->dib.DIBsection);
5860 surface->dib.bitmap_data = NULL;
5861 surface->resource.allocatedMemory = NULL;
5862 surface->Flags &= ~SFLAG_DIBSECTION;
5864 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5865 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5866 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5867 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5868 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5869 } else {
5870 surface->pow2Width = surface->pow2Height = 1;
5871 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5872 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5874 if(surface->glDescription.textureName) {
5875 ENTER_GL();
5876 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5877 glDeleteTextures(1, &surface->glDescription.textureName);
5878 LEAVE_GL();
5879 surface->glDescription.textureName = 0;
5880 surface->Flags &= ~SFLAG_CLIENT;
5882 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5883 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5884 surface->Flags |= SFLAG_NONPOW2;
5885 } else {
5886 surface->Flags &= ~SFLAG_NONPOW2;
5888 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5889 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5892 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5894 IWineD3DSwapChainImpl *swapchain;
5895 HRESULT hr;
5896 BOOL DisplayModeChanged = FALSE;
5897 WINED3DDISPLAYMODE mode;
5898 TRACE("(%p)\n", This);
5900 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5901 if(FAILED(hr)) {
5902 ERR("Failed to get the first implicit swapchain\n");
5903 return hr;
5906 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5907 * on an existing gl context, so there's no real need for recreation.
5909 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5911 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5913 TRACE("New params:\n");
5914 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5915 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5916 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5917 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5918 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5919 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5920 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5921 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5922 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5923 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5924 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5925 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5926 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5928 /* No special treatment of these parameters. Just store them */
5929 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5930 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5931 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5932 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5934 /* What to do about these? */
5935 if(pPresentationParameters->BackBufferCount != 0 &&
5936 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5937 ERR("Cannot change the back buffer count yet\n");
5939 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5940 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5941 ERR("Cannot change the back buffer format yet\n");
5943 if(pPresentationParameters->hDeviceWindow != NULL &&
5944 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5945 ERR("Cannot change the device window yet\n");
5947 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5948 ERR("What do do about a changed auto depth stencil parameter?\n");
5951 if(pPresentationParameters->Windowed) {
5952 mode.Width = swapchain->orig_width;
5953 mode.Height = swapchain->orig_height;
5954 mode.RefreshRate = 0;
5955 mode.Format = swapchain->presentParms.BackBufferFormat;
5956 } else {
5957 mode.Width = pPresentationParameters->BackBufferWidth;
5958 mode.Height = pPresentationParameters->BackBufferHeight;
5959 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5960 mode.Format = swapchain->presentParms.BackBufferFormat;
5963 /* Should Width == 800 && Height == 0 set 800x600? */
5964 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5965 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5966 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5968 WINED3DVIEWPORT vp;
5969 int i;
5971 vp.X = 0;
5972 vp.Y = 0;
5973 vp.Width = pPresentationParameters->BackBufferWidth;
5974 vp.Height = pPresentationParameters->BackBufferHeight;
5975 vp.MinZ = 0;
5976 vp.MaxZ = 1;
5978 if(!pPresentationParameters->Windowed) {
5979 DisplayModeChanged = TRUE;
5981 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5982 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5984 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5985 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5986 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5989 /* Now set the new viewport */
5990 IWineD3DDevice_SetViewport(iface, &vp);
5993 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5994 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5995 DisplayModeChanged) {
5997 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5998 if(!pPresentationParameters->Windowed) {
5999 IWineD3DDevice_SetFullscreen(iface, TRUE);
6002 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6004 /* Switching out of fullscreen mode? First set the original res, then change the window */
6005 if(pPresentationParameters->Windowed) {
6006 IWineD3DDevice_SetFullscreen(iface, FALSE);
6008 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6011 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6012 return WINED3D_OK;
6015 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6017 /** FIXME: always true at the moment **/
6018 if(!bEnableDialogs) {
6019 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6021 return WINED3D_OK;
6025 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6027 TRACE("(%p) : pParameters %p\n", This, pParameters);
6029 *pParameters = This->createParms;
6030 return WINED3D_OK;
6033 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6034 IWineD3DSwapChain *swapchain;
6035 HRESULT hrc = WINED3D_OK;
6037 TRACE("Relaying to swapchain\n");
6039 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6040 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6041 IWineD3DSwapChain_Release(swapchain);
6043 return;
6046 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6047 IWineD3DSwapChain *swapchain;
6048 HRESULT hrc = WINED3D_OK;
6050 TRACE("Relaying to swapchain\n");
6052 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6053 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6054 IWineD3DSwapChain_Release(swapchain);
6056 return;
6060 /** ********************************************************
6061 * Notification functions
6062 ** ********************************************************/
6063 /** This function must be called in the release of a resource when ref == 0,
6064 * the contents of resource must still be correct,
6065 * any handels to other resource held by the caller must be closed
6066 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6067 *****************************************************/
6068 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6070 ResourceList* resourceList;
6072 TRACE("(%p) : resource %p\n", This, resource);
6073 /* add a new texture to the frot of the linked list */
6074 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6075 resourceList->resource = resource;
6077 /* Get the old head */
6078 resourceList->next = This->resources;
6080 This->resources = resourceList;
6081 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6083 return;
6086 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6088 ResourceList* resourceList = NULL;
6089 ResourceList* previousResourceList = NULL;
6091 TRACE("(%p) : resource %p\n", This, resource);
6093 resourceList = This->resources;
6095 while (resourceList != NULL) {
6096 if(resourceList->resource == resource) break;
6097 previousResourceList = resourceList;
6098 resourceList = resourceList->next;
6101 if (resourceList == NULL) {
6102 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6103 return;
6104 } else {
6105 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6107 /* make sure we don't leave a hole in the list */
6108 if (previousResourceList != NULL) {
6109 previousResourceList->next = resourceList->next;
6110 } else {
6111 This->resources = resourceList->next;
6114 return;
6118 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6120 int counter;
6122 TRACE("(%p) : resource %p\n", This, resource);
6123 switch(IWineD3DResource_GetType(resource)){
6124 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6125 case WINED3DRTYPE_SURFACE: {
6126 unsigned int i;
6128 /* Cleanup any FBO attachments */
6129 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6130 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6131 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6132 set_render_target_fbo(iface, i, NULL);
6133 This->fbo_color_attachments[i] = NULL;
6136 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6137 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6138 set_depth_stencil_fbo(iface, NULL);
6139 This->fbo_depth_attachment = NULL;
6142 break;
6145 case WINED3DRTYPE_TEXTURE:
6146 case WINED3DRTYPE_CUBETEXTURE:
6147 case WINED3DRTYPE_VOLUMETEXTURE:
6148 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6149 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6150 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6151 This->stateBlock->textures[counter] = NULL;
6153 if (This->updateStateBlock != This->stateBlock ){
6154 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6155 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6156 This->updateStateBlock->textures[counter] = NULL;
6160 break;
6161 case WINED3DRTYPE_VOLUME:
6162 /* TODO: nothing really? */
6163 break;
6164 case WINED3DRTYPE_VERTEXBUFFER:
6165 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6167 int streamNumber;
6168 TRACE("Cleaning up stream pointers\n");
6170 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6171 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6172 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6174 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6175 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6176 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6177 This->updateStateBlock->streamSource[streamNumber] = 0;
6178 /* Set changed flag? */
6181 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) */
6182 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6183 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6184 This->stateBlock->streamSource[streamNumber] = 0;
6187 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6188 else { /* This shouldn't happen */
6189 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6191 #endif
6195 break;
6196 case WINED3DRTYPE_INDEXBUFFER:
6197 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6198 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6199 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6200 This->updateStateBlock->pIndexData = NULL;
6203 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6204 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6205 This->stateBlock->pIndexData = NULL;
6209 break;
6210 default:
6211 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6212 break;
6216 /* Remove the resoruce from the resourceStore */
6217 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6219 TRACE("Resource released\n");
6223 /**********************************************************
6224 * IWineD3DDevice VTbl follows
6225 **********************************************************/
6227 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6229 /*** IUnknown methods ***/
6230 IWineD3DDeviceImpl_QueryInterface,
6231 IWineD3DDeviceImpl_AddRef,
6232 IWineD3DDeviceImpl_Release,
6233 /*** IWineD3DDevice methods ***/
6234 IWineD3DDeviceImpl_GetParent,
6235 /*** Creation methods**/
6236 IWineD3DDeviceImpl_CreateVertexBuffer,
6237 IWineD3DDeviceImpl_CreateIndexBuffer,
6238 IWineD3DDeviceImpl_CreateStateBlock,
6239 IWineD3DDeviceImpl_CreateSurface,
6240 IWineD3DDeviceImpl_CreateTexture,
6241 IWineD3DDeviceImpl_CreateVolumeTexture,
6242 IWineD3DDeviceImpl_CreateVolume,
6243 IWineD3DDeviceImpl_CreateCubeTexture,
6244 IWineD3DDeviceImpl_CreateQuery,
6245 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6246 IWineD3DDeviceImpl_CreateVertexDeclaration,
6247 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6248 IWineD3DDeviceImpl_CreateVertexShader,
6249 IWineD3DDeviceImpl_CreatePixelShader,
6250 IWineD3DDeviceImpl_CreatePalette,
6251 /*** Odd functions **/
6252 IWineD3DDeviceImpl_Init3D,
6253 IWineD3DDeviceImpl_Uninit3D,
6254 IWineD3DDeviceImpl_SetFullscreen,
6255 IWineD3DDeviceImpl_SetMultithreaded,
6256 IWineD3DDeviceImpl_EvictManagedResources,
6257 IWineD3DDeviceImpl_GetAvailableTextureMem,
6258 IWineD3DDeviceImpl_GetBackBuffer,
6259 IWineD3DDeviceImpl_GetCreationParameters,
6260 IWineD3DDeviceImpl_GetDeviceCaps,
6261 IWineD3DDeviceImpl_GetDirect3D,
6262 IWineD3DDeviceImpl_GetDisplayMode,
6263 IWineD3DDeviceImpl_SetDisplayMode,
6264 IWineD3DDeviceImpl_GetHWND,
6265 IWineD3DDeviceImpl_SetHWND,
6266 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6267 IWineD3DDeviceImpl_GetRasterStatus,
6268 IWineD3DDeviceImpl_GetSwapChain,
6269 IWineD3DDeviceImpl_Reset,
6270 IWineD3DDeviceImpl_SetDialogBoxMode,
6271 IWineD3DDeviceImpl_SetCursorProperties,
6272 IWineD3DDeviceImpl_SetCursorPosition,
6273 IWineD3DDeviceImpl_ShowCursor,
6274 IWineD3DDeviceImpl_TestCooperativeLevel,
6275 /*** Getters and setters **/
6276 IWineD3DDeviceImpl_SetClipPlane,
6277 IWineD3DDeviceImpl_GetClipPlane,
6278 IWineD3DDeviceImpl_SetClipStatus,
6279 IWineD3DDeviceImpl_GetClipStatus,
6280 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6281 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6282 IWineD3DDeviceImpl_SetDepthStencilSurface,
6283 IWineD3DDeviceImpl_GetDepthStencilSurface,
6284 IWineD3DDeviceImpl_SetFVF,
6285 IWineD3DDeviceImpl_GetFVF,
6286 IWineD3DDeviceImpl_SetGammaRamp,
6287 IWineD3DDeviceImpl_GetGammaRamp,
6288 IWineD3DDeviceImpl_SetIndices,
6289 IWineD3DDeviceImpl_GetIndices,
6290 IWineD3DDeviceImpl_SetBasevertexIndex,
6291 IWineD3DDeviceImpl_SetLight,
6292 IWineD3DDeviceImpl_GetLight,
6293 IWineD3DDeviceImpl_SetLightEnable,
6294 IWineD3DDeviceImpl_GetLightEnable,
6295 IWineD3DDeviceImpl_SetMaterial,
6296 IWineD3DDeviceImpl_GetMaterial,
6297 IWineD3DDeviceImpl_SetNPatchMode,
6298 IWineD3DDeviceImpl_GetNPatchMode,
6299 IWineD3DDeviceImpl_SetPaletteEntries,
6300 IWineD3DDeviceImpl_GetPaletteEntries,
6301 IWineD3DDeviceImpl_SetPixelShader,
6302 IWineD3DDeviceImpl_GetPixelShader,
6303 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6304 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6305 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6306 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6307 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6308 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6309 IWineD3DDeviceImpl_SetRenderState,
6310 IWineD3DDeviceImpl_GetRenderState,
6311 IWineD3DDeviceImpl_SetRenderTarget,
6312 IWineD3DDeviceImpl_GetRenderTarget,
6313 IWineD3DDeviceImpl_SetFrontBackBuffers,
6314 IWineD3DDeviceImpl_SetSamplerState,
6315 IWineD3DDeviceImpl_GetSamplerState,
6316 IWineD3DDeviceImpl_SetScissorRect,
6317 IWineD3DDeviceImpl_GetScissorRect,
6318 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6319 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6320 IWineD3DDeviceImpl_SetStreamSource,
6321 IWineD3DDeviceImpl_GetStreamSource,
6322 IWineD3DDeviceImpl_SetStreamSourceFreq,
6323 IWineD3DDeviceImpl_GetStreamSourceFreq,
6324 IWineD3DDeviceImpl_SetTexture,
6325 IWineD3DDeviceImpl_GetTexture,
6326 IWineD3DDeviceImpl_SetTextureStageState,
6327 IWineD3DDeviceImpl_GetTextureStageState,
6328 IWineD3DDeviceImpl_SetTransform,
6329 IWineD3DDeviceImpl_GetTransform,
6330 IWineD3DDeviceImpl_SetVertexDeclaration,
6331 IWineD3DDeviceImpl_GetVertexDeclaration,
6332 IWineD3DDeviceImpl_SetVertexShader,
6333 IWineD3DDeviceImpl_GetVertexShader,
6334 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6335 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6336 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6337 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6338 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6339 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6340 IWineD3DDeviceImpl_SetViewport,
6341 IWineD3DDeviceImpl_GetViewport,
6342 IWineD3DDeviceImpl_MultiplyTransform,
6343 IWineD3DDeviceImpl_ValidateDevice,
6344 IWineD3DDeviceImpl_ProcessVertices,
6345 /*** State block ***/
6346 IWineD3DDeviceImpl_BeginStateBlock,
6347 IWineD3DDeviceImpl_EndStateBlock,
6348 /*** Scene management ***/
6349 IWineD3DDeviceImpl_BeginScene,
6350 IWineD3DDeviceImpl_EndScene,
6351 IWineD3DDeviceImpl_Present,
6352 IWineD3DDeviceImpl_Clear,
6353 /*** Drawing ***/
6354 IWineD3DDeviceImpl_DrawPrimitive,
6355 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6356 IWineD3DDeviceImpl_DrawPrimitiveUP,
6357 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6358 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6359 IWineD3DDeviceImpl_DrawRectPatch,
6360 IWineD3DDeviceImpl_DrawTriPatch,
6361 IWineD3DDeviceImpl_DeletePatch,
6362 IWineD3DDeviceImpl_ColorFill,
6363 IWineD3DDeviceImpl_UpdateTexture,
6364 IWineD3DDeviceImpl_UpdateSurface,
6365 IWineD3DDeviceImpl_GetFrontBufferData,
6366 /*** object tracking ***/
6367 IWineD3DDeviceImpl_ResourceReleased
6371 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6372 WINED3DRS_ALPHABLENDENABLE ,
6373 WINED3DRS_ALPHAFUNC ,
6374 WINED3DRS_ALPHAREF ,
6375 WINED3DRS_ALPHATESTENABLE ,
6376 WINED3DRS_BLENDOP ,
6377 WINED3DRS_COLORWRITEENABLE ,
6378 WINED3DRS_DESTBLEND ,
6379 WINED3DRS_DITHERENABLE ,
6380 WINED3DRS_FILLMODE ,
6381 WINED3DRS_FOGDENSITY ,
6382 WINED3DRS_FOGEND ,
6383 WINED3DRS_FOGSTART ,
6384 WINED3DRS_LASTPIXEL ,
6385 WINED3DRS_SHADEMODE ,
6386 WINED3DRS_SRCBLEND ,
6387 WINED3DRS_STENCILENABLE ,
6388 WINED3DRS_STENCILFAIL ,
6389 WINED3DRS_STENCILFUNC ,
6390 WINED3DRS_STENCILMASK ,
6391 WINED3DRS_STENCILPASS ,
6392 WINED3DRS_STENCILREF ,
6393 WINED3DRS_STENCILWRITEMASK ,
6394 WINED3DRS_STENCILZFAIL ,
6395 WINED3DRS_TEXTUREFACTOR ,
6396 WINED3DRS_WRAP0 ,
6397 WINED3DRS_WRAP1 ,
6398 WINED3DRS_WRAP2 ,
6399 WINED3DRS_WRAP3 ,
6400 WINED3DRS_WRAP4 ,
6401 WINED3DRS_WRAP5 ,
6402 WINED3DRS_WRAP6 ,
6403 WINED3DRS_WRAP7 ,
6404 WINED3DRS_ZENABLE ,
6405 WINED3DRS_ZFUNC ,
6406 WINED3DRS_ZWRITEENABLE
6409 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6410 WINED3DTSS_ADDRESSW ,
6411 WINED3DTSS_ALPHAARG0 ,
6412 WINED3DTSS_ALPHAARG1 ,
6413 WINED3DTSS_ALPHAARG2 ,
6414 WINED3DTSS_ALPHAOP ,
6415 WINED3DTSS_BUMPENVLOFFSET ,
6416 WINED3DTSS_BUMPENVLSCALE ,
6417 WINED3DTSS_BUMPENVMAT00 ,
6418 WINED3DTSS_BUMPENVMAT01 ,
6419 WINED3DTSS_BUMPENVMAT10 ,
6420 WINED3DTSS_BUMPENVMAT11 ,
6421 WINED3DTSS_COLORARG0 ,
6422 WINED3DTSS_COLORARG1 ,
6423 WINED3DTSS_COLORARG2 ,
6424 WINED3DTSS_COLOROP ,
6425 WINED3DTSS_RESULTARG ,
6426 WINED3DTSS_TEXCOORDINDEX ,
6427 WINED3DTSS_TEXTURETRANSFORMFLAGS
6430 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6431 WINED3DSAMP_ADDRESSU ,
6432 WINED3DSAMP_ADDRESSV ,
6433 WINED3DSAMP_ADDRESSW ,
6434 WINED3DSAMP_BORDERCOLOR ,
6435 WINED3DSAMP_MAGFILTER ,
6436 WINED3DSAMP_MINFILTER ,
6437 WINED3DSAMP_MIPFILTER ,
6438 WINED3DSAMP_MIPMAPLODBIAS ,
6439 WINED3DSAMP_MAXMIPLEVEL ,
6440 WINED3DSAMP_MAXANISOTROPY ,
6441 WINED3DSAMP_SRGBTEXTURE ,
6442 WINED3DSAMP_ELEMENTINDEX
6445 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6446 WINED3DRS_AMBIENT ,
6447 WINED3DRS_AMBIENTMATERIALSOURCE ,
6448 WINED3DRS_CLIPPING ,
6449 WINED3DRS_CLIPPLANEENABLE ,
6450 WINED3DRS_COLORVERTEX ,
6451 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6452 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6453 WINED3DRS_FOGDENSITY ,
6454 WINED3DRS_FOGEND ,
6455 WINED3DRS_FOGSTART ,
6456 WINED3DRS_FOGTABLEMODE ,
6457 WINED3DRS_FOGVERTEXMODE ,
6458 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6459 WINED3DRS_LIGHTING ,
6460 WINED3DRS_LOCALVIEWER ,
6461 WINED3DRS_MULTISAMPLEANTIALIAS ,
6462 WINED3DRS_MULTISAMPLEMASK ,
6463 WINED3DRS_NORMALIZENORMALS ,
6464 WINED3DRS_PATCHEDGESTYLE ,
6465 WINED3DRS_POINTSCALE_A ,
6466 WINED3DRS_POINTSCALE_B ,
6467 WINED3DRS_POINTSCALE_C ,
6468 WINED3DRS_POINTSCALEENABLE ,
6469 WINED3DRS_POINTSIZE ,
6470 WINED3DRS_POINTSIZE_MAX ,
6471 WINED3DRS_POINTSIZE_MIN ,
6472 WINED3DRS_POINTSPRITEENABLE ,
6473 WINED3DRS_RANGEFOGENABLE ,
6474 WINED3DRS_SPECULARMATERIALSOURCE ,
6475 WINED3DRS_TWEENFACTOR ,
6476 WINED3DRS_VERTEXBLEND
6479 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6480 WINED3DTSS_TEXCOORDINDEX ,
6481 WINED3DTSS_TEXTURETRANSFORMFLAGS
6484 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6485 WINED3DSAMP_DMAPOFFSET
6488 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6489 DWORD rep = StateTable[state].representative;
6490 DWORD idx;
6491 BYTE shift;
6492 UINT i;
6493 WineD3DContext *context;
6495 if(!rep) return;
6496 for(i = 0; i < This->numContexts; i++) {
6497 context = This->contexts[i];
6498 if(isStateDirty(context, rep)) continue;
6500 context->dirtyArray[context->numDirtyEntries++] = rep;
6501 idx = rep >> 5;
6502 shift = rep & 0x1f;
6503 context->isStateDirty[idx] |= (1 << shift);