wined3d: Remove stateblock::set.*.
[wine.git] / dlls / wined3d / device.c
blobfcb167076cda13c57283d55527ded9f74350e2c3
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 } else if (Type == WINED3DSBT_PIXELSTATE) {
471 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
472 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
474 object->changed.pixelShader = TRUE;
476 /* Pixel Shader Constants */
477 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
478 object->changed.pixelShaderConstantsF[i] = TRUE;
479 for (i = 0; i < MAX_CONST_B; ++i)
480 object->changed.pixelShaderConstantsB[i] = TRUE;
481 for (i = 0; i < MAX_CONST_I; ++i)
482 object->changed.pixelShaderConstantsI[i] = TRUE;
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
485 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
487 for (j = 0; j < MAX_TEXTURES; j++) {
488 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
489 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
492 for (j = 0 ; j < 16; j++) {
493 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
495 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
499 } else if (Type == WINED3DSBT_VERTEXSTATE) {
501 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
502 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
504 object->changed.vertexShader = TRUE;
506 /* Vertex Shader Constants */
507 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
508 object->changed.vertexShaderConstantsF[i] = TRUE;
509 for (i = 0; i < MAX_CONST_B; ++i)
510 object->changed.vertexShaderConstantsB[i] = TRUE;
511 for (i = 0; i < MAX_CONST_I; ++i)
512 object->changed.vertexShaderConstantsI[i] = TRUE;
514 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
515 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
517 for (j = 0; j < MAX_TEXTURES; j++) {
518 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
519 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
522 for (j = 0 ; j < 16; j++){
523 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
524 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
528 for(j = 0; j < LIGHTMAP_SIZE; j++) {
529 struct list *e;
530 LIST_FOR_EACH(e, &object->lightMap[j]) {
531 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
532 light->changed = TRUE;
533 light->enabledChanged = TRUE;
536 } else {
537 FIXME("Unrecognized state block type %d\n", Type);
540 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
541 return WINED3D_OK;
544 /* ************************************
545 MSDN:
546 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
548 Discard
549 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
551 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.
553 ******************************** */
555 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) {
556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
557 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
558 unsigned int Size = 1;
559 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
560 TRACE("(%p) Create surface\n",This);
562 /** FIXME: Check ranges on the inputs are valid
563 * MSDN
564 * MultisampleQuality
565 * [in] Quality level. The valid range is between zero and one less than the level
566 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
567 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
568 * values of paired render targets, depth stencil surfaces, and the MultiSample type
569 * must all match.
570 *******************************/
574 * TODO: Discard MSDN
575 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
577 * If this flag is set, the contents of the depth stencil buffer will be
578 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
579 * with a different depth surface.
581 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
582 ***************************/
584 if(MultisampleQuality < 0) {
585 FIXME("Invalid multisample level %d\n", MultisampleQuality);
586 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
589 if(MultisampleQuality > 0) {
590 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
591 MultisampleQuality=0;
594 /** FIXME: Check that the format is supported
595 * by the device.
596 *******************************/
598 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
599 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
600 * space!
601 *********************************/
602 if (WINED3DFMT_UNKNOWN == Format) {
603 Size = 0;
604 } else if (Format == WINED3DFMT_DXT1) {
605 /* DXT1 is half byte per pixel */
606 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
608 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
609 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
610 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
611 } else {
612 /* The pitch is a multiple of 4 bytes */
613 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
614 Size *= Height;
617 /** Create and initialise the surface resource **/
618 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
619 /* "Standalone" surface */
620 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
622 object->currentDesc.Width = Width;
623 object->currentDesc.Height = Height;
624 object->currentDesc.MultiSampleType = MultiSample;
625 object->currentDesc.MultiSampleQuality = MultisampleQuality;
626 object->glDescription.level = Level;
628 /* Flags */
629 object->Flags = 0;
630 object->Flags |= Discard ? SFLAG_DISCARD : 0;
631 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
632 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
635 if (WINED3DFMT_UNKNOWN != Format) {
636 object->bytesPerPixel = tableEntry->bpp;
637 } else {
638 object->bytesPerPixel = 0;
641 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
643 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
645 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
646 * this function is too deep to need to care about things like this.
647 * Levels need to be checked too, and possibly Type since they all affect what can be done.
648 * ****************************************/
649 switch(Pool) {
650 case WINED3DPOOL_SCRATCH:
651 if(!Lockable)
652 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
653 "which are mutually exclusive, setting lockable to TRUE\n");
654 Lockable = TRUE;
655 break;
656 case WINED3DPOOL_SYSTEMMEM:
657 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
658 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
659 case WINED3DPOOL_MANAGED:
660 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
661 "Usage of DYNAMIC which are mutually exclusive, not doing "
662 "anything just telling you.\n");
663 break;
664 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
665 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
666 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
667 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
668 break;
669 default:
670 FIXME("(%p) Unknown pool %d\n", This, Pool);
671 break;
674 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
675 FIXME("Trying to create a render target that isn't in the default pool\n");
678 /* mark the texture as dirty so that it gets loaded first time around*/
679 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
680 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
681 This, Width, Height, Format, debug_d3dformat(Format),
682 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
684 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
685 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
686 This->ddraw_primary = (IWineD3DSurface *) object;
688 /* Look at the implementation and set the correct Vtable */
689 switch(Impl) {
690 case SURFACE_OPENGL:
691 /* Check if a 3D adapter is available when creating gl surfaces */
692 if(!This->adapter) {
693 ERR("OpenGL surfaces are not available without opengl\n");
694 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
695 HeapFree(GetProcessHeap(), 0, object);
696 return WINED3DERR_NOTAVAILABLE;
698 break;
700 case SURFACE_GDI:
701 object->lpVtbl = &IWineGDISurface_Vtbl;
702 break;
704 default:
705 /* To be sure to catch this */
706 ERR("Unknown requested surface implementation %d!\n", Impl);
707 IWineD3DSurface_Release((IWineD3DSurface *) object);
708 return WINED3DERR_INVALIDCALL;
711 list_init(&object->renderbuffers);
713 /* Call the private setup routine */
714 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
718 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
719 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
720 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
721 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
724 IWineD3DTextureImpl *object;
725 unsigned int i;
726 UINT tmpW;
727 UINT tmpH;
728 HRESULT hr;
729 unsigned int pow2Width;
730 unsigned int pow2Height;
733 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
734 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
735 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
737 /* TODO: It should only be possible to create textures for formats
738 that are reported as supported */
739 if (WINED3DFMT_UNKNOWN >= Format) {
740 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
741 return WINED3DERR_INVALIDCALL;
744 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
745 D3DINITIALIZEBASETEXTURE(object->baseTexture);
746 object->width = Width;
747 object->height = Height;
749 /** Non-power2 support **/
750 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
751 pow2Width = Width;
752 pow2Height = Height;
753 } else {
754 /* Find the nearest pow2 match */
755 pow2Width = pow2Height = 1;
756 while (pow2Width < Width) pow2Width <<= 1;
757 while (pow2Height < Height) pow2Height <<= 1;
760 /** FIXME: add support for real non-power-two if it's provided by the video card **/
761 /* Precalculated scaling for 'faked' non power of two texture coords */
762 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
763 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
764 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
766 /* Calculate levels for mip mapping */
767 if (Levels == 0) {
768 TRACE("calculating levels %d\n", object->baseTexture.levels);
769 object->baseTexture.levels++;
770 tmpW = Width;
771 tmpH = Height;
772 while (tmpW > 1 || tmpH > 1) {
773 tmpW = max(1, tmpW >> 1);
774 tmpH = max(1, tmpH >> 1);
775 object->baseTexture.levels++;
777 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
780 /* Generate all the surfaces */
781 tmpW = Width;
782 tmpH = Height;
783 for (i = 0; i < object->baseTexture.levels; i++)
785 /* use the callback to create the texture surface */
786 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
787 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
788 FIXME("Failed to create surface %p\n", object);
789 /* clean up */
790 object->surfaces[i] = NULL;
791 IWineD3DTexture_Release((IWineD3DTexture *)object);
793 *ppTexture = NULL;
794 return hr;
797 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
798 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
799 /* calculate the next mipmap level */
800 tmpW = max(1, tmpW >> 1);
801 tmpH = max(1, tmpH >> 1);
804 TRACE("(%p) : Created texture %p\n", This, object);
805 return WINED3D_OK;
808 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
809 UINT Width, UINT Height, UINT Depth,
810 UINT Levels, DWORD Usage,
811 WINED3DFORMAT Format, WINED3DPOOL Pool,
812 IWineD3DVolumeTexture **ppVolumeTexture,
813 HANDLE *pSharedHandle, IUnknown *parent,
814 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
817 IWineD3DVolumeTextureImpl *object;
818 unsigned int i;
819 UINT tmpW;
820 UINT tmpH;
821 UINT tmpD;
823 /* TODO: It should only be possible to create textures for formats
824 that are reported as supported */
825 if (WINED3DFMT_UNKNOWN >= Format) {
826 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
827 return WINED3DERR_INVALIDCALL;
830 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
831 D3DINITIALIZEBASETEXTURE(object->baseTexture);
833 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
834 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
836 object->width = Width;
837 object->height = Height;
838 object->depth = Depth;
840 /* Calculate levels for mip mapping */
841 if (Levels == 0) {
842 object->baseTexture.levels++;
843 tmpW = Width;
844 tmpH = Height;
845 tmpD = Depth;
846 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
847 tmpW = max(1, tmpW >> 1);
848 tmpH = max(1, tmpH >> 1);
849 tmpD = max(1, tmpD >> 1);
850 object->baseTexture.levels++;
852 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
855 /* Generate all the surfaces */
856 tmpW = Width;
857 tmpH = Height;
858 tmpD = Depth;
860 for (i = 0; i < object->baseTexture.levels; i++)
862 HRESULT hr;
863 /* Create the volume */
864 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
865 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
867 if(FAILED(hr)) {
868 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
869 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
870 *ppVolumeTexture = NULL;
871 return hr;
874 /* Set its container to this object */
875 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
877 /* calcualte the next mipmap level */
878 tmpW = max(1, tmpW >> 1);
879 tmpH = max(1, tmpH >> 1);
880 tmpD = max(1, tmpD >> 1);
883 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
884 TRACE("(%p) : Created volume texture %p\n", This, object);
885 return WINED3D_OK;
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Depth,
890 DWORD Usage,
891 WINED3DFORMAT Format, WINED3DPOOL Pool,
892 IWineD3DVolume** ppVolume,
893 HANDLE* pSharedHandle, IUnknown *parent) {
895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
896 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
897 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
899 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
901 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
902 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
904 object->currentDesc.Width = Width;
905 object->currentDesc.Height = Height;
906 object->currentDesc.Depth = Depth;
907 object->bytesPerPixel = formatDesc->bpp;
909 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
910 object->lockable = TRUE;
911 object->locked = FALSE;
912 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
913 object->dirty = TRUE;
915 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
918 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
919 UINT Levels, DWORD Usage,
920 WINED3DFORMAT Format, WINED3DPOOL Pool,
921 IWineD3DCubeTexture **ppCubeTexture,
922 HANDLE *pSharedHandle, IUnknown *parent,
923 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
926 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
927 unsigned int i, j;
928 UINT tmpW;
929 HRESULT hr;
930 unsigned int pow2EdgeLength = EdgeLength;
932 /* TODO: It should only be possible to create textures for formats
933 that are reported as supported */
934 if (WINED3DFMT_UNKNOWN >= Format) {
935 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
936 return WINED3DERR_INVALIDCALL;
939 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
940 WARN("(%p) : Tried to create not supported cube texture\n", This);
941 return WINED3DERR_INVALIDCALL;
944 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
945 D3DINITIALIZEBASETEXTURE(object->baseTexture);
947 TRACE("(%p) Create Cube Texture\n", This);
949 /** Non-power2 support **/
951 /* Find the nearest pow2 match */
952 pow2EdgeLength = 1;
953 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
955 object->edgeLength = EdgeLength;
956 /* TODO: support for native non-power 2 */
957 /* Precalculated scaling for 'faked' non power of two texture coords */
958 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
960 /* Calculate levels for mip mapping */
961 if (Levels == 0) {
962 object->baseTexture.levels++;
963 tmpW = EdgeLength;
964 while (tmpW > 1) {
965 tmpW = max(1, tmpW >> 1);
966 object->baseTexture.levels++;
968 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
971 /* Generate all the surfaces */
972 tmpW = EdgeLength;
973 for (i = 0; i < object->baseTexture.levels; i++) {
975 /* Create the 6 faces */
976 for (j = 0; j < 6; j++) {
978 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
979 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
981 if(hr!= WINED3D_OK) {
982 /* clean up */
983 int k;
984 int l;
985 for (l = 0; l < j; l++) {
986 IWineD3DSurface_Release(object->surfaces[j][i]);
988 for (k = 0; k < i; k++) {
989 for (l = 0; l < 6; l++) {
990 IWineD3DSurface_Release(object->surfaces[l][j]);
994 FIXME("(%p) Failed to create surface\n",object);
995 HeapFree(GetProcessHeap(),0,object);
996 *ppCubeTexture = NULL;
997 return hr;
999 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1000 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1002 tmpW = max(1, tmpW >> 1);
1005 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1006 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1007 return WINED3D_OK;
1010 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1012 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1013 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1015 /* Just a check to see if we support this type of query */
1016 switch(Type) {
1017 case WINED3DQUERYTYPE_OCCLUSION:
1018 TRACE("(%p) occlusion query\n", This);
1019 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1020 hr = WINED3D_OK;
1021 else
1022 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1023 break;
1025 case WINED3DQUERYTYPE_EVENT:
1026 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1027 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1028 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1030 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1032 hr = WINED3D_OK;
1033 break;
1035 case WINED3DQUERYTYPE_VCACHE:
1036 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1037 case WINED3DQUERYTYPE_VERTEXSTATS:
1038 case WINED3DQUERYTYPE_TIMESTAMP:
1039 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1040 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1041 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1042 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1043 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1044 case WINED3DQUERYTYPE_PIXELTIMINGS:
1045 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1046 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1047 default:
1048 FIXME("(%p) Unhandled query type %d\n", This, Type);
1050 if(NULL == ppQuery || hr != WINED3D_OK) {
1051 return hr;
1054 D3DCREATEOBJECTINSTANCE(object, Query)
1055 object->type = Type;
1056 /* allocated the 'extended' data based on the type of query requested */
1057 switch(Type){
1058 case WINED3DQUERYTYPE_OCCLUSION:
1059 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1060 TRACE("(%p) Allocating data for an occlusion query\n", This);
1061 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1062 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1063 break;
1065 case WINED3DQUERYTYPE_EVENT:
1066 /* TODO: GL_APPLE_fence */
1067 if(GL_SUPPORT(APPLE_FENCE)) {
1068 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1069 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1070 checkGLcall("glGenFencesAPPLE");
1071 } else if(GL_SUPPORT(NV_FENCE)) {
1072 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1073 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1074 checkGLcall("glGenFencesNV");
1076 break;
1078 case WINED3DQUERYTYPE_VCACHE:
1079 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1080 case WINED3DQUERYTYPE_VERTEXSTATS:
1081 case WINED3DQUERYTYPE_TIMESTAMP:
1082 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1083 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1084 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1085 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1086 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1087 case WINED3DQUERYTYPE_PIXELTIMINGS:
1088 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1089 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1090 default:
1091 object->extendedData = 0;
1092 FIXME("(%p) Unhandled query type %d\n",This , Type);
1094 TRACE("(%p) : Created Query %p\n", This, object);
1095 return WINED3D_OK;
1098 /*****************************************************************************
1099 * IWineD3DDeviceImpl_SetupFullscreenWindow
1101 * Helper function that modifies a HWND's Style and ExStyle for proper
1102 * fullscreen use.
1104 * Params:
1105 * iface: Pointer to the IWineD3DDevice interface
1106 * window: Window to setup
1108 *****************************************************************************/
1109 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1112 LONG style, exStyle;
1113 /* Don't do anything if an original style is stored.
1114 * That shouldn't happen
1116 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1117 if (This->style || This->exStyle) {
1118 ERR("(%p): Want to change the window parameters of HWND %p, but "
1119 "another style is stored for restoration afterwards\n", This, window);
1122 /* Get the parameters and save them */
1123 style = GetWindowLongW(window, GWL_STYLE);
1124 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1125 This->style = style;
1126 This->exStyle = exStyle;
1128 /* Filter out window decorations */
1129 style &= ~WS_CAPTION;
1130 style &= ~WS_THICKFRAME;
1131 exStyle &= ~WS_EX_WINDOWEDGE;
1132 exStyle &= ~WS_EX_CLIENTEDGE;
1134 /* Make sure the window is managed, otherwise we won't get keyboard input */
1135 style |= WS_POPUP | WS_SYSMENU;
1137 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1138 This->style, This->exStyle, style, exStyle);
1140 SetWindowLongW(window, GWL_STYLE, style);
1141 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1143 /* Inform the window about the update. */
1144 SetWindowPos(window, HWND_TOP, 0, 0,
1145 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1146 ShowWindow(window, SW_NORMAL);
1149 /*****************************************************************************
1150 * IWineD3DDeviceImpl_RestoreWindow
1152 * Helper function that restores a windows' properties when taking it out
1153 * of fullscreen mode
1155 * Params:
1156 * iface: Pointer to the IWineD3DDevice interface
1157 * window: Window to setup
1159 *****************************************************************************/
1160 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1163 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1164 * switch, do nothing
1166 if (!This->style && !This->exStyle) return;
1168 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1169 This, window, This->style, This->exStyle);
1171 SetWindowLongW(window, GWL_STYLE, This->style);
1172 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1174 /* Delete the old values */
1175 This->style = 0;
1176 This->exStyle = 0;
1178 /* Inform the window about the update */
1179 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1180 0, 0, 0, 0, /* Pos, Size, ignored */
1181 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1184 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1185 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1186 IUnknown* parent,
1187 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1188 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1191 HDC hDc;
1192 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1193 HRESULT hr = WINED3D_OK;
1194 IUnknown *bufferParent;
1196 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1198 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1199 * does a device hold a reference to a swap chain giving them a lifetime of the device
1200 * or does the swap chain notify the device of its destruction.
1201 *******************************/
1203 /* Check the params */
1204 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1205 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1206 return WINED3DERR_INVALIDCALL;
1207 } else if (pPresentationParameters->BackBufferCount > 1) {
1208 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");
1211 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1213 /*********************
1214 * Lookup the window Handle and the relating X window handle
1215 ********************/
1217 /* Setup hwnd we are using, plus which display this equates to */
1218 object->win_handle = pPresentationParameters->hDeviceWindow;
1219 if (!object->win_handle) {
1220 object->win_handle = This->createParms.hFocusWindow;
1223 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1224 hDc = GetDC(object->win_handle);
1225 TRACE("Using hDc %p\n", hDc);
1227 if (NULL == hDc) {
1228 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1229 return WINED3DERR_NOTAVAILABLE;
1232 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1233 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1234 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1235 ReleaseDC(object->win_handle, hDc);
1237 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1238 * then the corresponding dimension of the client area of the hDeviceWindow
1239 * (or the focus window, if hDeviceWindow is NULL) is taken.
1240 **********************/
1242 if (pPresentationParameters->Windowed &&
1243 ((pPresentationParameters->BackBufferWidth == 0) ||
1244 (pPresentationParameters->BackBufferHeight == 0))) {
1246 RECT Rect;
1247 GetClientRect(object->win_handle, &Rect);
1249 if (pPresentationParameters->BackBufferWidth == 0) {
1250 pPresentationParameters->BackBufferWidth = Rect.right;
1251 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1253 if (pPresentationParameters->BackBufferHeight == 0) {
1254 pPresentationParameters->BackBufferHeight = Rect.bottom;
1255 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1259 /* Put the correct figures in the presentation parameters */
1260 TRACE("Copying across presentation parameters\n");
1261 object->presentParms = *pPresentationParameters;
1263 TRACE("calling rendertarget CB\n");
1264 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1265 parent,
1266 object->presentParms.BackBufferWidth,
1267 object->presentParms.BackBufferHeight,
1268 object->presentParms.BackBufferFormat,
1269 object->presentParms.MultiSampleType,
1270 object->presentParms.MultiSampleQuality,
1271 TRUE /* Lockable */,
1272 &object->frontBuffer,
1273 NULL /* pShared (always null)*/);
1274 if (object->frontBuffer != NULL) {
1275 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1276 } else {
1277 ERR("Failed to create the front buffer\n");
1278 goto error;
1282 * Create an opengl context for the display visual
1283 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1284 * use different properties after that point in time. FIXME: How to handle when requested format
1285 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1286 * it chooses is identical to the one already being used!
1287 **********************************/
1288 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1290 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1291 if(!object->context)
1292 return E_OUTOFMEMORY;
1293 object->num_contexts = 1;
1295 ENTER_GL();
1296 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */);
1297 LEAVE_GL();
1299 if (!object->context[0]) {
1300 ERR("Failed to create a new context\n");
1301 hr = WINED3DERR_NOTAVAILABLE;
1302 goto error;
1303 } else {
1304 TRACE("Context created (HWND=%p, glContext=%p)\n",
1305 object->win_handle, object->context[0]->glCtx);
1308 /*********************
1309 * Windowed / Fullscreen
1310 *******************/
1313 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1314 * so we should really check to see if there is a fullscreen swapchain already
1315 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1316 **************************************/
1318 if (!pPresentationParameters->Windowed) {
1320 DEVMODEW devmode;
1321 HDC hdc;
1322 int bpp = 0;
1323 RECT clip_rc;
1325 /* Get info on the current display setup */
1326 hdc = GetDC(0);
1327 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1328 ReleaseDC(0, hdc);
1330 /* Change the display settings */
1331 memset(&devmode, 0, sizeof(devmode));
1332 devmode.dmSize = sizeof(devmode);
1333 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1334 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1335 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1336 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1337 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1338 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1340 /* For GetDisplayMode */
1341 This->ddraw_width = devmode.dmPelsWidth;
1342 This->ddraw_height = devmode.dmPelsHeight;
1343 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1345 IWineD3DDevice_SetFullscreen(iface, TRUE);
1347 /* And finally clip mouse to our screen */
1348 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1349 ClipCursor(&clip_rc);
1352 /*********************
1353 * Create the back, front and stencil buffers
1354 *******************/
1355 if(object->presentParms.BackBufferCount > 0) {
1356 int i;
1358 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1359 if(!object->backBuffer) {
1360 ERR("Out of memory\n");
1361 hr = E_OUTOFMEMORY;
1362 goto error;
1365 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1366 TRACE("calling rendertarget CB\n");
1367 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1368 parent,
1369 object->presentParms.BackBufferWidth,
1370 object->presentParms.BackBufferHeight,
1371 object->presentParms.BackBufferFormat,
1372 object->presentParms.MultiSampleType,
1373 object->presentParms.MultiSampleQuality,
1374 TRUE /* Lockable */,
1375 &object->backBuffer[i],
1376 NULL /* pShared (always null)*/);
1377 if(hr == WINED3D_OK && object->backBuffer[i]) {
1378 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1379 } else {
1380 ERR("Cannot create new back buffer\n");
1381 goto error;
1383 ENTER_GL();
1384 glDrawBuffer(GL_BACK);
1385 checkGLcall("glDrawBuffer(GL_BACK)");
1386 LEAVE_GL();
1388 } else {
1389 object->backBuffer = NULL;
1391 /* Single buffering - draw to front buffer */
1392 ENTER_GL();
1393 glDrawBuffer(GL_FRONT);
1394 checkGLcall("glDrawBuffer(GL_FRONT)");
1395 LEAVE_GL();
1398 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1399 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1400 TRACE("Creating depth stencil buffer\n");
1401 if (This->depthStencilBuffer == NULL ) {
1402 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1403 parent,
1404 object->presentParms.BackBufferWidth,
1405 object->presentParms.BackBufferHeight,
1406 object->presentParms.AutoDepthStencilFormat,
1407 object->presentParms.MultiSampleType,
1408 object->presentParms.MultiSampleQuality,
1409 FALSE /* FIXME: Discard */,
1410 &This->depthStencilBuffer,
1411 NULL /* pShared (always null)*/ );
1412 if (This->depthStencilBuffer != NULL)
1413 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1416 /** TODO: A check on width, height and multisample types
1417 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1418 ****************************/
1419 object->wantsDepthStencilBuffer = TRUE;
1420 } else {
1421 object->wantsDepthStencilBuffer = FALSE;
1424 TRACE("Created swapchain %p\n", object);
1425 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1426 return WINED3D_OK;
1428 error:
1429 if (object->backBuffer) {
1430 int i;
1431 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1432 if(object->backBuffer[i]) {
1433 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1434 IUnknown_Release(bufferParent); /* once for the get parent */
1435 if (IUnknown_Release(bufferParent) > 0) {
1436 FIXME("(%p) Something's still holding the back buffer\n",This);
1440 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1441 object->backBuffer = NULL;
1443 if(object->context[0])
1444 DestroyContext(This, object->context[0]);
1445 if(object->frontBuffer) {
1446 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1447 IUnknown_Release(bufferParent); /* once for the get parent */
1448 if (IUnknown_Release(bufferParent) > 0) {
1449 FIXME("(%p) Something's still holding the front buffer\n",This);
1452 HeapFree(GetProcessHeap(), 0, object);
1453 return hr;
1456 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1457 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1459 TRACE("(%p)\n", This);
1461 return This->NumberOfSwapChains;
1464 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1466 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1468 if(iSwapChain < This->NumberOfSwapChains) {
1469 *pSwapChain = This->swapchains[iSwapChain];
1470 IWineD3DSwapChain_AddRef(*pSwapChain);
1471 TRACE("(%p) returning %p\n", This, *pSwapChain);
1472 return WINED3D_OK;
1473 } else {
1474 TRACE("Swapchain out of range\n");
1475 *pSwapChain = NULL;
1476 return WINED3DERR_INVALIDCALL;
1480 /*****
1481 * Vertex Declaration
1482 *****/
1483 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1484 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1486 IWineD3DVertexDeclarationImpl *object = NULL;
1487 HRESULT hr = WINED3D_OK;
1489 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1490 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1492 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1494 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1496 return hr;
1499 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1501 unsigned int idx, idx2;
1502 unsigned int offset;
1503 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1504 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1505 BOOL has_blend_idx = has_blend &&
1506 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1507 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1508 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1509 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1510 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1511 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1512 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1514 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1515 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1517 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1518 WINED3DVERTEXELEMENT *elements = NULL;
1520 unsigned int size;
1521 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1522 if (has_blend_idx) num_blends--;
1524 /* Compute declaration size */
1525 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1526 has_psize + has_diffuse + has_specular + num_textures + 1;
1528 /* convert the declaration */
1529 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1530 if (!elements)
1531 return 0;
1533 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1534 idx = 0;
1535 if (has_pos) {
1536 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1537 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1538 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1540 else {
1541 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1542 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1544 elements[idx].UsageIndex = 0;
1545 idx++;
1547 if (has_blend && (num_blends > 0)) {
1548 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1549 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1550 else
1551 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1552 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1553 elements[idx].UsageIndex = 0;
1554 idx++;
1556 if (has_blend_idx) {
1557 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1558 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1559 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1560 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1561 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1562 else
1563 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1564 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1565 elements[idx].UsageIndex = 0;
1566 idx++;
1568 if (has_normal) {
1569 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1570 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1571 elements[idx].UsageIndex = 0;
1572 idx++;
1574 if (has_psize) {
1575 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1576 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1577 elements[idx].UsageIndex = 0;
1578 idx++;
1580 if (has_diffuse) {
1581 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1582 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1583 elements[idx].UsageIndex = 0;
1584 idx++;
1586 if (has_specular) {
1587 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1588 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1589 elements[idx].UsageIndex = 1;
1590 idx++;
1592 for (idx2 = 0; idx2 < num_textures; idx2++) {
1593 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1594 switch (numcoords) {
1595 case WINED3DFVF_TEXTUREFORMAT1:
1596 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1597 break;
1598 case WINED3DFVF_TEXTUREFORMAT2:
1599 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1600 break;
1601 case WINED3DFVF_TEXTUREFORMAT3:
1602 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1603 break;
1604 case WINED3DFVF_TEXTUREFORMAT4:
1605 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1606 break;
1608 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1609 elements[idx].UsageIndex = idx2;
1610 idx++;
1613 /* Now compute offsets, and initialize the rest of the fields */
1614 for (idx = 0, offset = 0; idx < size-1; idx++) {
1615 elements[idx].Stream = 0;
1616 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1617 elements[idx].Offset = offset;
1618 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1621 *ppVertexElements = elements;
1622 return size;
1625 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1626 WINED3DVERTEXELEMENT* elements = NULL;
1627 size_t size;
1628 DWORD hr;
1630 size = ConvertFvfToDeclaration(Fvf, &elements);
1631 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1633 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1634 HeapFree(GetProcessHeap(), 0, elements);
1635 if (hr != S_OK) return hr;
1637 return WINED3D_OK;
1640 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1641 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1643 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1644 HRESULT hr = WINED3D_OK;
1645 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1646 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1648 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1650 if (vertex_declaration) {
1651 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1654 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1656 if (WINED3D_OK != hr) {
1657 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1658 IWineD3DVertexShader_Release(*ppVertexShader);
1659 return WINED3DERR_INVALIDCALL;
1662 return WINED3D_OK;
1665 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1667 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1668 HRESULT hr = WINED3D_OK;
1670 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1671 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1672 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1673 if (WINED3D_OK == hr) {
1674 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1675 } else {
1676 WARN("(%p) : Failed to create pixel shader\n", This);
1679 return hr;
1682 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1684 IWineD3DPaletteImpl *object;
1685 HRESULT hr;
1686 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1688 /* Create the new object */
1689 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1690 if(!object) {
1691 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1692 return E_OUTOFMEMORY;
1695 object->lpVtbl = &IWineD3DPalette_Vtbl;
1696 object->ref = 1;
1697 object->Flags = Flags;
1698 object->parent = Parent;
1699 object->wineD3DDevice = This;
1700 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1702 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1704 if(!object->hpal) {
1705 HeapFree( GetProcessHeap(), 0, object);
1706 return E_OUTOFMEMORY;
1709 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1710 if(FAILED(hr)) {
1711 IWineD3DPalette_Release((IWineD3DPalette *) object);
1712 return hr;
1715 *Palette = (IWineD3DPalette *) object;
1717 return WINED3D_OK;
1720 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1722 IWineD3DSwapChainImpl *swapchain;
1723 HRESULT hr;
1724 DWORD state;
1726 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1727 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1729 /* TODO: Test if OpenGL is compiled in and loaded */
1731 TRACE("(%p) : Creating stateblock\n", This);
1732 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1733 hr = IWineD3DDevice_CreateStateBlock(iface,
1734 WINED3DSBT_INIT,
1735 (IWineD3DStateBlock **)&This->stateBlock,
1736 NULL);
1737 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1738 WARN("Failed to create stateblock\n");
1739 return hr;
1741 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1742 This->updateStateBlock = This->stateBlock;
1743 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1745 hr = allocate_shader_constants(This->updateStateBlock);
1746 if (WINED3D_OK != hr)
1747 return hr;
1749 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1750 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1751 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1753 /* Initialize the texture unit mapping to a 1:1 mapping */
1754 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1755 if (state < GL_LIMITS(fragment_samplers)) {
1756 This->texUnitMap[state] = state;
1757 This->rev_tex_unit_map[state] = state;
1758 } else {
1759 This->texUnitMap[state] = -1;
1760 This->rev_tex_unit_map[state] = -1;
1764 /* Setup the implicit swapchain */
1765 TRACE("Creating implicit swapchain\n");
1766 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1767 if (FAILED(hr) || !swapchain) {
1768 WARN("Failed to create implicit swapchain\n");
1769 return hr;
1772 This->NumberOfSwapChains = 1;
1773 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1774 if(!This->swapchains) {
1775 ERR("Out of memory!\n");
1776 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1777 return E_OUTOFMEMORY;
1779 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1781 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1783 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1784 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1785 This->render_targets[0] = swapchain->backBuffer[0];
1786 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1788 else {
1789 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1790 This->render_targets[0] = swapchain->frontBuffer;
1791 This->lastActiveRenderTarget = swapchain->frontBuffer;
1793 IWineD3DSurface_AddRef(This->render_targets[0]);
1794 This->activeContext = swapchain->context[0];
1795 This->lastThread = GetCurrentThreadId();
1797 /* Depth Stencil support */
1798 This->stencilBufferTarget = This->depthStencilBuffer;
1799 if (NULL != This->stencilBufferTarget) {
1800 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1803 /* Set up some starting GL setup */
1804 ENTER_GL();
1806 /* Setup all the devices defaults */
1807 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1808 #if 0
1809 IWineD3DImpl_CheckGraphicsMemory();
1810 #endif
1812 { /* Set a default viewport */
1813 WINED3DVIEWPORT vp;
1814 vp.X = 0;
1815 vp.Y = 0;
1816 vp.Width = pPresentationParameters->BackBufferWidth;
1817 vp.Height = pPresentationParameters->BackBufferHeight;
1818 vp.MinZ = 0.0f;
1819 vp.MaxZ = 1.0f;
1820 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1823 /* Initialize the current view state */
1824 This->view_ident = 1;
1825 This->contexts[0]->last_was_rhw = 0;
1826 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1827 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1829 switch(wined3d_settings.offscreen_rendering_mode) {
1830 case ORM_FBO:
1831 case ORM_PBUFFER:
1832 This->offscreenBuffer = GL_BACK;
1833 break;
1835 case ORM_BACKBUFFER:
1837 if(GL_LIMITS(aux_buffers) > 0) {
1838 TRACE("Using auxilliary buffer for offscreen rendering\n");
1839 This->offscreenBuffer = GL_AUX0;
1840 } else {
1841 TRACE("Using back buffer for offscreen rendering\n");
1842 This->offscreenBuffer = GL_BACK;
1847 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1848 LEAVE_GL();
1850 /* Clear the screen */
1851 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1852 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1853 0x00, 1.0, 0);
1855 This->d3d_initialized = TRUE;
1856 return WINED3D_OK;
1859 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1861 int sampler;
1862 UINT i;
1863 TRACE("(%p)\n", This);
1865 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1867 /* I don't think that the interface guarants that the device is destroyed from the same thread
1868 * it was created. Thus make sure a context is active for the glDelete* calls
1870 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1872 TRACE("Deleting high order patches\n");
1873 for(i = 0; i < PATCHMAP_SIZE; i++) {
1874 struct list *e1, *e2;
1875 struct WineD3DRectPatch *patch;
1876 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1877 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1878 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1882 /* Delete the pbuffer context if there is any */
1883 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1885 /* Delete the mouse cursor texture */
1886 if(This->cursorTexture) {
1887 ENTER_GL();
1888 glDeleteTextures(1, &This->cursorTexture);
1889 LEAVE_GL();
1890 This->cursorTexture = 0;
1893 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1894 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1896 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1897 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1900 /* Release the buffers (with sanity checks)*/
1901 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1902 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1903 if(This->depthStencilBuffer != This->stencilBufferTarget)
1904 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1906 This->stencilBufferTarget = NULL;
1908 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1909 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1910 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1912 TRACE("Setting rendertarget to NULL\n");
1913 This->render_targets[0] = NULL;
1915 if (This->depthStencilBuffer) {
1916 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1917 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1919 This->depthStencilBuffer = NULL;
1922 for(i=0; i < This->NumberOfSwapChains; i++) {
1923 TRACE("Releasing the implicit swapchain %d\n", i);
1924 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1925 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1929 HeapFree(GetProcessHeap(), 0, This->swapchains);
1930 This->swapchains = NULL;
1931 This->NumberOfSwapChains = 0;
1933 /* Release the update stateblock */
1934 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1935 if(This->updateStateBlock != This->stateBlock)
1936 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1938 This->updateStateBlock = NULL;
1940 { /* because were not doing proper internal refcounts releasing the primary state block
1941 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1942 to set this->stateBlock = NULL; first */
1943 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1944 This->stateBlock = NULL;
1946 /* Release the stateblock */
1947 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1948 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1952 HeapFree(GetProcessHeap(), 0, This->render_targets);
1953 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
1954 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1955 This->render_targets = NULL;
1956 This->fbo_color_attachments = NULL;
1957 This->draw_buffers = NULL;
1960 This->d3d_initialized = FALSE;
1961 return WINED3D_OK;
1964 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1966 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1968 /* Setup the window for fullscreen mode */
1969 if(fullscreen && !This->ddraw_fullscreen) {
1970 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1971 } else if(!fullscreen && This->ddraw_fullscreen) {
1972 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1975 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1976 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1977 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1978 * separately.
1980 This->ddraw_fullscreen = fullscreen;
1983 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1984 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1985 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1987 * There is no way to deactivate thread safety once it is enabled
1989 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1992 /*For now just store the flag(needed in case of ddraw) */
1993 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1995 return;
1998 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1999 DEVMODEW devmode;
2000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2001 LONG ret;
2002 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2003 RECT clip_rc;
2005 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2007 /* Resize the screen even without a window:
2008 * The app could have unset it with SetCooperativeLevel, but not called
2009 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2010 * but we don't have any hwnd
2013 memset(&devmode, 0, sizeof(devmode));
2014 devmode.dmSize = sizeof(devmode);
2015 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2016 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2017 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2018 devmode.dmPelsWidth = pMode->Width;
2019 devmode.dmPelsHeight = pMode->Height;
2021 devmode.dmDisplayFrequency = pMode->RefreshRate;
2022 if (pMode->RefreshRate != 0) {
2023 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2026 /* Only change the mode if necessary */
2027 if( (This->ddraw_width == pMode->Width) &&
2028 (This->ddraw_height == pMode->Height) &&
2029 (This->ddraw_format == pMode->Format) &&
2030 (pMode->RefreshRate == 0) ) {
2031 return WINED3D_OK;
2034 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2035 if (ret != DISP_CHANGE_SUCCESSFUL) {
2036 if(devmode.dmDisplayFrequency != 0) {
2037 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2038 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2039 devmode.dmDisplayFrequency = 0;
2040 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2042 if(ret != DISP_CHANGE_SUCCESSFUL) {
2043 return WINED3DERR_NOTAVAILABLE;
2047 /* Store the new values */
2048 This->ddraw_width = pMode->Width;
2049 This->ddraw_height = pMode->Height;
2050 This->ddraw_format = pMode->Format;
2052 /* Only do this with a window of course */
2053 if(This->ddraw_window)
2054 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2056 /* And finally clip mouse to our screen */
2057 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2058 ClipCursor(&clip_rc);
2060 return WINED3D_OK;
2063 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2065 *ppD3D= This->wineD3D;
2066 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2067 IWineD3D_AddRef(*ppD3D);
2068 return WINED3D_OK;
2071 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2072 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2073 * into the video ram as possible and seeing how many fit
2074 * you can also get the correct initial value from nvidia and ATI's driver via X
2075 * texture memory is video memory + AGP memory
2076 *******************/
2077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2078 static BOOL showfixmes = TRUE;
2079 if (showfixmes) {
2080 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2081 (wined3d_settings.emulated_textureram/(1024*1024)),
2082 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2083 showfixmes = FALSE;
2085 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2086 (wined3d_settings.emulated_textureram/(1024*1024)),
2087 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2088 /* return simulated texture memory left */
2089 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2094 /*****
2095 * Get / Set FVF
2096 *****/
2097 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2100 /* Update the current state block */
2101 This->updateStateBlock->changed.fvf = TRUE;
2103 if(This->updateStateBlock->fvf == fvf) {
2104 TRACE("Application is setting the old fvf over, nothing to do\n");
2105 return WINED3D_OK;
2108 This->updateStateBlock->fvf = fvf;
2109 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2111 return WINED3D_OK;
2115 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2117 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2118 *pfvf = This->stateBlock->fvf;
2119 return WINED3D_OK;
2122 /*****
2123 * Get / Set Stream Source
2124 *****/
2125 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2127 IWineD3DVertexBuffer *oldSrc;
2129 if (StreamNumber >= MAX_STREAMS) {
2130 WARN("Stream out of range %d\n", StreamNumber);
2131 return WINED3DERR_INVALIDCALL;
2134 oldSrc = This->stateBlock->streamSource[StreamNumber];
2135 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2137 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2139 if(oldSrc == pStreamData &&
2140 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2141 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2142 TRACE("Application is setting the old values over, nothing to do\n");
2143 return WINED3D_OK;
2146 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2147 if (pStreamData) {
2148 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2149 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2152 /* Handle recording of state blocks */
2153 if (This->isRecordingState) {
2154 TRACE("Recording... not performing anything\n");
2155 return WINED3D_OK;
2158 /* Need to do a getParent and pass the reffs up */
2159 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2160 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2161 so for now, just count internally */
2162 if (pStreamData != NULL) {
2163 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2164 InterlockedIncrement(&vbImpl->bindCount);
2166 if (oldSrc != NULL) {
2167 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2172 return WINED3D_OK;
2175 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2178 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2179 This->stateBlock->streamSource[StreamNumber],
2180 This->stateBlock->streamOffset[StreamNumber],
2181 This->stateBlock->streamStride[StreamNumber]);
2183 if (StreamNumber >= MAX_STREAMS) {
2184 WARN("Stream out of range %d\n", StreamNumber);
2185 return WINED3DERR_INVALIDCALL;
2187 *pStream = This->stateBlock->streamSource[StreamNumber];
2188 *pStride = This->stateBlock->streamStride[StreamNumber];
2189 if (pOffset) {
2190 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2193 if (*pStream != NULL) {
2194 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2196 return WINED3D_OK;
2199 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2201 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2202 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2204 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2205 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2207 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2208 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2210 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2211 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2215 return WINED3D_OK;
2218 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2221 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2222 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2224 TRACE("(%p) : returning %d\n", This, *Divider);
2226 return WINED3D_OK;
2229 /*****
2230 * Get / Set & Multiply Transform
2231 *****/
2232 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2235 /* Most of this routine, comments included copied from ddraw tree initially: */
2236 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2238 /* Handle recording of state blocks */
2239 if (This->isRecordingState) {
2240 TRACE("Recording... not performing anything\n");
2241 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2242 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2243 return WINED3D_OK;
2247 * If the new matrix is the same as the current one,
2248 * we cut off any further processing. this seems to be a reasonable
2249 * optimization because as was noticed, some apps (warcraft3 for example)
2250 * tend towards setting the same matrix repeatedly for some reason.
2252 * From here on we assume that the new matrix is different, wherever it matters.
2254 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2255 TRACE("The app is setting the same matrix over again\n");
2256 return WINED3D_OK;
2257 } else {
2258 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2262 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2263 where ViewMat = Camera space, WorldMat = world space.
2265 In OpenGL, camera and world space is combined into GL_MODELVIEW
2266 matrix. The Projection matrix stay projection matrix.
2269 /* Capture the times we can just ignore the change for now */
2270 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2271 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2272 /* Handled by the state manager */
2275 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2276 return WINED3D_OK;
2279 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2281 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2282 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2283 return WINED3D_OK;
2286 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2287 WINED3DMATRIX *mat = NULL;
2288 WINED3DMATRIX temp;
2290 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2291 * below means it will be recorded in a state block change, but it
2292 * works regardless where it is recorded.
2293 * If this is found to be wrong, change to StateBlock.
2295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2296 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2298 if (State < HIGHEST_TRANSFORMSTATE)
2300 mat = &This->updateStateBlock->transforms[State];
2301 } else {
2302 FIXME("Unhandled transform state!!\n");
2305 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2307 /* Apply change via set transform - will reapply to eg. lights this way */
2308 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2311 /*****
2312 * Get / Set Light
2313 *****/
2314 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2315 you can reference any indexes you want as long as that number max are enabled at any
2316 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2317 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2318 but when recording, just build a chain pretty much of commands to be replayed. */
2320 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2321 float rho;
2322 PLIGHTINFOEL *object = NULL;
2323 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2324 struct list *e;
2326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2327 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2329 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2330 * the gl driver.
2332 if(!pLight) {
2333 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2334 return WINED3DERR_INVALIDCALL;
2337 switch(pLight->Type) {
2338 case WINED3DLIGHT_POINT:
2339 case WINED3DLIGHT_SPOT:
2340 case WINED3DLIGHT_PARALLELPOINT:
2341 case WINED3DLIGHT_GLSPOT:
2342 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2343 * most wanted
2345 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2346 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2347 return WINED3DERR_INVALIDCALL;
2349 break;
2351 case WINED3DLIGHT_DIRECTIONAL:
2352 /* Ignores attenuation */
2353 break;
2355 default:
2356 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2357 return WINED3DERR_INVALIDCALL;
2360 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2361 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2362 if(object->OriginalIndex == Index) break;
2363 object = NULL;
2366 if(!object) {
2367 TRACE("Adding new light\n");
2368 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2369 if(!object) {
2370 ERR("Out of memory error when allocating a light\n");
2371 return E_OUTOFMEMORY;
2373 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2374 object->glIndex = -1;
2375 object->OriginalIndex = Index;
2376 object->changed = TRUE;
2379 /* Initialize the object */
2380 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,
2381 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2382 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2383 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2384 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2385 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2386 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2388 /* Save away the information */
2389 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2391 switch (pLight->Type) {
2392 case WINED3DLIGHT_POINT:
2393 /* Position */
2394 object->lightPosn[0] = pLight->Position.x;
2395 object->lightPosn[1] = pLight->Position.y;
2396 object->lightPosn[2] = pLight->Position.z;
2397 object->lightPosn[3] = 1.0f;
2398 object->cutoff = 180.0f;
2399 /* FIXME: Range */
2400 break;
2402 case WINED3DLIGHT_DIRECTIONAL:
2403 /* Direction */
2404 object->lightPosn[0] = -pLight->Direction.x;
2405 object->lightPosn[1] = -pLight->Direction.y;
2406 object->lightPosn[2] = -pLight->Direction.z;
2407 object->lightPosn[3] = 0.0;
2408 object->exponent = 0.0f;
2409 object->cutoff = 180.0f;
2410 break;
2412 case WINED3DLIGHT_SPOT:
2413 /* Position */
2414 object->lightPosn[0] = pLight->Position.x;
2415 object->lightPosn[1] = pLight->Position.y;
2416 object->lightPosn[2] = pLight->Position.z;
2417 object->lightPosn[3] = 1.0;
2419 /* Direction */
2420 object->lightDirn[0] = pLight->Direction.x;
2421 object->lightDirn[1] = pLight->Direction.y;
2422 object->lightDirn[2] = pLight->Direction.z;
2423 object->lightDirn[3] = 1.0;
2426 * opengl-ish and d3d-ish spot lights use too different models for the
2427 * light "intensity" as a function of the angle towards the main light direction,
2428 * so we only can approximate very roughly.
2429 * however spot lights are rather rarely used in games (if ever used at all).
2430 * furthermore if still used, probably nobody pays attention to such details.
2432 if (pLight->Falloff == 0) {
2433 rho = 6.28f;
2434 } else {
2435 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2437 if (rho < 0.0001) rho = 0.0001f;
2438 object->exponent = -0.3/log(cos(rho/2));
2439 if (object->exponent > 128.0) {
2440 object->exponent = 128.0;
2442 object->cutoff = pLight->Phi*90/M_PI;
2444 /* FIXME: Range */
2445 break;
2447 default:
2448 FIXME("Unrecognized light type %d\n", pLight->Type);
2451 /* Update the live definitions if the light is currently assigned a glIndex */
2452 if (object->glIndex != -1 && !This->isRecordingState) {
2453 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2455 return WINED3D_OK;
2458 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2459 PLIGHTINFOEL *lightInfo = NULL;
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2462 struct list *e;
2463 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2465 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2466 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2467 if(lightInfo->OriginalIndex == Index) break;
2468 lightInfo = NULL;
2471 if (lightInfo == NULL) {
2472 TRACE("Light information requested but light not defined\n");
2473 return WINED3DERR_INVALIDCALL;
2476 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2477 return WINED3D_OK;
2480 /*****
2481 * Get / Set Light Enable
2482 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2483 *****/
2484 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2485 PLIGHTINFOEL *lightInfo = NULL;
2486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2488 struct list *e;
2489 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2491 /* Tests show true = 128...not clear why */
2492 Enable = Enable? 128: 0;
2494 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2495 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2496 if(lightInfo->OriginalIndex == Index) break;
2497 lightInfo = NULL;
2499 TRACE("Found light: %p\n", lightInfo);
2501 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2502 if (lightInfo == NULL) {
2504 TRACE("Light enabled requested but light not defined, so defining one!\n");
2505 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2507 /* Search for it again! Should be fairly quick as near head of list */
2508 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2509 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2510 if(lightInfo->OriginalIndex == Index) break;
2511 lightInfo = NULL;
2513 if (lightInfo == NULL) {
2514 FIXME("Adding default lights has failed dismally\n");
2515 return WINED3DERR_INVALIDCALL;
2519 lightInfo->enabledChanged = TRUE;
2520 if(!Enable) {
2521 if(lightInfo->glIndex != -1) {
2522 if(!This->isRecordingState) {
2523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2526 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2527 lightInfo->glIndex = -1;
2528 } else {
2529 TRACE("Light already disabled, nothing to do\n");
2531 } else {
2532 if (lightInfo->glIndex != -1) {
2533 /* nop */
2534 TRACE("Nothing to do as light was enabled\n");
2535 } else {
2536 int i;
2537 /* Find a free gl light */
2538 for(i = 0; i < This->maxConcurrentLights; i++) {
2539 if(This->stateBlock->activeLights[i] == NULL) {
2540 This->stateBlock->activeLights[i] = lightInfo;
2541 lightInfo->glIndex = i;
2542 break;
2545 if(lightInfo->glIndex == -1) {
2546 ERR("Too many concurrently active lights\n");
2547 return WINED3DERR_INVALIDCALL;
2550 /* i == lightInfo->glIndex */
2551 if(!This->isRecordingState) {
2552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2557 return WINED3D_OK;
2560 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2562 PLIGHTINFOEL *lightInfo = NULL;
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564 struct list *e;
2565 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2566 TRACE("(%p) : for idx(%d)\n", This, Index);
2568 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2569 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2570 if(lightInfo->OriginalIndex == Index) break;
2571 lightInfo = NULL;
2574 if (lightInfo == NULL) {
2575 TRACE("Light enabled state requested but light not defined\n");
2576 return WINED3DERR_INVALIDCALL;
2578 /* true is 128 according to SetLightEnable */
2579 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2580 return WINED3D_OK;
2583 /*****
2584 * Get / Set Clip Planes
2585 *****/
2586 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2590 /* Validate Index */
2591 if (Index >= GL_LIMITS(clipplanes)) {
2592 TRACE("Application has requested clipplane this device doesn't support\n");
2593 return WINED3DERR_INVALIDCALL;
2596 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2598 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2599 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2600 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2601 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2602 TRACE("Application is setting old values over, nothing to do\n");
2603 return WINED3D_OK;
2606 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2607 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2608 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2609 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2611 /* Handle recording of state blocks */
2612 if (This->isRecordingState) {
2613 TRACE("Recording... not performing anything\n");
2614 return WINED3D_OK;
2617 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2619 return WINED3D_OK;
2622 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2624 TRACE("(%p) : for idx %d\n", This, Index);
2626 /* Validate Index */
2627 if (Index >= GL_LIMITS(clipplanes)) {
2628 TRACE("Application has requested clipplane this device doesn't support\n");
2629 return WINED3DERR_INVALIDCALL;
2632 pPlane[0] = This->stateBlock->clipplane[Index][0];
2633 pPlane[1] = This->stateBlock->clipplane[Index][1];
2634 pPlane[2] = This->stateBlock->clipplane[Index][2];
2635 pPlane[3] = This->stateBlock->clipplane[Index][3];
2636 return WINED3D_OK;
2639 /*****
2640 * Get / Set Clip Plane Status
2641 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2642 *****/
2643 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 FIXME("(%p) : stub\n", This);
2646 if (NULL == pClipStatus) {
2647 return WINED3DERR_INVALIDCALL;
2649 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2650 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2651 return WINED3D_OK;
2654 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 FIXME("(%p) : stub\n", This);
2657 if (NULL == pClipStatus) {
2658 return WINED3DERR_INVALIDCALL;
2660 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2661 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2662 return WINED3D_OK;
2665 /*****
2666 * Get / Set Material
2667 *****/
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2671 This->updateStateBlock->changed.material = TRUE;
2672 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2674 /* Handle recording of state blocks */
2675 if (This->isRecordingState) {
2676 TRACE("Recording... not performing anything\n");
2677 return WINED3D_OK;
2680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2681 return WINED3D_OK;
2684 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2687 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2688 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2689 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2690 pMaterial->Ambient.b, pMaterial->Ambient.a);
2691 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2692 pMaterial->Specular.b, pMaterial->Specular.a);
2693 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2694 pMaterial->Emissive.b, pMaterial->Emissive.a);
2695 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2697 return WINED3D_OK;
2700 /*****
2701 * Get / Set Indices
2702 *****/
2703 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2705 IWineD3DIndexBuffer *oldIdxs;
2707 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2708 oldIdxs = This->updateStateBlock->pIndexData;
2710 This->updateStateBlock->changed.indices = TRUE;
2711 This->updateStateBlock->pIndexData = pIndexData;
2713 /* Handle recording of state blocks */
2714 if (This->isRecordingState) {
2715 TRACE("Recording... not performing anything\n");
2716 return WINED3D_OK;
2719 if(oldIdxs != pIndexData) {
2720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2722 return WINED3D_OK;
2725 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2728 *ppIndexData = This->stateBlock->pIndexData;
2730 /* up ref count on ppindexdata */
2731 if (*ppIndexData) {
2732 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2733 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2734 }else{
2735 TRACE("(%p) No index data set\n", This);
2737 TRACE("Returning %p\n", *ppIndexData);
2739 return WINED3D_OK;
2742 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2743 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2745 TRACE("(%p)->(%d)\n", This, BaseIndex);
2747 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2748 TRACE("Application is setting the old value over, nothing to do\n");
2749 return WINED3D_OK;
2752 This->updateStateBlock->baseVertexIndex = BaseIndex;
2754 if (This->isRecordingState) {
2755 TRACE("Recording... not performing anything\n");
2756 return WINED3D_OK;
2758 /* The base vertex index affects the stream sources */
2759 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2760 return WINED3D_OK;
2763 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 TRACE("(%p) : base_index %p\n", This, base_index);
2767 *base_index = This->stateBlock->baseVertexIndex;
2769 TRACE("Returning %u\n", *base_index);
2771 return WINED3D_OK;
2774 /*****
2775 * Get / Set Viewports
2776 *****/
2777 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2780 TRACE("(%p)\n", This);
2781 This->updateStateBlock->changed.viewport = TRUE;
2782 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2784 /* Handle recording of state blocks */
2785 if (This->isRecordingState) {
2786 TRACE("Recording... not performing anything\n");
2787 return WINED3D_OK;
2790 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2791 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2794 return WINED3D_OK;
2798 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2800 TRACE("(%p)\n", This);
2801 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2802 return WINED3D_OK;
2805 /*****
2806 * Get / Set Render States
2807 * TODO: Verify against dx9 definitions
2808 *****/
2809 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2812 DWORD oldValue = This->stateBlock->renderState[State];
2814 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2816 This->updateStateBlock->changed.renderState[State] = TRUE;
2817 This->updateStateBlock->renderState[State] = Value;
2819 /* Handle recording of state blocks */
2820 if (This->isRecordingState) {
2821 TRACE("Recording... not performing anything\n");
2822 return WINED3D_OK;
2825 /* Compared here and not before the assignment to allow proper stateblock recording */
2826 if(Value == oldValue) {
2827 TRACE("Application is setting the old value over, nothing to do\n");
2828 } else {
2829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2832 return WINED3D_OK;
2835 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2837 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2838 *pValue = This->stateBlock->renderState[State];
2839 return WINED3D_OK;
2842 /*****
2843 * Get / Set Sampler States
2844 * TODO: Verify against dx9 definitions
2845 *****/
2847 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 DWORD oldValue;
2851 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2852 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2854 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2855 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2859 * SetSampler is designed to allow for more than the standard up to 8 textures
2860 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2861 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2863 * http://developer.nvidia.com/object/General_FAQ.html#t6
2865 * There are two new settings for GForce
2866 * the sampler one:
2867 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2868 * and the texture one:
2869 * GL_MAX_TEXTURE_COORDS_ARB.
2870 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2871 ******************/
2873 oldValue = This->stateBlock->samplerState[Sampler][Type];
2874 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2875 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2877 /* Handle recording of state blocks */
2878 if (This->isRecordingState) {
2879 TRACE("Recording... not performing anything\n");
2880 return WINED3D_OK;
2883 if(oldValue == Value) {
2884 TRACE("Application is setting the old value over, nothing to do\n");
2885 return WINED3D_OK;
2888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2890 return WINED3D_OK;
2893 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2897 This, Sampler, debug_d3dsamplerstate(Type), Type);
2899 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2900 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2903 *Value = This->stateBlock->samplerState[Sampler][Type];
2904 TRACE("(%p) : Returning %#x\n", This, *Value);
2906 return WINED3D_OK;
2909 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912 This->updateStateBlock->changed.scissorRect = TRUE;
2913 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2914 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2915 return WINED3D_OK;
2917 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2919 if(This->isRecordingState) {
2920 TRACE("Recording... not performing anything\n");
2921 return WINED3D_OK;
2924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2926 return WINED3D_OK;
2929 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2933 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2934 return WINED3D_OK;
2937 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2939 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2941 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2943 This->updateStateBlock->vertexDecl = pDecl;
2944 This->updateStateBlock->changed.vertexDecl = TRUE;
2946 if (This->isRecordingState) {
2947 TRACE("Recording... not performing anything\n");
2948 return WINED3D_OK;
2949 } else if(pDecl == oldDecl) {
2950 /* Checked after the assignment to allow proper stateblock recording */
2951 TRACE("Application is setting the old declaration over, nothing to do\n");
2952 return WINED3D_OK;
2955 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2956 return WINED3D_OK;
2959 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2962 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2964 *ppDecl = This->stateBlock->vertexDecl;
2965 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2966 return WINED3D_OK;
2969 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2971 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2973 This->updateStateBlock->vertexShader = pShader;
2974 This->updateStateBlock->changed.vertexShader = TRUE;
2976 if (This->isRecordingState) {
2977 TRACE("Recording... not performing anything\n");
2978 return WINED3D_OK;
2979 } else if(oldShader == pShader) {
2980 /* Checked here to allow proper stateblock recording */
2981 TRACE("App is setting the old shader over, nothing to do\n");
2982 return WINED3D_OK;
2985 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2989 return WINED3D_OK;
2992 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 if (NULL == ppShader) {
2996 return WINED3DERR_INVALIDCALL;
2998 *ppShader = This->stateBlock->vertexShader;
2999 if( NULL != *ppShader)
3000 IWineD3DVertexShader_AddRef(*ppShader);
3002 TRACE("(%p) : returning %p\n", This, *ppShader);
3003 return WINED3D_OK;
3006 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3007 IWineD3DDevice *iface,
3008 UINT start,
3009 CONST BOOL *srcData,
3010 UINT count) {
3012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 int i, cnt = min(count, MAX_CONST_B - start);
3015 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3016 iface, srcData, start, count);
3018 if (srcData == NULL || cnt < 0)
3019 return WINED3DERR_INVALIDCALL;
3021 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3022 for (i = 0; i < cnt; i++)
3023 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3025 for (i = start; i < cnt + start; ++i) {
3026 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3031 return WINED3D_OK;
3034 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3035 IWineD3DDevice *iface,
3036 UINT start,
3037 BOOL *dstData,
3038 UINT count) {
3040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3041 int cnt = min(count, MAX_CONST_B - start);
3043 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3044 iface, dstData, start, count);
3046 if (dstData == NULL || cnt < 0)
3047 return WINED3DERR_INVALIDCALL;
3049 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3050 return WINED3D_OK;
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3054 IWineD3DDevice *iface,
3055 UINT start,
3056 CONST int *srcData,
3057 UINT count) {
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 int i, cnt = min(count, MAX_CONST_I - start);
3062 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3063 iface, srcData, start, count);
3065 if (srcData == NULL || cnt < 0)
3066 return WINED3DERR_INVALIDCALL;
3068 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3069 for (i = 0; i < cnt; i++)
3070 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3071 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3073 for (i = start; i < cnt + start; ++i) {
3074 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3077 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3079 return WINED3D_OK;
3082 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3083 IWineD3DDevice *iface,
3084 UINT start,
3085 int *dstData,
3086 UINT count) {
3088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 int cnt = min(count, MAX_CONST_I - start);
3091 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3092 iface, dstData, start, count);
3094 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3095 return WINED3DERR_INVALIDCALL;
3097 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3098 return WINED3D_OK;
3101 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3102 IWineD3DDevice *iface,
3103 UINT start,
3104 CONST float *srcData,
3105 UINT count) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 int i;
3110 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3111 iface, srcData, start, count);
3113 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3114 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3115 return WINED3DERR_INVALIDCALL;
3117 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3118 if(TRACE_ON(d3d)) {
3119 for (i = 0; i < count; i++)
3120 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3121 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3124 for (i = start; i < count + start; ++i) {
3125 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3126 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3127 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3128 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3129 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3131 ptr->idx[ptr->count++] = i;
3132 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3138 return WINED3D_OK;
3141 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3142 IWineD3DDevice *iface,
3143 UINT start,
3144 float *dstData,
3145 UINT count) {
3147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3148 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3150 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3151 iface, dstData, start, count);
3153 if (dstData == NULL || cnt < 0)
3154 return WINED3DERR_INVALIDCALL;
3156 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3157 return WINED3D_OK;
3160 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3161 DWORD i;
3162 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3167 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3168 int i = This->rev_tex_unit_map[unit];
3169 int j = This->texUnitMap[stage];
3171 This->texUnitMap[stage] = unit;
3172 if (i != -1 && i != stage) {
3173 This->texUnitMap[i] = -1;
3176 This->rev_tex_unit_map[unit] = stage;
3177 if (j != -1 && j != unit) {
3178 This->rev_tex_unit_map[j] = -1;
3182 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3183 int i;
3185 for (i = 0; i < MAX_TEXTURES; ++i) {
3186 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3187 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3188 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3189 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3190 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3191 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3192 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3193 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3195 if (color_op == WINED3DTOP_DISABLE) {
3196 /* Not used, and disable higher stages */
3197 while (i < MAX_TEXTURES) {
3198 This->fixed_function_usage_map[i] = FALSE;
3199 ++i;
3201 break;
3204 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3205 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3206 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3207 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3208 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3209 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3210 This->fixed_function_usage_map[i] = TRUE;
3211 } else {
3212 This->fixed_function_usage_map[i] = FALSE;
3215 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3216 This->fixed_function_usage_map[i+1] = TRUE;
3221 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3222 int i, tex;
3224 device_update_fixed_function_usage_map(This);
3226 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3227 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3228 if (!This->fixed_function_usage_map[i]) continue;
3230 if (This->texUnitMap[i] != i) {
3231 device_map_stage(This, i, i);
3232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3233 markTextureStagesDirty(This, i);
3236 return;
3239 /* Now work out the mapping */
3240 tex = 0;
3241 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3242 if (!This->fixed_function_usage_map[i]) continue;
3244 if (This->texUnitMap[i] != tex) {
3245 device_map_stage(This, i, tex);
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3247 markTextureStagesDirty(This, i);
3250 ++tex;
3254 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3255 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3256 int i;
3258 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3259 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3260 device_map_stage(This, i, i);
3261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3262 if (i < MAX_TEXTURES) {
3263 markTextureStagesDirty(This, i);
3269 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3270 int current_mapping = This->rev_tex_unit_map[unit];
3272 if (current_mapping == -1) {
3273 /* Not currently used */
3274 return TRUE;
3277 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3278 /* Used by a fragment sampler */
3280 if (!pshader_sampler_tokens) {
3281 /* No pixel shader, check fixed function */
3282 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3285 /* Pixel shader, check the shader's sampler map */
3286 return !pshader_sampler_tokens[current_mapping];
3289 /* Used by a vertex sampler */
3290 return !vshader_sampler_tokens[current_mapping];
3293 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3294 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3295 DWORD *pshader_sampler_tokens = NULL;
3296 int start = GL_LIMITS(combined_samplers) - 1;
3297 int i;
3299 if (ps) {
3300 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3302 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3303 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3304 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3307 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3308 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3309 if (vshader_sampler_tokens[i]) {
3310 if (This->texUnitMap[vsampler_idx] != -1) {
3311 /* Already mapped somewhere */
3312 continue;
3315 while (start >= 0) {
3316 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3317 device_map_stage(This, vsampler_idx, start);
3318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3320 --start;
3321 break;
3324 --start;
3330 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3331 BOOL vs = use_vs(This);
3332 BOOL ps = use_ps(This);
3334 * Rules are:
3335 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3336 * that would be really messy and require shader recompilation
3337 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3338 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3340 if (ps) {
3341 device_map_psamplers(This);
3342 } else {
3343 device_map_fixed_function_samplers(This);
3346 if (vs) {
3347 device_map_vsamplers(This, ps);
3351 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3353 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3354 This->updateStateBlock->pixelShader = pShader;
3355 This->updateStateBlock->changed.pixelShader = TRUE;
3357 /* Handle recording of state blocks */
3358 if (This->isRecordingState) {
3359 TRACE("Recording... not performing anything\n");
3362 if (This->isRecordingState) {
3363 TRACE("Recording... not performing anything\n");
3364 return WINED3D_OK;
3367 if(pShader == oldShader) {
3368 TRACE("App is setting the old pixel shader over, nothing to do\n");
3369 return WINED3D_OK;
3372 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3375 return WINED3D_OK;
3378 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3381 if (NULL == ppShader) {
3382 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3383 return WINED3DERR_INVALIDCALL;
3386 *ppShader = This->stateBlock->pixelShader;
3387 if (NULL != *ppShader) {
3388 IWineD3DPixelShader_AddRef(*ppShader);
3390 TRACE("(%p) : returning %p\n", This, *ppShader);
3391 return WINED3D_OK;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3395 IWineD3DDevice *iface,
3396 UINT start,
3397 CONST BOOL *srcData,
3398 UINT count) {
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 int i, cnt = min(count, MAX_CONST_B - start);
3403 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3404 iface, srcData, start, count);
3406 if (srcData == NULL || cnt < 0)
3407 return WINED3DERR_INVALIDCALL;
3409 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3410 for (i = 0; i < cnt; i++)
3411 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3413 for (i = start; i < cnt + start; ++i) {
3414 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3419 return WINED3D_OK;
3422 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3423 IWineD3DDevice *iface,
3424 UINT start,
3425 BOOL *dstData,
3426 UINT count) {
3428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3429 int cnt = min(count, MAX_CONST_B - start);
3431 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3432 iface, dstData, start, count);
3434 if (dstData == NULL || cnt < 0)
3435 return WINED3DERR_INVALIDCALL;
3437 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3438 return WINED3D_OK;
3441 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3442 IWineD3DDevice *iface,
3443 UINT start,
3444 CONST int *srcData,
3445 UINT count) {
3447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3448 int i, cnt = min(count, MAX_CONST_I - start);
3450 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3451 iface, srcData, start, count);
3453 if (srcData == NULL || cnt < 0)
3454 return WINED3DERR_INVALIDCALL;
3456 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3457 for (i = 0; i < cnt; i++)
3458 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3459 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3461 for (i = start; i < cnt + start; ++i) {
3462 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3467 return WINED3D_OK;
3470 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3471 IWineD3DDevice *iface,
3472 UINT start,
3473 int *dstData,
3474 UINT count) {
3476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3477 int cnt = min(count, MAX_CONST_I - start);
3479 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3480 iface, dstData, start, count);
3482 if (dstData == NULL || cnt < 0)
3483 return WINED3DERR_INVALIDCALL;
3485 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3486 return WINED3D_OK;
3489 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3490 IWineD3DDevice *iface,
3491 UINT start,
3492 CONST float *srcData,
3493 UINT count) {
3495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3496 int i;
3498 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3499 iface, srcData, start, count);
3501 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3502 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3503 return WINED3DERR_INVALIDCALL;
3505 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3506 if(TRACE_ON(d3d)) {
3507 for (i = 0; i < count; i++)
3508 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3509 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3512 for (i = start; i < count + start; ++i) {
3513 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3514 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3515 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3516 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3517 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3519 ptr->idx[ptr->count++] = i;
3520 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3526 return WINED3D_OK;
3529 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3530 IWineD3DDevice *iface,
3531 UINT start,
3532 float *dstData,
3533 UINT count) {
3535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3536 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3538 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3539 iface, dstData, start, count);
3541 if (dstData == NULL || cnt < 0)
3542 return WINED3DERR_INVALIDCALL;
3544 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3545 return WINED3D_OK;
3548 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3549 static HRESULT
3550 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3551 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3552 unsigned int i;
3553 DWORD DestFVF = dest->fvf;
3554 WINED3DVIEWPORT vp;
3555 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3556 BOOL doClip;
3557 int numTextures;
3559 if (lpStrideData->u.s.normal.lpData) {
3560 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3563 if (lpStrideData->u.s.position.lpData == NULL) {
3564 ERR("Source has no position mask\n");
3565 return WINED3DERR_INVALIDCALL;
3568 /* We might access VBOs from this code, so hold the lock */
3569 ENTER_GL();
3571 if (dest->resource.allocatedMemory == NULL) {
3572 /* This may happen if we do direct locking into a vbo. Unlikely,
3573 * but theoretically possible(ddraw processvertices test)
3575 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3576 if(!dest->resource.allocatedMemory) {
3577 LEAVE_GL();
3578 ERR("Out of memory\n");
3579 return E_OUTOFMEMORY;
3581 if(dest->vbo) {
3582 void *src;
3583 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3584 checkGLcall("glBindBufferARB");
3585 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3586 if(src) {
3587 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3589 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3590 checkGLcall("glUnmapBufferARB");
3594 /* Get a pointer into the destination vbo(create one if none exists) and
3595 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3597 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3598 CreateVBO(dest);
3601 if(dest->vbo) {
3602 unsigned char extrabytes = 0;
3603 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3604 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3605 * this may write 4 extra bytes beyond the area that should be written
3607 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3608 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3609 if(!dest_conv_addr) {
3610 ERR("Out of memory\n");
3611 /* Continue without storing converted vertices */
3613 dest_conv = dest_conv_addr;
3616 /* Should I clip?
3617 * a) WINED3DRS_CLIPPING is enabled
3618 * b) WINED3DVOP_CLIP is passed
3620 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3621 static BOOL warned = FALSE;
3623 * The clipping code is not quite correct. Some things need
3624 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3625 * so disable clipping for now.
3626 * (The graphics in Half-Life are broken, and my processvertices
3627 * test crashes with IDirect3DDevice3)
3628 doClip = TRUE;
3630 doClip = FALSE;
3631 if(!warned) {
3632 warned = TRUE;
3633 FIXME("Clipping is broken and disabled for now\n");
3635 } else doClip = FALSE;
3636 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3638 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3639 WINED3DTS_VIEW,
3640 &view_mat);
3641 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3642 WINED3DTS_PROJECTION,
3643 &proj_mat);
3644 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3645 WINED3DTS_WORLDMATRIX(0),
3646 &world_mat);
3648 TRACE("View mat:\n");
3649 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);
3650 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);
3651 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);
3652 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);
3654 TRACE("Proj mat:\n");
3655 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);
3656 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);
3657 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);
3658 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);
3660 TRACE("World mat:\n");
3661 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);
3662 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);
3663 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);
3664 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);
3666 /* Get the viewport */
3667 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3668 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3669 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3671 multiply_matrix(&mat,&view_mat,&world_mat);
3672 multiply_matrix(&mat,&proj_mat,&mat);
3674 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3676 for (i = 0; i < dwCount; i+= 1) {
3677 unsigned int tex_index;
3679 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3680 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3681 /* The position first */
3682 float *p =
3683 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3684 float x, y, z, rhw;
3685 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3687 /* Multiplication with world, view and projection matrix */
3688 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);
3689 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);
3690 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);
3691 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);
3693 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3695 /* WARNING: The following things are taken from d3d7 and were not yet checked
3696 * against d3d8 or d3d9!
3699 /* Clipping conditions: From
3700 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3702 * A vertex is clipped if it does not match the following requirements
3703 * -rhw < x <= rhw
3704 * -rhw < y <= rhw
3705 * 0 < z <= rhw
3706 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3708 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3709 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3713 if( !doClip ||
3714 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3715 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3716 ( rhw > eps ) ) ) {
3718 /* "Normal" viewport transformation (not clipped)
3719 * 1) The values are divided by rhw
3720 * 2) The y axis is negative, so multiply it with -1
3721 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3722 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3723 * 4) Multiply x with Width/2 and add Width/2
3724 * 5) The same for the height
3725 * 6) Add the viewpoint X and Y to the 2D coordinates and
3726 * The minimum Z value to z
3727 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3729 * Well, basically it's simply a linear transformation into viewport
3730 * coordinates
3733 x /= rhw;
3734 y /= rhw;
3735 z /= rhw;
3737 y *= -1;
3739 x *= vp.Width / 2;
3740 y *= vp.Height / 2;
3741 z *= vp.MaxZ - vp.MinZ;
3743 x += vp.Width / 2 + vp.X;
3744 y += vp.Height / 2 + vp.Y;
3745 z += vp.MinZ;
3747 rhw = 1 / rhw;
3748 } else {
3749 /* That vertex got clipped
3750 * Contrary to OpenGL it is not dropped completely, it just
3751 * undergoes a different calculation.
3753 TRACE("Vertex got clipped\n");
3754 x += rhw;
3755 y += rhw;
3757 x /= 2;
3758 y /= 2;
3760 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3761 * outside of the main vertex buffer memory. That needs some more
3762 * investigation...
3766 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3769 ( (float *) dest_ptr)[0] = x;
3770 ( (float *) dest_ptr)[1] = y;
3771 ( (float *) dest_ptr)[2] = z;
3772 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3774 dest_ptr += 3 * sizeof(float);
3776 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3777 dest_ptr += sizeof(float);
3780 if(dest_conv) {
3781 float w = 1 / rhw;
3782 ( (float *) dest_conv)[0] = x * w;
3783 ( (float *) dest_conv)[1] = y * w;
3784 ( (float *) dest_conv)[2] = z * w;
3785 ( (float *) dest_conv)[3] = w;
3787 dest_conv += 3 * sizeof(float);
3789 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3790 dest_conv += sizeof(float);
3794 if (DestFVF & WINED3DFVF_PSIZE) {
3795 dest_ptr += sizeof(DWORD);
3796 if(dest_conv) dest_conv += sizeof(DWORD);
3798 if (DestFVF & WINED3DFVF_NORMAL) {
3799 float *normal =
3800 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3801 /* AFAIK this should go into the lighting information */
3802 FIXME("Didn't expect the destination to have a normal\n");
3803 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3804 if(dest_conv) {
3805 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3809 if (DestFVF & WINED3DFVF_DIFFUSE) {
3810 DWORD *color_d =
3811 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3812 if(!color_d) {
3813 static BOOL warned = FALSE;
3815 if(!warned) {
3816 ERR("No diffuse color in source, but destination has one\n");
3817 warned = TRUE;
3820 *( (DWORD *) dest_ptr) = 0xffffffff;
3821 dest_ptr += sizeof(DWORD);
3823 if(dest_conv) {
3824 *( (DWORD *) dest_conv) = 0xffffffff;
3825 dest_conv += sizeof(DWORD);
3828 else {
3829 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3830 if(dest_conv) {
3831 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3832 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3833 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3834 dest_conv += sizeof(DWORD);
3839 if (DestFVF & WINED3DFVF_SPECULAR) {
3840 /* What's the color value in the feedback buffer? */
3841 DWORD *color_s =
3842 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3843 if(!color_s) {
3844 static BOOL warned = FALSE;
3846 if(!warned) {
3847 ERR("No specular color in source, but destination has one\n");
3848 warned = TRUE;
3851 *( (DWORD *) dest_ptr) = 0xFF000000;
3852 dest_ptr += sizeof(DWORD);
3854 if(dest_conv) {
3855 *( (DWORD *) dest_conv) = 0xFF000000;
3856 dest_conv += sizeof(DWORD);
3859 else {
3860 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3861 if(dest_conv) {
3862 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3863 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3864 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3865 dest_conv += sizeof(DWORD);
3870 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3871 float *tex_coord =
3872 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3873 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3874 if(!tex_coord) {
3875 ERR("No source texture, but destination requests one\n");
3876 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3877 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3879 else {
3880 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3881 if(dest_conv) {
3882 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3888 if(dest_conv) {
3889 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3890 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3891 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3892 dwCount * get_flexible_vertex_size(DestFVF),
3893 dest_conv_addr));
3894 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3895 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3898 LEAVE_GL();
3900 return WINED3D_OK;
3902 #undef copy_and_next
3904 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3906 WineDirect3DVertexStridedData strided;
3907 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3908 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3910 if(pVertexDecl) {
3911 ERR("Output vertex declaration not implemented yet\n");
3914 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3915 * and this call is quite performance critical, so don't call needlessly
3917 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3918 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3921 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3922 * control the streamIsUP flag, thus restore it afterwards.
3924 This->stateBlock->streamIsUP = FALSE;
3925 memset(&strided, 0, sizeof(strided));
3926 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3927 This->stateBlock->streamIsUP = streamWasUP;
3929 if(vbo || SrcStartIndex) {
3930 unsigned int i;
3931 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3932 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3934 * Also get the start index in, but only loop over all elements if there's something to add at all.
3936 #define FIXSRC(type) \
3937 if(strided.u.s.type.VBO) { \
3938 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3939 strided.u.s.type.VBO = 0; \
3940 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3941 ENTER_GL(); \
3942 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3943 vb->vbo = 0; \
3944 LEAVE_GL(); \
3946 if(strided.u.s.type.lpData) { \
3947 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3949 FIXSRC(position);
3950 FIXSRC(blendWeights);
3951 FIXSRC(blendMatrixIndices);
3952 FIXSRC(normal);
3953 FIXSRC(pSize);
3954 FIXSRC(diffuse);
3955 FIXSRC(specular);
3956 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3957 FIXSRC(texCoords[i]);
3959 FIXSRC(position2);
3960 FIXSRC(normal2);
3961 FIXSRC(tangent);
3962 FIXSRC(binormal);
3963 FIXSRC(tessFactor);
3964 FIXSRC(fog);
3965 FIXSRC(depth);
3966 FIXSRC(sample);
3967 #undef FIXSRC
3970 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3973 /*****
3974 * Get / Set Texture Stage States
3975 * TODO: Verify against dx9 definitions
3976 *****/
3977 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3979 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3981 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3983 if (Stage >= MAX_TEXTURES) {
3984 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3985 return WINED3D_OK;
3988 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3989 This->updateStateBlock->textureState[Stage][Type] = Value;
3991 if (This->isRecordingState) {
3992 TRACE("Recording... not performing anything\n");
3993 return WINED3D_OK;
3996 /* Checked after the assignments to allow proper stateblock recording */
3997 if(oldValue == Value) {
3998 TRACE("App is setting the old value over, nothing to do\n");
3999 return WINED3D_OK;
4002 if(Stage > This->stateBlock->lowest_disabled_stage &&
4003 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4004 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4005 * Changes in other states are important on disabled stages too
4007 return WINED3D_OK;
4010 if(Type == WINED3DTSS_COLOROP) {
4011 int i;
4013 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4014 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4015 * they have to be disabled
4017 * The current stage is dirtified below.
4019 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4020 TRACE("Additionally dirtifying stage %d\n", i);
4021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4023 This->stateBlock->lowest_disabled_stage = Stage;
4024 TRACE("New lowest disabled: %d\n", Stage);
4025 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4026 /* Previously disabled stage enabled. Stages above it may need enabling
4027 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4028 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4030 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4033 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4034 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4035 break;
4037 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4040 This->stateBlock->lowest_disabled_stage = i;
4041 TRACE("New lowest disabled: %d\n", i);
4043 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4044 /* TODO: Built a stage -> texture unit mapping for register combiners */
4048 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4050 return WINED3D_OK;
4053 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4055 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4056 *pValue = This->updateStateBlock->textureState[Stage][Type];
4057 return WINED3D_OK;
4060 /*****
4061 * Get / Set Texture
4062 *****/
4063 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4065 IWineD3DBaseTexture *oldTexture;
4067 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4069 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4070 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4073 oldTexture = This->updateStateBlock->textures[Stage];
4075 if(pTexture != NULL) {
4076 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4078 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4079 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4080 return WINED3DERR_INVALIDCALL;
4082 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4085 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4086 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4088 This->updateStateBlock->changed.textures[Stage] = TRUE;
4089 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4090 This->updateStateBlock->textures[Stage] = pTexture;
4092 /* Handle recording of state blocks */
4093 if (This->isRecordingState) {
4094 TRACE("Recording... not performing anything\n");
4095 return WINED3D_OK;
4098 if(oldTexture == pTexture) {
4099 TRACE("App is setting the same texture again, nothing to do\n");
4100 return WINED3D_OK;
4103 /** NOTE: MSDN says that setTexture increases the reference count,
4104 * and the the application must set the texture back to null (or have a leaky application),
4105 * This means we should pass the refcount up to the parent
4106 *******************************/
4107 if (NULL != This->updateStateBlock->textures[Stage]) {
4108 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4109 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4111 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4112 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4113 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4114 * so the COLOROP and ALPHAOP have to be dirtified.
4116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4119 if(bindCount == 1) {
4120 new->baseTexture.sampler = Stage;
4122 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4126 if (NULL != oldTexture) {
4127 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4128 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4130 IWineD3DBaseTexture_Release(oldTexture);
4131 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4136 if(bindCount && old->baseTexture.sampler == Stage) {
4137 int i;
4138 /* Have to do a search for the other sampler(s) where the texture is bound to
4139 * Shouldn't happen as long as apps bind a texture only to one stage
4141 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4142 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4143 if(This->updateStateBlock->textures[i] == oldTexture) {
4144 old->baseTexture.sampler = i;
4145 break;
4151 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4153 return WINED3D_OK;
4156 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4159 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4161 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4162 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4165 *ppTexture=This->stateBlock->textures[Stage];
4166 if (*ppTexture)
4167 IWineD3DBaseTexture_AddRef(*ppTexture);
4169 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4171 return WINED3D_OK;
4174 /*****
4175 * Get Back Buffer
4176 *****/
4177 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4178 IWineD3DSurface **ppBackBuffer) {
4179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4180 IWineD3DSwapChain *swapChain;
4181 HRESULT hr;
4183 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4185 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4186 if (hr == WINED3D_OK) {
4187 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4188 IWineD3DSwapChain_Release(swapChain);
4189 } else {
4190 *ppBackBuffer = NULL;
4192 return hr;
4195 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4197 WARN("(%p) : stub, calling idirect3d for now\n", This);
4198 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4201 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4203 IWineD3DSwapChain *swapChain;
4204 HRESULT hr;
4206 if(iSwapChain > 0) {
4207 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4208 if (hr == WINED3D_OK) {
4209 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4210 IWineD3DSwapChain_Release(swapChain);
4211 } else {
4212 FIXME("(%p) Error getting display mode\n", This);
4214 } else {
4215 /* Don't read the real display mode,
4216 but return the stored mode instead. X11 can't change the color
4217 depth, and some apps are pretty angry if they SetDisplayMode from
4218 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4220 Also don't relay to the swapchain because with ddraw it's possible
4221 that there isn't a swapchain at all */
4222 pMode->Width = This->ddraw_width;
4223 pMode->Height = This->ddraw_height;
4224 pMode->Format = This->ddraw_format;
4225 pMode->RefreshRate = 0;
4226 hr = WINED3D_OK;
4229 return hr;
4232 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4234 TRACE("(%p)->(%p)\n", This, hWnd);
4236 if(This->ddraw_fullscreen) {
4237 if(This->ddraw_window && This->ddraw_window != hWnd) {
4238 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4240 if(hWnd && This->ddraw_window != hWnd) {
4241 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4245 This->ddraw_window = hWnd;
4246 return WINED3D_OK;
4249 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4251 TRACE("(%p)->(%p)\n", This, hWnd);
4253 *hWnd = This->ddraw_window;
4254 return WINED3D_OK;
4257 /*****
4258 * Stateblock related functions
4259 *****/
4261 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4263 IWineD3DStateBlockImpl *object;
4264 HRESULT temp_result;
4265 int i;
4267 TRACE("(%p)\n", This);
4269 if (This->isRecordingState) {
4270 return WINED3DERR_INVALIDCALL;
4273 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4274 if (NULL == object ) {
4275 FIXME("(%p)Error allocating memory for stateblock\n", This);
4276 return E_OUTOFMEMORY;
4278 TRACE("(%p) created object %p\n", This, object);
4279 object->wineD3DDevice= This;
4280 /** FIXME: object->parent = parent; **/
4281 object->parent = NULL;
4282 object->blockType = WINED3DSBT_ALL;
4283 object->ref = 1;
4284 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4286 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4287 list_init(&object->lightMap[i]);
4290 temp_result = allocate_shader_constants(object);
4291 if (WINED3D_OK != temp_result)
4292 return temp_result;
4294 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4295 This->updateStateBlock = object;
4296 This->isRecordingState = TRUE;
4298 TRACE("(%p) recording stateblock %p\n",This , object);
4299 return WINED3D_OK;
4302 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4305 if (!This->isRecordingState) {
4306 FIXME("(%p) not recording! returning error\n", This);
4307 *ppStateBlock = NULL;
4308 return WINED3DERR_INVALIDCALL;
4311 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4312 This->isRecordingState = FALSE;
4313 This->updateStateBlock = This->stateBlock;
4314 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4315 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4316 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4317 return WINED3D_OK;
4320 /*****
4321 * Scene related functions
4322 *****/
4323 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4324 /* At the moment we have no need for any functionality at the beginning
4325 of a scene */
4326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4327 TRACE("(%p)\n", This);
4329 if(This->inScene) {
4330 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4331 return WINED3DERR_INVALIDCALL;
4333 This->inScene = TRUE;
4334 return WINED3D_OK;
4337 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4339 TRACE("(%p)\n", This);
4341 if(!This->inScene) {
4342 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4343 return WINED3DERR_INVALIDCALL;
4346 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4347 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4349 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4350 ENTER_GL();
4351 glFlush();
4352 checkGLcall("glFlush");
4353 LEAVE_GL();
4355 This->inScene = FALSE;
4356 return WINED3D_OK;
4359 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4360 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4361 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4363 IWineD3DSwapChain *swapChain = NULL;
4364 int i;
4365 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4367 TRACE("(%p) Presenting the frame\n", This);
4369 for(i = 0 ; i < swapchains ; i ++) {
4371 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4372 TRACE("presentinng chain %d, %p\n", i, swapChain);
4373 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4374 IWineD3DSwapChain_Release(swapChain);
4377 return WINED3D_OK;
4380 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4381 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4385 GLbitfield glMask = 0;
4386 unsigned int i;
4387 CONST WINED3DRECT* curRect;
4389 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4390 Count, pRects, Flags, Color, Z, Stencil);
4392 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4393 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4394 /* TODO: What about depth stencil buffers without stencil bits? */
4395 return WINED3DERR_INVALIDCALL;
4398 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4399 * and not the last active one.
4402 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4403 ENTER_GL();
4404 apply_fbo_state(iface);
4405 LEAVE_GL();
4408 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4409 ENTER_GL();
4411 if (Count > 0 && pRects) {
4412 curRect = pRects;
4413 } else {
4414 curRect = NULL;
4417 /* Only set the values up once, as they are not changing */
4418 if (Flags & WINED3DCLEAR_STENCIL) {
4419 glClearStencil(Stencil);
4420 checkGLcall("glClearStencil");
4421 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4422 glStencilMask(0xFFFFFFFF);
4425 if (Flags & WINED3DCLEAR_ZBUFFER) {
4426 glDepthMask(GL_TRUE);
4427 glClearDepth(Z);
4428 checkGLcall("glClearDepth");
4429 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4433 if (Flags & WINED3DCLEAR_TARGET) {
4434 TRACE("Clearing screen with glClear to color %x\n", Color);
4435 glClearColor(D3DCOLOR_R(Color),
4436 D3DCOLOR_G(Color),
4437 D3DCOLOR_B(Color),
4438 D3DCOLOR_A(Color));
4439 checkGLcall("glClearColor");
4441 /* Clear ALL colors! */
4442 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4443 glMask = glMask | GL_COLOR_BUFFER_BIT;
4446 if (!curRect) {
4447 /* In drawable flag is set below */
4449 if (This->render_offscreen) {
4450 glScissor(This->stateBlock->viewport.X,
4451 This->stateBlock->viewport.Y,
4452 This->stateBlock->viewport.Width,
4453 This->stateBlock->viewport.Height);
4454 } else {
4455 glScissor(This->stateBlock->viewport.X,
4456 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4457 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4458 This->stateBlock->viewport.Width,
4459 This->stateBlock->viewport.Height);
4461 checkGLcall("glScissor");
4462 glClear(glMask);
4463 checkGLcall("glClear");
4464 } else {
4465 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4466 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4468 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4469 curRect[0].x2 < target->currentDesc.Width ||
4470 curRect[0].y2 < target->currentDesc.Height) {
4471 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4472 blt_to_drawable(This, target);
4476 /* Now process each rect in turn */
4477 for (i = 0; i < Count; i++) {
4478 /* Note gl uses lower left, width/height */
4479 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4480 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4481 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4482 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4484 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4485 * The rectangle is not cleared, no error is returned, but further rectanlges are
4486 * still cleared if they are valid
4488 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4489 TRACE("Rectangle with negative dimensions, ignoring\n");
4490 continue;
4493 if(This->render_offscreen) {
4494 glScissor(curRect[i].x1, curRect[i].y1,
4495 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4496 } else {
4497 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4498 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4500 checkGLcall("glScissor");
4502 glClear(glMask);
4503 checkGLcall("glClear");
4507 /* Restore the old values (why..?) */
4508 if (Flags & WINED3DCLEAR_STENCIL) {
4509 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4511 if (Flags & WINED3DCLEAR_TARGET) {
4512 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4513 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4514 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4515 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4516 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4519 LEAVE_GL();
4521 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4522 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4524 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4525 target->Flags |= SFLAG_INTEXTURE;
4526 target->Flags &= ~SFLAG_INSYSMEM;
4527 } else {
4528 target->Flags |= SFLAG_INDRAWABLE;
4529 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4531 return WINED3D_OK;
4534 /*****
4535 * Drawing functions
4536 *****/
4537 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4538 UINT PrimitiveCount) {
4540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4542 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4543 debug_d3dprimitivetype(PrimitiveType),
4544 StartVertex, PrimitiveCount);
4546 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4547 if(This->stateBlock->streamIsUP) {
4548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4549 This->stateBlock->streamIsUP = FALSE;
4552 if(This->stateBlock->loadBaseVertexIndex != 0) {
4553 This->stateBlock->loadBaseVertexIndex = 0;
4554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4556 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4557 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4558 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4559 return WINED3D_OK;
4562 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4563 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4564 WINED3DPRIMITIVETYPE PrimitiveType,
4565 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4568 UINT idxStride = 2;
4569 IWineD3DIndexBuffer *pIB;
4570 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4571 GLuint vbo;
4573 pIB = This->stateBlock->pIndexData;
4574 if (!pIB) {
4575 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4576 * without an index buffer set. (The first time at least...)
4577 * D3D8 simply dies, but I doubt it can do much harm to return
4578 * D3DERR_INVALIDCALL there as well. */
4579 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4580 return WINED3DERR_INVALIDCALL;
4583 if(This->stateBlock->streamIsUP) {
4584 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4585 This->stateBlock->streamIsUP = FALSE;
4587 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4589 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4590 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4591 minIndex, NumVertices, startIndex, primCount);
4593 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4594 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4595 idxStride = 2;
4596 } else {
4597 idxStride = 4;
4600 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4601 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4605 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4606 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4608 return WINED3D_OK;
4611 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4612 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4613 UINT VertexStreamZeroStride) {
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4617 debug_d3dprimitivetype(PrimitiveType),
4618 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4620 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4621 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4622 This->stateBlock->streamOffset[0] = 0;
4623 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4624 This->stateBlock->streamIsUP = TRUE;
4625 This->stateBlock->loadBaseVertexIndex = 0;
4627 /* TODO: Only mark dirty if drawing from a different UP address */
4628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4630 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4631 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4633 /* MSDN specifies stream zero settings must be set to NULL */
4634 This->stateBlock->streamStride[0] = 0;
4635 This->stateBlock->streamSource[0] = NULL;
4637 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4638 * the new stream sources or use UP drawing again
4640 return WINED3D_OK;
4643 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4644 UINT MinVertexIndex, UINT NumVertices,
4645 UINT PrimitiveCount, CONST void* pIndexData,
4646 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4647 UINT VertexStreamZeroStride) {
4648 int idxStride;
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4651 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4652 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4653 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4654 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4656 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4657 idxStride = 2;
4658 } else {
4659 idxStride = 4;
4662 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4663 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4664 This->stateBlock->streamIsUP = TRUE;
4665 This->stateBlock->streamOffset[0] = 0;
4666 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4668 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4669 This->stateBlock->baseVertexIndex = 0;
4670 This->stateBlock->loadBaseVertexIndex = 0;
4671 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4675 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4677 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4678 This->stateBlock->streamSource[0] = NULL;
4679 This->stateBlock->streamStride[0] = 0;
4680 This->stateBlock->pIndexData = NULL;
4681 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4682 * SetStreamSource to specify a vertex buffer
4685 return WINED3D_OK;
4688 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4691 /* Mark the state dirty until we have nicer tracking
4692 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4693 * that value.
4695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4697 This->stateBlock->baseVertexIndex = 0;
4698 This->up_strided = DrawPrimStrideData;
4699 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4700 This->up_strided = NULL;
4701 return WINED3D_OK;
4704 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4706 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4708 /* Mark the state dirty until we have nicer tracking
4709 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4710 * that value.
4712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4714 This->stateBlock->streamIsUP = TRUE;
4715 This->stateBlock->baseVertexIndex = 0;
4716 This->up_strided = DrawPrimStrideData;
4717 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4718 This->up_strided = NULL;
4719 return WINED3D_OK;
4723 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4724 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4726 HRESULT hr = WINED3D_OK;
4727 WINED3DRESOURCETYPE sourceType;
4728 WINED3DRESOURCETYPE destinationType;
4729 int i ,levels;
4731 /* TODO: think about moving the code into IWineD3DBaseTexture */
4733 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4735 /* verify that the source and destination textures aren't NULL */
4736 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4737 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4738 This, pSourceTexture, pDestinationTexture);
4739 hr = WINED3DERR_INVALIDCALL;
4742 if (pSourceTexture == pDestinationTexture) {
4743 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4744 This, pSourceTexture, pDestinationTexture);
4745 hr = WINED3DERR_INVALIDCALL;
4747 /* Verify that the source and destination textures are the same type */
4748 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4749 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4751 if (sourceType != destinationType) {
4752 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4753 This);
4754 hr = WINED3DERR_INVALIDCALL;
4757 /* check that both textures have the identical numbers of levels */
4758 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4759 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4760 hr = WINED3DERR_INVALIDCALL;
4763 if (WINED3D_OK == hr) {
4765 /* Make sure that the destination texture is loaded */
4766 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4768 /* Update every surface level of the texture */
4769 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4771 switch (sourceType) {
4772 case WINED3DRTYPE_TEXTURE:
4774 IWineD3DSurface *srcSurface;
4775 IWineD3DSurface *destSurface;
4777 for (i = 0 ; i < levels ; ++i) {
4778 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4779 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4780 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4781 IWineD3DSurface_Release(srcSurface);
4782 IWineD3DSurface_Release(destSurface);
4783 if (WINED3D_OK != hr) {
4784 WARN("(%p) : Call to update surface failed\n", This);
4785 return hr;
4789 break;
4790 case WINED3DRTYPE_CUBETEXTURE:
4792 IWineD3DSurface *srcSurface;
4793 IWineD3DSurface *destSurface;
4794 WINED3DCUBEMAP_FACES faceType;
4796 for (i = 0 ; i < levels ; ++i) {
4797 /* Update each cube face */
4798 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4799 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4800 if (WINED3D_OK != hr) {
4801 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4802 } else {
4803 TRACE("Got srcSurface %p\n", srcSurface);
4805 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4806 if (WINED3D_OK != hr) {
4807 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4808 } else {
4809 TRACE("Got desrSurface %p\n", destSurface);
4811 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4812 IWineD3DSurface_Release(srcSurface);
4813 IWineD3DSurface_Release(destSurface);
4814 if (WINED3D_OK != hr) {
4815 WARN("(%p) : Call to update surface failed\n", This);
4816 return hr;
4821 break;
4822 #if 0 /* TODO: Add support for volume textures */
4823 case WINED3DRTYPE_VOLUMETEXTURE:
4825 IWineD3DVolume srcVolume = NULL;
4826 IWineD3DSurface destVolume = NULL;
4828 for (i = 0 ; i < levels ; ++i) {
4829 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4830 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4831 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4832 IWineD3DVolume_Release(srcSurface);
4833 IWineD3DVolume_Release(destSurface);
4834 if (WINED3D_OK != hr) {
4835 WARN("(%p) : Call to update volume failed\n", This);
4836 return hr;
4840 break;
4841 #endif
4842 default:
4843 FIXME("(%p) : Unsupported source and destination type\n", This);
4844 hr = WINED3DERR_INVALIDCALL;
4848 return hr;
4851 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4852 IWineD3DSwapChain *swapChain;
4853 HRESULT hr;
4854 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4855 if(hr == WINED3D_OK) {
4856 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4857 IWineD3DSwapChain_Release(swapChain);
4859 return hr;
4862 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 /* return a sensible default */
4865 *pNumPasses = 1;
4866 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4867 FIXME("(%p) : stub\n", This);
4868 return WINED3D_OK;
4871 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4873 int j;
4874 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4875 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4876 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4877 return WINED3DERR_INVALIDCALL;
4879 for (j = 0; j < 256; ++j) {
4880 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4881 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4882 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4883 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4885 TRACE("(%p) : returning\n", This);
4886 return WINED3D_OK;
4889 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4891 int j;
4892 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4893 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4894 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4895 return WINED3DERR_INVALIDCALL;
4897 for (j = 0; j < 256; ++j) {
4898 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4899 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4900 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4901 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4903 TRACE("(%p) : returning\n", This);
4904 return WINED3D_OK;
4907 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4909 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4910 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4911 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4912 return WINED3DERR_INVALIDCALL;
4914 /*TODO: stateblocks */
4915 This->currentPalette = PaletteNumber;
4916 TRACE("(%p) : returning\n", This);
4917 return WINED3D_OK;
4920 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4922 if (PaletteNumber == NULL) {
4923 WARN("(%p) : returning Invalid Call\n", This);
4924 return WINED3DERR_INVALIDCALL;
4926 /*TODO: stateblocks */
4927 *PaletteNumber = This->currentPalette;
4928 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4929 return WINED3D_OK;
4932 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4934 static BOOL showFixmes = TRUE;
4935 if (showFixmes) {
4936 FIXME("(%p) : stub\n", This);
4937 showFixmes = FALSE;
4940 This->softwareVertexProcessing = bSoftware;
4941 return WINED3D_OK;
4945 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4947 static BOOL showFixmes = TRUE;
4948 if (showFixmes) {
4949 FIXME("(%p) : stub\n", This);
4950 showFixmes = FALSE;
4952 return This->softwareVertexProcessing;
4956 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4958 IWineD3DSwapChain *swapChain;
4959 HRESULT hr;
4961 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4963 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4964 if(hr == WINED3D_OK){
4965 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4966 IWineD3DSwapChain_Release(swapChain);
4967 }else{
4968 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4970 return hr;
4974 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4976 static BOOL showfixmes = TRUE;
4977 if(nSegments != 0.0f) {
4978 if( showfixmes) {
4979 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4980 showfixmes = FALSE;
4983 return WINED3D_OK;
4986 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4988 static BOOL showfixmes = TRUE;
4989 if( showfixmes) {
4990 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4991 showfixmes = FALSE;
4993 return 0.0f;
4996 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4998 /** TODO: remove casts to IWineD3DSurfaceImpl
4999 * NOTE: move code to surface to accomplish this
5000 ****************************************/
5001 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5002 int srcWidth, srcHeight;
5003 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5004 WINED3DFORMAT destFormat, srcFormat;
5005 UINT destSize;
5006 int srcLeft, destLeft, destTop;
5007 WINED3DPOOL srcPool, destPool;
5008 int offset = 0;
5009 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5010 glDescriptor *glDescription = NULL;
5012 WINED3DSURFACE_DESC winedesc;
5014 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5015 memset(&winedesc, 0, sizeof(winedesc));
5016 winedesc.Width = &srcSurfaceWidth;
5017 winedesc.Height = &srcSurfaceHeight;
5018 winedesc.Pool = &srcPool;
5019 winedesc.Format = &srcFormat;
5021 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5023 winedesc.Width = &destSurfaceWidth;
5024 winedesc.Height = &destSurfaceHeight;
5025 winedesc.Pool = &destPool;
5026 winedesc.Format = &destFormat;
5027 winedesc.Size = &destSize;
5029 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5031 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5032 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5033 return WINED3DERR_INVALIDCALL;
5036 if (destFormat == WINED3DFMT_UNKNOWN) {
5037 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5038 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5040 /* Get the update surface description */
5041 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5044 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5046 ENTER_GL();
5048 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5049 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5050 checkGLcall("glActiveTextureARB");
5053 /* Make sure the surface is loaded and up to date */
5054 IWineD3DSurface_PreLoad(pDestinationSurface);
5056 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5058 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5059 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5060 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5061 srcLeft = pSourceRect ? pSourceRect->left : 0;
5062 destLeft = pDestPoint ? pDestPoint->x : 0;
5063 destTop = pDestPoint ? pDestPoint->y : 0;
5066 /* This function doesn't support compressed textures
5067 the pitch is just bytesPerPixel * width */
5068 if(srcWidth != srcSurfaceWidth || srcLeft ){
5069 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5070 offset += srcLeft * pSrcSurface->bytesPerPixel;
5071 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5073 /* TODO DXT formats */
5075 if(pSourceRect != NULL && pSourceRect->top != 0){
5076 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5078 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5079 ,This
5080 ,glDescription->level
5081 ,destLeft
5082 ,destTop
5083 ,srcWidth
5084 ,srcHeight
5085 ,glDescription->glFormat
5086 ,glDescription->glType
5087 ,IWineD3DSurface_GetData(pSourceSurface)
5090 /* Sanity check */
5091 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5093 /* need to lock the surface to get the data */
5094 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5097 /* TODO: Cube and volume support */
5098 if(rowoffset != 0){
5099 /* not a whole row so we have to do it a line at a time */
5100 int j;
5102 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5103 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5105 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5107 glTexSubImage2D(glDescription->target
5108 ,glDescription->level
5109 ,destLeft
5111 ,srcWidth
5113 ,glDescription->glFormat
5114 ,glDescription->glType
5115 ,data /* could be quicker using */
5117 data += rowoffset;
5120 } else { /* Full width, so just write out the whole texture */
5122 if (WINED3DFMT_DXT1 == destFormat ||
5123 WINED3DFMT_DXT2 == destFormat ||
5124 WINED3DFMT_DXT3 == destFormat ||
5125 WINED3DFMT_DXT4 == destFormat ||
5126 WINED3DFMT_DXT5 == destFormat) {
5127 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5128 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5129 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5130 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5131 } if (destFormat != srcFormat) {
5132 FIXME("Updating mixed format compressed texture is not curretly support\n");
5133 } else {
5134 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5135 glDescription->level,
5136 glDescription->glFormatInternal,
5137 srcWidth,
5138 srcHeight,
5140 destSize,
5141 IWineD3DSurface_GetData(pSourceSurface));
5143 } else {
5144 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5148 } else {
5149 glTexSubImage2D(glDescription->target
5150 ,glDescription->level
5151 ,destLeft
5152 ,destTop
5153 ,srcWidth
5154 ,srcHeight
5155 ,glDescription->glFormat
5156 ,glDescription->glType
5157 ,IWineD3DSurface_GetData(pSourceSurface)
5161 checkGLcall("glTexSubImage2D");
5163 LEAVE_GL();
5165 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5166 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5169 return WINED3D_OK;
5172 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5174 struct WineD3DRectPatch *patch;
5175 unsigned int i;
5176 struct list *e;
5177 BOOL found;
5178 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5180 if(!(Handle || pRectPatchInfo)) {
5181 /* TODO: Write a test for the return value, thus the FIXME */
5182 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5183 return WINED3DERR_INVALIDCALL;
5186 if(Handle) {
5187 i = PATCHMAP_HASHFUNC(Handle);
5188 found = FALSE;
5189 LIST_FOR_EACH(e, &This->patches[i]) {
5190 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5191 if(patch->Handle == Handle) {
5192 found = TRUE;
5193 break;
5197 if(!found) {
5198 TRACE("Patch does not exist. Creating a new one\n");
5199 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5200 patch->Handle = Handle;
5201 list_add_head(&This->patches[i], &patch->entry);
5202 } else {
5203 TRACE("Found existing patch %p\n", patch);
5205 } else {
5206 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5207 * attributes we have to tesselate, read back, and draw. This needs a patch
5208 * management structure instance. Create one.
5210 * A possible improvement is to check if a vertex shader is used, and if not directly
5211 * draw the patch.
5213 FIXME("Drawing an uncached patch. This is slow\n");
5214 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5217 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5218 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5219 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5220 HRESULT hr;
5221 TRACE("Tesselation density or patch info changed, retesselating\n");
5223 if(pRectPatchInfo) {
5224 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5226 patch->numSegs[0] = pNumSegs[0];
5227 patch->numSegs[1] = pNumSegs[1];
5228 patch->numSegs[2] = pNumSegs[2];
5229 patch->numSegs[3] = pNumSegs[3];
5231 hr = tesselate_rectpatch(This, patch);
5232 if(FAILED(hr)) {
5233 WARN("Patch tesselation failed\n");
5235 /* Do not release the handle to store the params of the patch */
5236 if(!Handle) {
5237 HeapFree(GetProcessHeap(), 0, patch);
5239 return hr;
5243 This->currentPatch = patch;
5244 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5245 This->currentPatch = NULL;
5247 /* Destroy uncached patches */
5248 if(!Handle) {
5249 HeapFree(GetProcessHeap(), 0, patch->mem);
5250 HeapFree(GetProcessHeap(), 0, patch);
5252 return WINED3D_OK;
5255 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5256 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5258 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5259 FIXME("(%p) : Stub\n", This);
5260 return WINED3D_OK;
5263 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5265 int i;
5266 struct WineD3DRectPatch *patch;
5267 struct list *e;
5268 TRACE("(%p) Handle(%d)\n", This, Handle);
5270 i = PATCHMAP_HASHFUNC(Handle);
5271 LIST_FOR_EACH(e, &This->patches[i]) {
5272 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5273 if(patch->Handle == Handle) {
5274 TRACE("Deleting patch %p\n", patch);
5275 list_remove(&patch->entry);
5276 HeapFree(GetProcessHeap(), 0, patch->mem);
5277 HeapFree(GetProcessHeap(), 0, patch);
5278 return WINED3D_OK;
5282 /* TODO: Write a test for the return value */
5283 FIXME("Attempt to destroy nonexistant patch\n");
5284 return WINED3DERR_INVALIDCALL;
5287 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5288 HRESULT hr;
5289 IWineD3DSwapChain *swapchain;
5291 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5292 if (SUCCEEDED(hr)) {
5293 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5294 return swapchain;
5297 return NULL;
5300 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5303 if (!*fbo) {
5304 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5305 checkGLcall("glGenFramebuffersEXT()");
5307 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5308 checkGLcall("glBindFramebuffer()");
5311 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5312 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5313 IWineD3DBaseTextureImpl *texture_impl;
5314 GLenum texttarget, target;
5315 GLint old_binding;
5317 texttarget = surface_impl->glDescription.target;
5318 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5319 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5321 IWineD3DSurface_PreLoad(surface);
5323 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5324 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5325 glBindTexture(target, old_binding);
5327 /* Update base texture states array */
5328 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5329 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5330 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5331 if (texture_impl->baseTexture.bindCount) {
5332 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5335 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5338 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5340 checkGLcall("attach_surface_fbo");
5343 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5345 IWineD3DSwapChain *swapchain;
5347 swapchain = get_swapchain(surface);
5348 if (swapchain) {
5349 GLenum buffer;
5351 TRACE("Surface %p is onscreen\n", surface);
5353 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5354 buffer = surface_get_gl_buffer(surface, swapchain);
5355 glDrawBuffer(buffer);
5356 checkGLcall("glDrawBuffer()");
5357 } else {
5358 TRACE("Surface %p is offscreen\n", surface);
5359 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5360 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5363 if (rect) {
5364 glEnable(GL_SCISSOR_TEST);
5365 if(!swapchain) {
5366 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5367 } else {
5368 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5369 rect->x2 - rect->x1, rect->y2 - rect->y1);
5371 checkGLcall("glScissor");
5372 } else {
5373 glDisable(GL_SCISSOR_TEST);
5375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5377 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5380 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5381 glClear(GL_COLOR_BUFFER_BIT);
5382 checkGLcall("glClear");
5384 if (This->render_offscreen) {
5385 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5386 } else {
5387 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5388 checkGLcall("glBindFramebuffer()");
5391 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5392 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5393 glDrawBuffer(GL_BACK);
5394 checkGLcall("glDrawBuffer()");
5398 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5400 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5401 WINEDDBLTFX BltFx;
5402 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5404 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5405 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5406 return WINED3DERR_INVALIDCALL;
5409 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5410 color_fill_fbo(iface, pSurface, pRect, color);
5411 return WINED3D_OK;
5412 } else {
5413 /* Just forward this to the DirectDraw blitting engine */
5414 memset(&BltFx, 0, sizeof(BltFx));
5415 BltFx.dwSize = sizeof(BltFx);
5416 BltFx.u5.dwFillColor = color;
5417 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5421 /* rendertarget and deptth stencil functions */
5422 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5425 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5426 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5427 return WINED3DERR_INVALIDCALL;
5430 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5431 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5432 /* Note inc ref on returned surface */
5433 if(*ppRenderTarget != NULL)
5434 IWineD3DSurface_AddRef(*ppRenderTarget);
5435 return WINED3D_OK;
5438 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5440 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5441 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5442 IWineD3DSwapChainImpl *Swapchain;
5443 HRESULT hr;
5445 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5447 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5448 if(hr != WINED3D_OK) {
5449 ERR("Can't get the swapchain\n");
5450 return hr;
5453 /* Make sure to release the swapchain */
5454 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5456 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5457 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5458 return WINED3DERR_INVALIDCALL;
5460 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5461 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5462 return WINED3DERR_INVALIDCALL;
5465 if(Swapchain->frontBuffer != Front) {
5466 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5468 if(Swapchain->frontBuffer)
5469 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5470 Swapchain->frontBuffer = Front;
5472 if(Swapchain->frontBuffer) {
5473 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5477 if(Back && !Swapchain->backBuffer) {
5478 /* We need memory for the back buffer array - only one back buffer this way */
5479 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5480 if(!Swapchain->backBuffer) {
5481 ERR("Out of memory\n");
5482 return E_OUTOFMEMORY;
5486 if(Swapchain->backBuffer[0] != Back) {
5487 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5489 /* What to do about the context here in the case of multithreading? Not sure.
5490 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5492 ENTER_GL();
5493 if(!Swapchain->backBuffer[0]) {
5494 /* GL was told to draw to the front buffer at creation,
5495 * undo that
5497 glDrawBuffer(GL_BACK);
5498 checkGLcall("glDrawBuffer(GL_BACK)");
5499 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5500 Swapchain->presentParms.BackBufferCount = 1;
5501 } else if (!Back) {
5502 /* That makes problems - disable for now */
5503 /* glDrawBuffer(GL_FRONT); */
5504 checkGLcall("glDrawBuffer(GL_FRONT)");
5505 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5506 Swapchain->presentParms.BackBufferCount = 0;
5508 LEAVE_GL();
5510 if(Swapchain->backBuffer[0])
5511 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5512 Swapchain->backBuffer[0] = Back;
5514 if(Swapchain->backBuffer[0]) {
5515 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5516 } else {
5517 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5522 return WINED3D_OK;
5525 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5527 *ppZStencilSurface = This->depthStencilBuffer;
5528 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5530 if(*ppZStencilSurface != NULL) {
5531 /* Note inc ref on returned surface */
5532 IWineD3DSurface_AddRef(*ppZStencilSurface);
5534 return WINED3D_OK;
5537 /* TODO: Handle stencil attachments */
5538 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5540 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5542 TRACE("Set depth stencil to %p\n", depth_stencil);
5544 if (depth_stencil_impl) {
5545 if (depth_stencil_impl->current_renderbuffer) {
5546 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5547 checkGLcall("glFramebufferRenderbufferEXT()");
5548 } else {
5549 IWineD3DBaseTextureImpl *texture_impl;
5550 GLenum texttarget, target;
5551 GLint old_binding = 0;
5553 texttarget = depth_stencil_impl->glDescription.target;
5554 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5555 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5557 IWineD3DSurface_PreLoad(depth_stencil);
5559 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5560 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5561 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5562 glBindTexture(target, old_binding);
5564 /* Update base texture states array */
5565 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5566 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5567 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5568 if (texture_impl->baseTexture.bindCount) {
5569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5572 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5575 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5576 checkGLcall("glFramebufferTexture2DEXT()");
5578 } else {
5579 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5580 checkGLcall("glFramebufferTexture2DEXT()");
5584 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5586 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5588 TRACE("Set render target %u to %p\n", idx, render_target);
5590 if (rtimpl) {
5591 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5592 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5593 } else {
5594 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5595 checkGLcall("glFramebufferTexture2DEXT()");
5597 This->draw_buffers[idx] = GL_NONE;
5601 static void check_fbo_status(IWineD3DDevice *iface) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 GLenum status;
5605 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5606 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5607 TRACE("FBO complete\n");
5608 } else {
5609 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5611 /* Dump the FBO attachments */
5612 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5613 IWineD3DSurfaceImpl *attachment;
5614 int i;
5616 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5617 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5618 if (attachment) {
5619 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5620 attachment->pow2Width, attachment->pow2Height);
5623 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5624 if (attachment) {
5625 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5626 attachment->pow2Width, attachment->pow2Height);
5632 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5634 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5635 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5637 if (!ds_impl) return FALSE;
5639 if (ds_impl->current_renderbuffer) {
5640 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5641 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5644 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5645 rt_impl->pow2Height != ds_impl->pow2Height);
5648 void apply_fbo_state(IWineD3DDevice *iface) {
5649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5650 unsigned int i;
5652 if (This->render_offscreen) {
5653 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5655 /* Apply render targets */
5656 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5657 IWineD3DSurface *render_target = This->render_targets[i];
5658 if (This->fbo_color_attachments[i] != render_target) {
5659 set_render_target_fbo(iface, i, render_target);
5660 This->fbo_color_attachments[i] = render_target;
5664 /* Apply depth targets */
5665 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5666 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5667 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5669 if (This->stencilBufferTarget) {
5670 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5672 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5673 This->fbo_depth_attachment = This->stencilBufferTarget;
5676 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5677 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5678 checkGLcall("glDrawBuffers()");
5679 } else {
5680 glDrawBuffer(This->draw_buffers[0]);
5681 checkGLcall("glDrawBuffer()");
5683 } else {
5684 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5687 check_fbo_status(iface);
5690 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5691 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5693 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5694 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5695 GLenum gl_filter;
5697 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5698 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5699 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5700 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5702 switch (filter) {
5703 case WINED3DTEXF_LINEAR:
5704 gl_filter = GL_LINEAR;
5705 break;
5707 default:
5708 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5709 case WINED3DTEXF_NONE:
5710 case WINED3DTEXF_POINT:
5711 gl_filter = GL_NEAREST;
5712 break;
5715 /* Attach src surface to src fbo */
5716 src_swapchain = get_swapchain(src_surface);
5717 if (src_swapchain) {
5718 GLenum buffer;
5720 TRACE("Source surface %p is onscreen\n", src_surface);
5721 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5723 ENTER_GL();
5724 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5725 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5726 glReadBuffer(buffer);
5727 checkGLcall("glReadBuffer()");
5729 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5730 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5731 } else {
5732 TRACE("Source surface %p is offscreen\n", src_surface);
5733 ENTER_GL();
5734 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5735 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5736 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5737 checkGLcall("glReadBuffer()");
5739 LEAVE_GL();
5741 /* Attach dst surface to dst fbo */
5742 dst_swapchain = get_swapchain(dst_surface);
5743 if (dst_swapchain) {
5744 GLenum buffer;
5746 TRACE("Destination surface %p is onscreen\n", dst_surface);
5747 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5749 ENTER_GL();
5750 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5751 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5752 glDrawBuffer(buffer);
5753 checkGLcall("glDrawBuffer()");
5755 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5756 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5757 } else {
5758 TRACE("Destination surface %p is offscreen\n", dst_surface);
5760 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5761 if(!src_swapchain) {
5762 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5765 ENTER_GL();
5766 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5767 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5768 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5769 checkGLcall("glDrawBuffer()");
5771 glDisable(GL_SCISSOR_TEST);
5772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5774 if (flip) {
5775 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5776 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5777 checkGLcall("glBlitFramebuffer()");
5778 } else {
5779 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5780 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5781 checkGLcall("glBlitFramebuffer()");
5784 if (This->render_offscreen) {
5785 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5786 } else {
5787 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5788 checkGLcall("glBindFramebuffer()");
5791 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5792 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5793 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5794 glDrawBuffer(GL_BACK);
5795 checkGLcall("glDrawBuffer()");
5797 LEAVE_GL();
5800 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5802 WINED3DVIEWPORT viewport;
5804 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5806 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5807 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5808 return WINED3DERR_INVALIDCALL;
5811 /* MSDN says that null disables the render target
5812 but a device must always be associated with a render target
5813 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5815 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5816 for more details
5818 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5819 FIXME("Trying to set render target 0 to NULL\n");
5820 return WINED3DERR_INVALIDCALL;
5822 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5823 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);
5824 return WINED3DERR_INVALIDCALL;
5827 /* If we are trying to set what we already have, don't bother */
5828 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5829 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5830 return WINED3D_OK;
5832 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5833 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5834 This->render_targets[RenderTargetIndex] = pRenderTarget;
5836 /* Render target 0 is special */
5837 if(RenderTargetIndex == 0) {
5838 /* Finally, reset the viewport as the MSDN states. */
5839 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5840 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5841 viewport.X = 0;
5842 viewport.Y = 0;
5843 viewport.MaxZ = 1.0f;
5844 viewport.MinZ = 0.0f;
5845 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5846 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5847 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5851 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5852 * ctx properly.
5853 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5854 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5856 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5858 return WINED3D_OK;
5861 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5863 HRESULT hr = WINED3D_OK;
5864 IWineD3DSurface *tmp;
5866 TRACE("(%p) Swapping z-buffer\n",This);
5868 if (pNewZStencil == This->stencilBufferTarget) {
5869 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5870 } else {
5871 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5872 * depending on the renter target implementation being used.
5873 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5874 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5875 * stencil buffer and incure an extra memory overhead
5876 ******************************************************/
5878 tmp = This->stencilBufferTarget;
5879 This->stencilBufferTarget = pNewZStencil;
5880 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5881 /* should we be calling the parent or the wined3d surface? */
5882 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5883 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5884 hr = WINED3D_OK;
5886 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5887 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5888 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5890 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5894 return hr;
5897 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5898 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5900 /* TODO: the use of Impl is deprecated. */
5901 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5902 WINED3DLOCKED_RECT lockedRect;
5904 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5906 /* some basic validation checks */
5907 if(This->cursorTexture) {
5908 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5909 ENTER_GL();
5910 glDeleteTextures(1, &This->cursorTexture);
5911 LEAVE_GL();
5912 This->cursorTexture = 0;
5915 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5916 This->haveHardwareCursor = TRUE;
5917 else
5918 This->haveHardwareCursor = FALSE;
5920 if(pCursorBitmap) {
5921 WINED3DLOCKED_RECT rect;
5923 /* MSDN: Cursor must be A8R8G8B8 */
5924 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5925 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5926 return WINED3DERR_INVALIDCALL;
5929 /* MSDN: Cursor must be smaller than the display mode */
5930 if(pSur->currentDesc.Width > This->ddraw_width ||
5931 pSur->currentDesc.Height > This->ddraw_height) {
5932 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);
5933 return WINED3DERR_INVALIDCALL;
5936 if (!This->haveHardwareCursor) {
5937 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5939 /* Do not store the surface's pointer because the application may
5940 * release it after setting the cursor image. Windows doesn't
5941 * addref the set surface, so we can't do this either without
5942 * creating circular refcount dependencies. Copy out the gl texture
5943 * instead.
5945 This->cursorWidth = pSur->currentDesc.Width;
5946 This->cursorHeight = pSur->currentDesc.Height;
5947 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5949 const GlPixelFormatDesc *glDesc;
5950 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
5951 char *mem, *bits = (char *)rect.pBits;
5952 GLint intfmt = glDesc->glInternal;
5953 GLint format = glDesc->glFormat;
5954 GLint type = glDesc->glType;
5955 INT height = This->cursorHeight;
5956 INT width = This->cursorWidth;
5957 INT bpp = tableEntry->bpp;
5958 INT i;
5960 /* Reformat the texture memory (pitch and width can be
5961 * different) */
5962 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5963 for(i = 0; i < height; i++)
5964 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5965 IWineD3DSurface_UnlockRect(pCursorBitmap);
5966 ENTER_GL();
5968 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5969 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5970 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5973 /* Make sure that a proper texture unit is selected */
5974 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5975 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5976 checkGLcall("glActiveTextureARB");
5978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5979 /* Create a new cursor texture */
5980 glGenTextures(1, &This->cursorTexture);
5981 checkGLcall("glGenTextures");
5982 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5983 checkGLcall("glBindTexture");
5984 /* Copy the bitmap memory into the cursor texture */
5985 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5986 HeapFree(GetProcessHeap(), 0, mem);
5987 checkGLcall("glTexImage2D");
5989 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5990 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5991 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5994 LEAVE_GL();
5996 else
5998 FIXME("A cursor texture was not returned.\n");
5999 This->cursorTexture = 0;
6002 else
6004 /* Draw a hardware cursor */
6005 ICONINFO cursorInfo;
6006 HCURSOR cursor;
6007 /* Create and clear maskBits because it is not needed for
6008 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6009 * chunks. */
6010 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6011 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6012 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6013 WINED3DLOCK_NO_DIRTY_UPDATE |
6014 WINED3DLOCK_READONLY
6016 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6017 pSur->currentDesc.Height);
6019 cursorInfo.fIcon = FALSE;
6020 cursorInfo.xHotspot = XHotSpot;
6021 cursorInfo.yHotspot = YHotSpot;
6022 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6023 pSur->currentDesc.Height, 1,
6024 1, &maskBits);
6025 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6026 pSur->currentDesc.Height, 1,
6027 32, lockedRect.pBits);
6028 IWineD3DSurface_UnlockRect(pCursorBitmap);
6029 /* Create our cursor and clean up. */
6030 cursor = CreateIconIndirect(&cursorInfo);
6031 SetCursor(cursor);
6032 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6033 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6034 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6035 This->hardwareCursor = cursor;
6036 HeapFree(GetProcessHeap(), 0, maskBits);
6040 This->xHotSpot = XHotSpot;
6041 This->yHotSpot = YHotSpot;
6042 return WINED3D_OK;
6045 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6047 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6049 This->xScreenSpace = XScreenSpace;
6050 This->yScreenSpace = YScreenSpace;
6052 return;
6056 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6058 BOOL oldVisible = This->bCursorVisible;
6059 POINT pt;
6061 TRACE("(%p) : visible(%d)\n", This, bShow);
6064 * When ShowCursor is first called it should make the cursor appear at the OS's last
6065 * known cursor position. Because of this, some applications just repetitively call
6066 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6068 GetCursorPos(&pt);
6069 This->xScreenSpace = pt.x;
6070 This->yScreenSpace = pt.y;
6072 if (This->haveHardwareCursor) {
6073 This->bCursorVisible = bShow;
6074 if (bShow)
6075 SetCursor(This->hardwareCursor);
6076 else
6077 SetCursor(NULL);
6079 else
6081 if (This->cursorTexture)
6082 This->bCursorVisible = bShow;
6085 return oldVisible;
6088 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6090 TRACE("(%p) : state (%u)\n", This, This->state);
6091 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6092 switch (This->state) {
6093 case WINED3D_OK:
6094 return WINED3D_OK;
6095 case WINED3DERR_DEVICELOST:
6097 ResourceList *resourceList = This->resources;
6098 while (NULL != resourceList) {
6099 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6100 return WINED3DERR_DEVICENOTRESET;
6101 resourceList = resourceList->next;
6103 return WINED3DERR_DEVICELOST;
6105 case WINED3DERR_DRIVERINTERNALERROR:
6106 return WINED3DERR_DRIVERINTERNALERROR;
6109 /* Unknown state */
6110 return WINED3DERR_DRIVERINTERNALERROR;
6114 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6116 /** FIXME: Resource tracking needs to be done,
6117 * The closes we can do to this is set the priorities of all managed textures low
6118 * and then reset them.
6119 ***********************************************************/
6120 FIXME("(%p) : stub\n", This);
6121 return WINED3D_OK;
6124 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6125 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6127 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6128 if(surface->Flags & SFLAG_DIBSECTION) {
6129 /* Release the DC */
6130 SelectObject(surface->hDC, surface->dib.holdbitmap);
6131 DeleteDC(surface->hDC);
6132 /* Release the DIB section */
6133 DeleteObject(surface->dib.DIBsection);
6134 surface->dib.bitmap_data = NULL;
6135 surface->resource.allocatedMemory = NULL;
6136 surface->Flags &= ~SFLAG_DIBSECTION;
6138 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6139 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6140 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6141 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6142 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6143 } else {
6144 surface->pow2Width = surface->pow2Height = 1;
6145 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6146 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6148 if(surface->glDescription.textureName) {
6149 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6150 ENTER_GL();
6151 glDeleteTextures(1, &surface->glDescription.textureName);
6152 LEAVE_GL();
6153 surface->glDescription.textureName = 0;
6154 surface->Flags &= ~SFLAG_CLIENT;
6156 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6157 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6158 surface->Flags |= SFLAG_NONPOW2;
6159 } else {
6160 surface->Flags &= ~SFLAG_NONPOW2;
6162 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6163 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6166 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6168 IWineD3DSwapChainImpl *swapchain;
6169 HRESULT hr;
6170 BOOL DisplayModeChanged = FALSE;
6171 WINED3DDISPLAYMODE mode;
6172 TRACE("(%p)\n", This);
6174 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6175 if(FAILED(hr)) {
6176 ERR("Failed to get the first implicit swapchain\n");
6177 return hr;
6180 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6181 * on an existing gl context, so there's no real need for recreation.
6183 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6185 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6187 TRACE("New params:\n");
6188 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6189 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6190 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6191 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6192 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6193 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6194 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6195 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6196 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6197 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6198 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6199 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6200 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6202 /* No special treatment of these parameters. Just store them */
6203 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6204 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6205 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6206 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6208 /* What to do about these? */
6209 if(pPresentationParameters->BackBufferCount != 0 &&
6210 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6211 ERR("Cannot change the back buffer count yet\n");
6213 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6214 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6215 ERR("Cannot change the back buffer format yet\n");
6217 if(pPresentationParameters->hDeviceWindow != NULL &&
6218 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6219 ERR("Cannot change the device window yet\n");
6221 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6222 ERR("What do do about a changed auto depth stencil parameter?\n");
6225 if(pPresentationParameters->Windowed) {
6226 mode.Width = swapchain->orig_width;
6227 mode.Height = swapchain->orig_height;
6228 mode.RefreshRate = 0;
6229 mode.Format = swapchain->presentParms.BackBufferFormat;
6230 } else {
6231 mode.Width = pPresentationParameters->BackBufferWidth;
6232 mode.Height = pPresentationParameters->BackBufferHeight;
6233 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6234 mode.Format = swapchain->presentParms.BackBufferFormat;
6237 /* Should Width == 800 && Height == 0 set 800x600? */
6238 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6239 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6240 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6242 WINED3DVIEWPORT vp;
6243 int i;
6245 vp.X = 0;
6246 vp.Y = 0;
6247 vp.Width = pPresentationParameters->BackBufferWidth;
6248 vp.Height = pPresentationParameters->BackBufferHeight;
6249 vp.MinZ = 0;
6250 vp.MaxZ = 1;
6252 if(!pPresentationParameters->Windowed) {
6253 DisplayModeChanged = TRUE;
6255 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6256 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6258 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6259 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6260 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6263 /* Now set the new viewport */
6264 IWineD3DDevice_SetViewport(iface, &vp);
6267 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6268 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6269 DisplayModeChanged) {
6271 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6272 if(!pPresentationParameters->Windowed) {
6273 IWineD3DDevice_SetFullscreen(iface, TRUE);
6276 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6278 /* Switching out of fullscreen mode? First set the original res, then change the window */
6279 if(pPresentationParameters->Windowed) {
6280 IWineD3DDevice_SetFullscreen(iface, FALSE);
6282 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6285 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6286 return WINED3D_OK;
6289 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6291 /** FIXME: always true at the moment **/
6292 if(!bEnableDialogs) {
6293 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6295 return WINED3D_OK;
6299 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6301 TRACE("(%p) : pParameters %p\n", This, pParameters);
6303 *pParameters = This->createParms;
6304 return WINED3D_OK;
6307 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6308 IWineD3DSwapChain *swapchain;
6309 HRESULT hrc = WINED3D_OK;
6311 TRACE("Relaying to swapchain\n");
6313 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6314 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6315 IWineD3DSwapChain_Release(swapchain);
6317 return;
6320 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6321 IWineD3DSwapChain *swapchain;
6322 HRESULT hrc = WINED3D_OK;
6324 TRACE("Relaying to swapchain\n");
6326 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6327 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6328 IWineD3DSwapChain_Release(swapchain);
6330 return;
6334 /** ********************************************************
6335 * Notification functions
6336 ** ********************************************************/
6337 /** This function must be called in the release of a resource when ref == 0,
6338 * the contents of resource must still be correct,
6339 * any handels to other resource held by the caller must be closed
6340 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6341 *****************************************************/
6342 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6344 ResourceList* resourceList;
6346 TRACE("(%p) : resource %p\n", This, resource);
6347 /* add a new texture to the frot of the linked list */
6348 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6349 resourceList->resource = resource;
6351 /* Get the old head */
6352 resourceList->next = This->resources;
6354 This->resources = resourceList;
6355 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6357 return;
6360 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6362 ResourceList* resourceList = NULL;
6363 ResourceList* previousResourceList = NULL;
6365 TRACE("(%p) : resource %p\n", This, resource);
6367 resourceList = This->resources;
6369 while (resourceList != NULL) {
6370 if(resourceList->resource == resource) break;
6371 previousResourceList = resourceList;
6372 resourceList = resourceList->next;
6375 if (resourceList == NULL) {
6376 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6377 return;
6378 } else {
6379 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6381 /* make sure we don't leave a hole in the list */
6382 if (previousResourceList != NULL) {
6383 previousResourceList->next = resourceList->next;
6384 } else {
6385 This->resources = resourceList->next;
6388 return;
6392 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6394 int counter;
6396 TRACE("(%p) : resource %p\n", This, resource);
6397 switch(IWineD3DResource_GetType(resource)){
6398 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6399 case WINED3DRTYPE_SURFACE: {
6400 unsigned int i;
6402 /* Cleanup any FBO attachments if d3d is enabled */
6403 if(This->d3d_initialized) {
6404 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6405 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6406 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6407 set_render_target_fbo(iface, i, NULL);
6408 This->fbo_color_attachments[i] = NULL;
6411 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6412 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6413 set_depth_stencil_fbo(iface, NULL);
6414 This->fbo_depth_attachment = NULL;
6418 break;
6420 case WINED3DRTYPE_TEXTURE:
6421 case WINED3DRTYPE_CUBETEXTURE:
6422 case WINED3DRTYPE_VOLUMETEXTURE:
6423 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6424 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6425 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6426 This->stateBlock->textures[counter] = NULL;
6428 if (This->updateStateBlock != This->stateBlock ){
6429 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6430 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6431 This->updateStateBlock->textures[counter] = NULL;
6435 break;
6436 case WINED3DRTYPE_VOLUME:
6437 /* TODO: nothing really? */
6438 break;
6439 case WINED3DRTYPE_VERTEXBUFFER:
6440 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6442 int streamNumber;
6443 TRACE("Cleaning up stream pointers\n");
6445 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6446 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6447 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6449 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6450 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6451 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6452 This->updateStateBlock->streamSource[streamNumber] = 0;
6453 /* Set changed flag? */
6456 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) */
6457 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6458 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6459 This->stateBlock->streamSource[streamNumber] = 0;
6462 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6463 else { /* This shouldn't happen */
6464 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6466 #endif
6470 break;
6471 case WINED3DRTYPE_INDEXBUFFER:
6472 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6473 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6474 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6475 This->updateStateBlock->pIndexData = NULL;
6478 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6479 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6480 This->stateBlock->pIndexData = NULL;
6484 break;
6485 default:
6486 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6487 break;
6491 /* Remove the resoruce from the resourceStore */
6492 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6494 TRACE("Resource released\n");
6498 /**********************************************************
6499 * IWineD3DDevice VTbl follows
6500 **********************************************************/
6502 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6504 /*** IUnknown methods ***/
6505 IWineD3DDeviceImpl_QueryInterface,
6506 IWineD3DDeviceImpl_AddRef,
6507 IWineD3DDeviceImpl_Release,
6508 /*** IWineD3DDevice methods ***/
6509 IWineD3DDeviceImpl_GetParent,
6510 /*** Creation methods**/
6511 IWineD3DDeviceImpl_CreateVertexBuffer,
6512 IWineD3DDeviceImpl_CreateIndexBuffer,
6513 IWineD3DDeviceImpl_CreateStateBlock,
6514 IWineD3DDeviceImpl_CreateSurface,
6515 IWineD3DDeviceImpl_CreateTexture,
6516 IWineD3DDeviceImpl_CreateVolumeTexture,
6517 IWineD3DDeviceImpl_CreateVolume,
6518 IWineD3DDeviceImpl_CreateCubeTexture,
6519 IWineD3DDeviceImpl_CreateQuery,
6520 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6521 IWineD3DDeviceImpl_CreateVertexDeclaration,
6522 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6523 IWineD3DDeviceImpl_CreateVertexShader,
6524 IWineD3DDeviceImpl_CreatePixelShader,
6525 IWineD3DDeviceImpl_CreatePalette,
6526 /*** Odd functions **/
6527 IWineD3DDeviceImpl_Init3D,
6528 IWineD3DDeviceImpl_Uninit3D,
6529 IWineD3DDeviceImpl_SetFullscreen,
6530 IWineD3DDeviceImpl_SetMultithreaded,
6531 IWineD3DDeviceImpl_EvictManagedResources,
6532 IWineD3DDeviceImpl_GetAvailableTextureMem,
6533 IWineD3DDeviceImpl_GetBackBuffer,
6534 IWineD3DDeviceImpl_GetCreationParameters,
6535 IWineD3DDeviceImpl_GetDeviceCaps,
6536 IWineD3DDeviceImpl_GetDirect3D,
6537 IWineD3DDeviceImpl_GetDisplayMode,
6538 IWineD3DDeviceImpl_SetDisplayMode,
6539 IWineD3DDeviceImpl_GetHWND,
6540 IWineD3DDeviceImpl_SetHWND,
6541 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6542 IWineD3DDeviceImpl_GetRasterStatus,
6543 IWineD3DDeviceImpl_GetSwapChain,
6544 IWineD3DDeviceImpl_Reset,
6545 IWineD3DDeviceImpl_SetDialogBoxMode,
6546 IWineD3DDeviceImpl_SetCursorProperties,
6547 IWineD3DDeviceImpl_SetCursorPosition,
6548 IWineD3DDeviceImpl_ShowCursor,
6549 IWineD3DDeviceImpl_TestCooperativeLevel,
6550 /*** Getters and setters **/
6551 IWineD3DDeviceImpl_SetClipPlane,
6552 IWineD3DDeviceImpl_GetClipPlane,
6553 IWineD3DDeviceImpl_SetClipStatus,
6554 IWineD3DDeviceImpl_GetClipStatus,
6555 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6556 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6557 IWineD3DDeviceImpl_SetDepthStencilSurface,
6558 IWineD3DDeviceImpl_GetDepthStencilSurface,
6559 IWineD3DDeviceImpl_SetFVF,
6560 IWineD3DDeviceImpl_GetFVF,
6561 IWineD3DDeviceImpl_SetGammaRamp,
6562 IWineD3DDeviceImpl_GetGammaRamp,
6563 IWineD3DDeviceImpl_SetIndices,
6564 IWineD3DDeviceImpl_GetIndices,
6565 IWineD3DDeviceImpl_SetBaseVertexIndex,
6566 IWineD3DDeviceImpl_GetBaseVertexIndex,
6567 IWineD3DDeviceImpl_SetLight,
6568 IWineD3DDeviceImpl_GetLight,
6569 IWineD3DDeviceImpl_SetLightEnable,
6570 IWineD3DDeviceImpl_GetLightEnable,
6571 IWineD3DDeviceImpl_SetMaterial,
6572 IWineD3DDeviceImpl_GetMaterial,
6573 IWineD3DDeviceImpl_SetNPatchMode,
6574 IWineD3DDeviceImpl_GetNPatchMode,
6575 IWineD3DDeviceImpl_SetPaletteEntries,
6576 IWineD3DDeviceImpl_GetPaletteEntries,
6577 IWineD3DDeviceImpl_SetPixelShader,
6578 IWineD3DDeviceImpl_GetPixelShader,
6579 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6580 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6581 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6582 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6583 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6584 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6585 IWineD3DDeviceImpl_SetRenderState,
6586 IWineD3DDeviceImpl_GetRenderState,
6587 IWineD3DDeviceImpl_SetRenderTarget,
6588 IWineD3DDeviceImpl_GetRenderTarget,
6589 IWineD3DDeviceImpl_SetFrontBackBuffers,
6590 IWineD3DDeviceImpl_SetSamplerState,
6591 IWineD3DDeviceImpl_GetSamplerState,
6592 IWineD3DDeviceImpl_SetScissorRect,
6593 IWineD3DDeviceImpl_GetScissorRect,
6594 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6595 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6596 IWineD3DDeviceImpl_SetStreamSource,
6597 IWineD3DDeviceImpl_GetStreamSource,
6598 IWineD3DDeviceImpl_SetStreamSourceFreq,
6599 IWineD3DDeviceImpl_GetStreamSourceFreq,
6600 IWineD3DDeviceImpl_SetTexture,
6601 IWineD3DDeviceImpl_GetTexture,
6602 IWineD3DDeviceImpl_SetTextureStageState,
6603 IWineD3DDeviceImpl_GetTextureStageState,
6604 IWineD3DDeviceImpl_SetTransform,
6605 IWineD3DDeviceImpl_GetTransform,
6606 IWineD3DDeviceImpl_SetVertexDeclaration,
6607 IWineD3DDeviceImpl_GetVertexDeclaration,
6608 IWineD3DDeviceImpl_SetVertexShader,
6609 IWineD3DDeviceImpl_GetVertexShader,
6610 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6611 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6612 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6613 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6614 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6615 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6616 IWineD3DDeviceImpl_SetViewport,
6617 IWineD3DDeviceImpl_GetViewport,
6618 IWineD3DDeviceImpl_MultiplyTransform,
6619 IWineD3DDeviceImpl_ValidateDevice,
6620 IWineD3DDeviceImpl_ProcessVertices,
6621 /*** State block ***/
6622 IWineD3DDeviceImpl_BeginStateBlock,
6623 IWineD3DDeviceImpl_EndStateBlock,
6624 /*** Scene management ***/
6625 IWineD3DDeviceImpl_BeginScene,
6626 IWineD3DDeviceImpl_EndScene,
6627 IWineD3DDeviceImpl_Present,
6628 IWineD3DDeviceImpl_Clear,
6629 /*** Drawing ***/
6630 IWineD3DDeviceImpl_DrawPrimitive,
6631 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6632 IWineD3DDeviceImpl_DrawPrimitiveUP,
6633 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6634 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6635 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6636 IWineD3DDeviceImpl_DrawRectPatch,
6637 IWineD3DDeviceImpl_DrawTriPatch,
6638 IWineD3DDeviceImpl_DeletePatch,
6639 IWineD3DDeviceImpl_ColorFill,
6640 IWineD3DDeviceImpl_UpdateTexture,
6641 IWineD3DDeviceImpl_UpdateSurface,
6642 IWineD3DDeviceImpl_GetFrontBufferData,
6643 /*** object tracking ***/
6644 IWineD3DDeviceImpl_ResourceReleased
6648 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6649 WINED3DRS_ALPHABLENDENABLE ,
6650 WINED3DRS_ALPHAFUNC ,
6651 WINED3DRS_ALPHAREF ,
6652 WINED3DRS_ALPHATESTENABLE ,
6653 WINED3DRS_BLENDOP ,
6654 WINED3DRS_COLORWRITEENABLE ,
6655 WINED3DRS_DESTBLEND ,
6656 WINED3DRS_DITHERENABLE ,
6657 WINED3DRS_FILLMODE ,
6658 WINED3DRS_FOGDENSITY ,
6659 WINED3DRS_FOGEND ,
6660 WINED3DRS_FOGSTART ,
6661 WINED3DRS_LASTPIXEL ,
6662 WINED3DRS_SHADEMODE ,
6663 WINED3DRS_SRCBLEND ,
6664 WINED3DRS_STENCILENABLE ,
6665 WINED3DRS_STENCILFAIL ,
6666 WINED3DRS_STENCILFUNC ,
6667 WINED3DRS_STENCILMASK ,
6668 WINED3DRS_STENCILPASS ,
6669 WINED3DRS_STENCILREF ,
6670 WINED3DRS_STENCILWRITEMASK ,
6671 WINED3DRS_STENCILZFAIL ,
6672 WINED3DRS_TEXTUREFACTOR ,
6673 WINED3DRS_WRAP0 ,
6674 WINED3DRS_WRAP1 ,
6675 WINED3DRS_WRAP2 ,
6676 WINED3DRS_WRAP3 ,
6677 WINED3DRS_WRAP4 ,
6678 WINED3DRS_WRAP5 ,
6679 WINED3DRS_WRAP6 ,
6680 WINED3DRS_WRAP7 ,
6681 WINED3DRS_ZENABLE ,
6682 WINED3DRS_ZFUNC ,
6683 WINED3DRS_ZWRITEENABLE
6686 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6687 WINED3DTSS_ADDRESSW ,
6688 WINED3DTSS_ALPHAARG0 ,
6689 WINED3DTSS_ALPHAARG1 ,
6690 WINED3DTSS_ALPHAARG2 ,
6691 WINED3DTSS_ALPHAOP ,
6692 WINED3DTSS_BUMPENVLOFFSET ,
6693 WINED3DTSS_BUMPENVLSCALE ,
6694 WINED3DTSS_BUMPENVMAT00 ,
6695 WINED3DTSS_BUMPENVMAT01 ,
6696 WINED3DTSS_BUMPENVMAT10 ,
6697 WINED3DTSS_BUMPENVMAT11 ,
6698 WINED3DTSS_COLORARG0 ,
6699 WINED3DTSS_COLORARG1 ,
6700 WINED3DTSS_COLORARG2 ,
6701 WINED3DTSS_COLOROP ,
6702 WINED3DTSS_RESULTARG ,
6703 WINED3DTSS_TEXCOORDINDEX ,
6704 WINED3DTSS_TEXTURETRANSFORMFLAGS
6707 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6708 WINED3DSAMP_ADDRESSU ,
6709 WINED3DSAMP_ADDRESSV ,
6710 WINED3DSAMP_ADDRESSW ,
6711 WINED3DSAMP_BORDERCOLOR ,
6712 WINED3DSAMP_MAGFILTER ,
6713 WINED3DSAMP_MINFILTER ,
6714 WINED3DSAMP_MIPFILTER ,
6715 WINED3DSAMP_MIPMAPLODBIAS ,
6716 WINED3DSAMP_MAXMIPLEVEL ,
6717 WINED3DSAMP_MAXANISOTROPY ,
6718 WINED3DSAMP_SRGBTEXTURE ,
6719 WINED3DSAMP_ELEMENTINDEX
6722 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6723 WINED3DRS_AMBIENT ,
6724 WINED3DRS_AMBIENTMATERIALSOURCE ,
6725 WINED3DRS_CLIPPING ,
6726 WINED3DRS_CLIPPLANEENABLE ,
6727 WINED3DRS_COLORVERTEX ,
6728 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6729 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6730 WINED3DRS_FOGDENSITY ,
6731 WINED3DRS_FOGEND ,
6732 WINED3DRS_FOGSTART ,
6733 WINED3DRS_FOGTABLEMODE ,
6734 WINED3DRS_FOGVERTEXMODE ,
6735 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6736 WINED3DRS_LIGHTING ,
6737 WINED3DRS_LOCALVIEWER ,
6738 WINED3DRS_MULTISAMPLEANTIALIAS ,
6739 WINED3DRS_MULTISAMPLEMASK ,
6740 WINED3DRS_NORMALIZENORMALS ,
6741 WINED3DRS_PATCHEDGESTYLE ,
6742 WINED3DRS_POINTSCALE_A ,
6743 WINED3DRS_POINTSCALE_B ,
6744 WINED3DRS_POINTSCALE_C ,
6745 WINED3DRS_POINTSCALEENABLE ,
6746 WINED3DRS_POINTSIZE ,
6747 WINED3DRS_POINTSIZE_MAX ,
6748 WINED3DRS_POINTSIZE_MIN ,
6749 WINED3DRS_POINTSPRITEENABLE ,
6750 WINED3DRS_RANGEFOGENABLE ,
6751 WINED3DRS_SPECULARMATERIALSOURCE ,
6752 WINED3DRS_TWEENFACTOR ,
6753 WINED3DRS_VERTEXBLEND
6756 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6757 WINED3DTSS_TEXCOORDINDEX ,
6758 WINED3DTSS_TEXTURETRANSFORMFLAGS
6761 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6762 WINED3DSAMP_DMAPOFFSET
6765 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6766 DWORD rep = StateTable[state].representative;
6767 DWORD idx;
6768 BYTE shift;
6769 UINT i;
6770 WineD3DContext *context;
6772 if(!rep) return;
6773 for(i = 0; i < This->numContexts; i++) {
6774 context = This->contexts[i];
6775 if(isStateDirty(context, rep)) continue;
6777 context->dirtyArray[context->numDirtyEntries++] = rep;
6778 idx = rep >> 5;
6779 shift = rep & 0x1f;
6780 context->isStateDirty[idx] |= (1 << shift);