ole32: Add documentation for CreateBindCtx, BindMoniker, GetRunningObjectTable and...
[wine/gsoc_dplay.git] / dlls / wined3d / device.c
blob78637149641bc43b4541862bdb680cd5bfb46c12
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006 Stefan Dösinger for CodeWeavers
10 * Copyright 2006 Henri Verbeet
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include <stdio.h>
29 #ifdef HAVE_FLOAT_H
30 # include <float.h>
31 #endif
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
35 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
37 /* Define the default light parameters as specified by MSDN */
38 const WINED3DLIGHT WINED3D_default_light = {
40 WINED3DLIGHT_DIRECTIONAL, /* Type */
41 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
42 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
44 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
45 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
46 0.0, /* Range */
47 0.0, /* Falloff */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
49 0.0, /* Theta */
50 0.0 /* Phi */
53 /* x11drv GDI escapes */
54 #define X11DRV_ESCAPE 6789
55 enum x11drv_escape_codes
57 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
58 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
59 X11DRV_GET_FONT, /* get current X font for a DC */
62 /* retrieve the X display to use on a given DC */
63 static inline Display *get_display( HDC hdc )
65 Display *display;
66 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
68 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
69 sizeof(display), (LPSTR)&display )) display = NULL;
70 return display;
73 /* static function declarations */
74 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
76 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
78 /* helper macros */
79 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
81 #define D3DCREATEOBJECTINSTANCE(object, type) { \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->wineD3DDevice = This; \
86 object->parent = parent; \
87 object->ref = 1; \
88 *pp##type = (IWineD3D##type *) object; \
91 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
92 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
93 D3DMEMCHECK(object, pp##type); \
94 object->lpVtbl = &IWineD3D##type##_Vtbl; \
95 object->parent = parent; \
96 object->ref = 1; \
97 object->baseShader.device = (IWineD3DDevice*) This; \
98 list_init(&object->baseShader.linked_programs); \
99 *pp##type = (IWineD3D##type *) object; \
102 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
103 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
104 D3DMEMCHECK(object, pp##type); \
105 object->lpVtbl = &IWineD3D##type##_Vtbl; \
106 object->resource.wineD3DDevice = This; \
107 object->resource.parent = parent; \
108 object->resource.resourceType = d3dtype; \
109 object->resource.ref = 1; \
110 object->resource.pool = Pool; \
111 object->resource.format = Format; \
112 object->resource.usage = Usage; \
113 object->resource.size = _size; \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
119 *pp##type = NULL; \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
128 *pp##type = NULL; \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
143 /**********************************************************
144 * Global variable / Constants follow
145 **********************************************************/
146 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
148 /**********************************************************
149 * IUnknown parts follows
150 **********************************************************/
152 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
157 if (IsEqualGUID(riid, &IID_IUnknown)
158 || IsEqualGUID(riid, &IID_IWineD3DBase)
159 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
160 IUnknown_AddRef(iface);
161 *ppobj = This;
162 return S_OK;
164 *ppobj = NULL;
165 return E_NOINTERFACE;
168 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
170 ULONG refCount = InterlockedIncrement(&This->ref);
172 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
173 return refCount;
176 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
178 ULONG refCount = InterlockedDecrement(&This->ref);
180 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
182 if (!refCount) {
183 if (This->fbo) {
184 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
187 HeapFree(GetProcessHeap(), 0, This->render_targets);
189 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
191 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
193 /* TODO: Clean up all the surfaces and textures! */
194 /* NOTE: You must release the parent if the object was created via a callback
195 ** ***************************/
197 /* Release the update stateblock */
198 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
199 if(This->updateStateBlock != This->stateBlock)
200 FIXME("(%p) Something's still holding the Update stateblock\n",This);
202 This->updateStateBlock = NULL;
203 { /* because were not doing proper internal refcounts releasing the primary state block
204 causes recursion with the extra checks in ResourceReleased, to avoid this we have
205 to set this->stateBlock = NULL; first */
206 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
207 This->stateBlock = NULL;
209 /* Release the stateblock */
210 if(IWineD3DStateBlock_Release(stateBlock) > 0){
211 FIXME("(%p) Something's still holding the Update stateblock\n",This);
215 if (This->resources != NULL ) {
216 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
217 dumpResources(This->resources);
220 if(This->contexts) ERR("Context array not freed!\n");
222 IWineD3D_Release(This->wineD3D);
223 This->wineD3D = NULL;
224 HeapFree(GetProcessHeap(), 0, This);
225 TRACE("Freed device %p\n", This);
226 This = NULL;
228 return refCount;
231 /**********************************************************
232 * IWineD3DDevice implementation follows
233 **********************************************************/
234 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
236 *pParent = This->parent;
237 IUnknown_AddRef(This->parent);
238 return WINED3D_OK;
241 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
242 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
243 GLenum error, glUsage;
244 DWORD vboUsage = object->resource.usage;
245 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
246 WARN("Creating a vbo failed once, not trying again\n");
247 return;
250 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
252 ENTER_GL();
253 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
254 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
256 /* Make sure that the gl error is cleared. Do not use checkGLcall
257 * here because checkGLcall just prints a fixme and continues. However,
258 * if an error during VBO creation occurs we can fall back to non-vbo operation
259 * with full functionality(but performance loss)
261 while(glGetError() != GL_NO_ERROR);
263 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
264 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
265 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
266 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
267 * to check if the rhw and color values are in the correct format.
270 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
271 error = glGetError();
272 if(object->vbo == 0 || error != GL_NO_ERROR) {
273 WARN("Failed to create a VBO with error %d\n", error);
274 goto error;
277 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
278 error = glGetError();
279 if(error != GL_NO_ERROR) {
280 WARN("Failed to bind the VBO, error %d\n", error);
281 goto error;
284 /* Don't use static, because dx apps tend to update the buffer
285 * quite often even if they specify 0 usage. Because we always keep the local copy
286 * we never read from the vbo and can create a write only opengl buffer.
288 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
289 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
290 case WINED3DUSAGE_DYNAMIC:
291 TRACE("Gl usage = GL_STREAM_DRAW\n");
292 glUsage = GL_STREAM_DRAW_ARB;
293 break;
294 case WINED3DUSAGE_WRITEONLY:
295 default:
296 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
297 glUsage = GL_DYNAMIC_DRAW_ARB;
298 break;
301 /* Reserve memory for the buffer. The amount of data won't change
302 * so we are safe with calling glBufferData once with a NULL ptr and
303 * calling glBufferSubData on updates
305 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
306 error = glGetError();
307 if(error != GL_NO_ERROR) {
308 WARN("glBufferDataARB failed with error %d\n", error);
309 goto error;
312 LEAVE_GL();
314 return;
315 error:
316 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
317 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
318 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
319 object->vbo = 0;
320 object->Flags |= VBFLAG_VBOCREATEFAIL;
321 LEAVE_GL();
322 return;
325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
326 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
327 IUnknown *parent) {
328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
329 IWineD3DVertexBufferImpl *object;
330 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
331 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
332 BOOL conv;
334 if(Size == 0) {
335 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
336 *ppVertexBuffer = NULL;
337 return WINED3DERR_INVALIDCALL;
340 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
342 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
343 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
345 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
346 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
348 object->fvf = FVF;
350 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
351 * drawStridedFast (half-life 2).
353 * Basically converting the vertices in the buffer is quite expensive, and observations
354 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
355 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
357 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
358 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
359 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
360 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
361 * dx7 apps.
362 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
363 * more. In this call we can convert dx7 buffers too.
365 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
366 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
367 (dxVersion > 7 || !conv) ) {
368 CreateVBO(object);
370 return WINED3D_OK;
373 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
374 GLenum error, glUsage;
375 TRACE("Creating VBO for Index Buffer %p\n", object);
377 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
378 * restored on the next draw
380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
382 ENTER_GL();
383 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
384 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
386 while(glGetError());
388 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
389 error = glGetError();
390 if(error != GL_NO_ERROR || object->vbo == 0) {
391 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
392 goto out;
395 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
396 error = glGetError();
397 if(error != GL_NO_ERROR) {
398 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
399 goto out;
402 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
403 * copy no readback will be needed
405 glUsage = GL_STATIC_DRAW_ARB;
406 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
407 error = glGetError();
408 if(error != GL_NO_ERROR) {
409 ERR("Failed to initialize the index buffer\n");
410 goto out;
412 LEAVE_GL();
413 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
414 return;
416 out:
417 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
418 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
419 LEAVE_GL();
420 object->vbo = 0;
423 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
424 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
425 HANDLE *sharedHandle, IUnknown *parent) {
426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
427 IWineD3DIndexBufferImpl *object;
428 TRACE("(%p) Creating index buffer\n", This);
430 /* Allocate the storage for the device */
431 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
433 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
434 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
437 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
438 CreateIndexBufferVBO(This, object);
441 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
442 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
443 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
445 return WINED3D_OK;
448 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
451 IWineD3DStateBlockImpl *object;
452 int i, j;
453 HRESULT temp_result;
455 D3DCREATEOBJECTINSTANCE(object, StateBlock)
456 object->blockType = Type;
458 for(i = 0; i < LIGHTMAP_SIZE; i++) {
459 list_init(&object->lightMap[i]);
462 /* Special case - Used during initialization to produce a placeholder stateblock
463 so other functions called can update a state block */
464 if (Type == WINED3DSBT_INIT) {
465 /* Don't bother increasing the reference count otherwise a device will never
466 be freed due to circular dependencies */
467 return WINED3D_OK;
470 temp_result = allocate_shader_constants(object);
471 if (WINED3D_OK != temp_result)
472 return temp_result;
474 /* Otherwise, might as well set the whole state block to the appropriate values */
475 if (This->stateBlock != NULL)
476 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
477 else
478 memset(object->streamFreq, 1, sizeof(object->streamFreq));
480 /* Reset the ref and type after kludging it */
481 object->wineD3DDevice = This;
482 object->ref = 1;
483 object->blockType = Type;
485 TRACE("Updating changed flags appropriate for type %d\n", Type);
487 if (Type == WINED3DSBT_ALL) {
489 TRACE("ALL => Pretend everything has changed\n");
490 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
492 /* Lights are not part of the changed / set structure */
493 for(j = 0; j < LIGHTMAP_SIZE; j++) {
494 struct list *e;
495 LIST_FOR_EACH(e, &object->lightMap[j]) {
496 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
497 light->changed = TRUE;
498 light->enabledChanged = TRUE;
501 } else if (Type == WINED3DSBT_PIXELSTATE) {
503 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
504 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
506 object->changed.pixelShader = TRUE;
508 /* Pixel Shader Constants */
509 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
510 object->changed.pixelShaderConstantsF[i] = TRUE;
511 for (i = 0; i < MAX_CONST_B; ++i)
512 object->changed.pixelShaderConstantsB[i] = TRUE;
513 for (i = 0; i < MAX_CONST_I; ++i)
514 object->changed.pixelShaderConstantsI[i] = TRUE;
516 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
517 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
519 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
520 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
521 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
524 for (j = 0 ; j < 16; j++) {
525 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
527 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
531 } else if (Type == WINED3DSBT_VERTEXSTATE) {
533 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
534 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
536 object->changed.vertexShader = TRUE;
538 /* Vertex Shader Constants */
539 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
540 object->changed.vertexShaderConstantsF[i] = TRUE;
541 for (i = 0; i < MAX_CONST_B; ++i)
542 object->changed.vertexShaderConstantsB[i] = TRUE;
543 for (i = 0; i < MAX_CONST_I; ++i)
544 object->changed.vertexShaderConstantsI[i] = TRUE;
546 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
547 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
549 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
550 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
551 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
554 for (j = 0 ; j < 16; j++){
555 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
556 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
560 for(j = 0; j < LIGHTMAP_SIZE; j++) {
561 struct list *e;
562 LIST_FOR_EACH(e, &object->lightMap[j]) {
563 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
564 light->changed = TRUE;
565 light->enabledChanged = TRUE;
568 } else {
569 FIXME("Unrecognized state block type %d\n", Type);
572 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
573 return WINED3D_OK;
577 /* ************************************
578 MSDN:
579 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
581 Discard
582 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
584 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.
586 ******************************** */
588 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) {
589 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
590 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
591 unsigned int pow2Width, pow2Height;
592 unsigned int Size = 1;
593 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
594 TRACE("(%p) Create surface\n",This);
596 /** FIXME: Check ranges on the inputs are valid
597 * MSDN
598 * MultisampleQuality
599 * [in] Quality level. The valid range is between zero and one less than the level
600 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
601 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
602 * values of paired render targets, depth stencil surfaces, and the MultiSample type
603 * must all match.
604 *******************************/
608 * TODO: Discard MSDN
609 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
611 * If this flag is set, the contents of the depth stencil buffer will be
612 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
613 * with a different depth surface.
615 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
616 ***************************/
618 if(MultisampleQuality < 0) {
619 FIXME("Invalid multisample level %d\n", MultisampleQuality);
620 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
623 if(MultisampleQuality > 0) {
624 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
625 MultisampleQuality=0;
628 /** FIXME: Check that the format is supported
629 * by the device.
630 *******************************/
632 /* Non-power2 support */
633 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
634 pow2Width = Width;
635 pow2Height = Height;
636 } else {
637 /* Find the nearest pow2 match */
638 pow2Width = pow2Height = 1;
639 while (pow2Width < Width) pow2Width <<= 1;
640 while (pow2Height < Height) pow2Height <<= 1;
643 if (pow2Width > Width || pow2Height > Height) {
644 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
645 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
646 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
647 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
648 This, Width, Height);
649 return WINED3DERR_NOTAVAILABLE;
653 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
654 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
655 * space!
656 *********************************/
657 if (WINED3DFMT_UNKNOWN == Format) {
658 Size = 0;
659 } else if (Format == WINED3DFMT_DXT1) {
660 /* DXT1 is half byte per pixel */
661 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
663 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
664 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
665 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
666 } else {
667 /* The pitch is a multiple of 4 bytes */
668 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
669 Size *= Height;
672 /** Create and initialise the surface resource **/
673 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
674 /* "Standalone" surface */
675 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
677 object->currentDesc.Width = Width;
678 object->currentDesc.Height = Height;
679 object->currentDesc.MultiSampleType = MultiSample;
680 object->currentDesc.MultiSampleQuality = MultisampleQuality;
682 /* Setup some glformat defaults */
683 object->glDescription.glFormat = tableEntry->glFormat;
684 object->glDescription.glFormatInternal = tableEntry->glInternal;
685 object->glDescription.glType = tableEntry->glType;
687 object->glDescription.textureName = 0;
688 object->glDescription.level = Level;
689 object->glDescription.target = GL_TEXTURE_2D;
691 /* Internal data */
692 object->pow2Width = pow2Width;
693 object->pow2Height = pow2Height;
695 /* Flags */
696 object->Flags = SFLAG_DYNLOCK;
697 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
698 object->Flags |= Discard ? SFLAG_DISCARD : 0;
699 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
700 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
703 if (WINED3DFMT_UNKNOWN != Format) {
704 object->bytesPerPixel = tableEntry->bpp;
705 } else {
706 object->bytesPerPixel = 0;
709 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
711 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
713 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
714 * this function is too deep to need to care about things like this.
715 * Levels need to be checked too, and possibly Type since they all affect what can be done.
716 * ****************************************/
717 switch(Pool) {
718 case WINED3DPOOL_SCRATCH:
719 if(!Lockable)
720 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
721 "which are mutually exclusive, setting lockable to TRUE\n");
722 Lockable = TRUE;
723 break;
724 case WINED3DPOOL_SYSTEMMEM:
725 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
726 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
727 case WINED3DPOOL_MANAGED:
728 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
729 "Usage of DYNAMIC which are mutually exclusive, not doing "
730 "anything just telling you.\n");
731 break;
732 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
733 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
734 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
735 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
736 break;
737 default:
738 FIXME("(%p) Unknown pool %d\n", This, Pool);
739 break;
742 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
743 FIXME("Trying to create a render target that isn't in the default pool\n");
746 /* mark the texture as dirty so that it gets loaded first time around*/
747 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
748 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
749 This, Width, Height, Format, debug_d3dformat(Format),
750 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
752 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
753 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
754 This->ddraw_primary = (IWineD3DSurface *) object;
756 /* Look at the implementation and set the correct Vtable */
757 switch(Impl) {
758 case SURFACE_OPENGL:
759 /* Nothing to do, it's set already */
760 break;
762 case SURFACE_GDI:
763 object->lpVtbl = &IWineGDISurface_Vtbl;
764 break;
766 default:
767 /* To be sure to catch this */
768 ERR("Unknown requested surface implementation %d!\n", Impl);
769 IWineD3DSurface_Release((IWineD3DSurface *) object);
770 return WINED3DERR_INVALIDCALL;
773 /* Call the private setup routine */
774 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
778 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
779 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
780 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
781 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
784 IWineD3DTextureImpl *object;
785 unsigned int i;
786 UINT tmpW;
787 UINT tmpH;
788 HRESULT hr;
789 unsigned int pow2Width;
790 unsigned int pow2Height;
793 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
794 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
795 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
797 /* TODO: It should only be possible to create textures for formats
798 that are reported as supported */
799 if (WINED3DFMT_UNKNOWN >= Format) {
800 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
801 return WINED3DERR_INVALIDCALL;
804 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
805 D3DINITIALIZEBASETEXTURE(object->baseTexture);
806 object->width = Width;
807 object->height = Height;
809 /** Non-power2 support **/
810 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
811 pow2Width = Width;
812 pow2Height = Height;
813 } else {
814 /* Find the nearest pow2 match */
815 pow2Width = pow2Height = 1;
816 while (pow2Width < Width) pow2Width <<= 1;
817 while (pow2Height < Height) pow2Height <<= 1;
820 /** FIXME: add support for real non-power-two if it's provided by the video card **/
821 /* Precalculated scaling for 'faked' non power of two texture coords */
822 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
823 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
824 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
826 object->baseTexture.format = Format;
828 /* Calculate levels for mip mapping */
829 if (Levels == 0) {
830 TRACE("calculating levels %d\n", object->baseTexture.levels);
831 object->baseTexture.levels++;
832 tmpW = Width;
833 tmpH = Height;
834 while (tmpW > 1 || tmpH > 1) {
835 tmpW = max(1, tmpW >> 1);
836 tmpH = max(1, tmpH >> 1);
837 object->baseTexture.levels++;
839 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
842 /* Generate all the surfaces */
843 tmpW = Width;
844 tmpH = Height;
845 for (i = 0; i < object->baseTexture.levels; i++)
847 /* use the callback to create the texture surface */
848 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
849 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
850 FIXME("Failed to create surface %p\n", object);
851 /* clean up */
852 object->surfaces[i] = NULL;
853 IWineD3DTexture_Release((IWineD3DTexture *)object);
855 *ppTexture = NULL;
856 return hr;
859 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
860 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
861 /* calculate the next mipmap level */
862 tmpW = max(1, tmpW >> 1);
863 tmpH = max(1, tmpH >> 1);
866 TRACE("(%p) : Created texture %p\n", This, object);
867 return WINED3D_OK;
870 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
871 UINT Width, UINT Height, UINT Depth,
872 UINT Levels, DWORD Usage,
873 WINED3DFORMAT Format, WINED3DPOOL Pool,
874 IWineD3DVolumeTexture **ppVolumeTexture,
875 HANDLE *pSharedHandle, IUnknown *parent,
876 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
879 IWineD3DVolumeTextureImpl *object;
880 unsigned int i;
881 UINT tmpW;
882 UINT tmpH;
883 UINT tmpD;
885 /* TODO: It should only be possible to create textures for formats
886 that are reported as supported */
887 if (WINED3DFMT_UNKNOWN >= Format) {
888 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
889 return WINED3DERR_INVALIDCALL;
892 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
893 D3DINITIALIZEBASETEXTURE(object->baseTexture);
895 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
896 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
898 object->width = Width;
899 object->height = Height;
900 object->depth = Depth;
901 object->baseTexture.format = Format;
903 /* Calculate levels for mip mapping */
904 if (Levels == 0) {
905 object->baseTexture.levels++;
906 tmpW = Width;
907 tmpH = Height;
908 tmpD = Depth;
909 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
910 tmpW = max(1, tmpW >> 1);
911 tmpH = max(1, tmpH >> 1);
912 tmpD = max(1, tmpD >> 1);
913 object->baseTexture.levels++;
915 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
918 /* Generate all the surfaces */
919 tmpW = Width;
920 tmpH = Height;
921 tmpD = Depth;
923 for (i = 0; i < object->baseTexture.levels; i++)
925 HRESULT hr;
926 /* Create the volume */
927 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
928 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
930 if(FAILED(hr)) {
931 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
932 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
933 *ppVolumeTexture = NULL;
934 return hr;
937 /* Set its container to this object */
938 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
940 /* calcualte the next mipmap level */
941 tmpW = max(1, tmpW >> 1);
942 tmpH = max(1, tmpH >> 1);
943 tmpD = max(1, tmpD >> 1);
946 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
947 TRACE("(%p) : Created volume texture %p\n", This, object);
948 return WINED3D_OK;
951 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
952 UINT Width, UINT Height, UINT Depth,
953 DWORD Usage,
954 WINED3DFORMAT Format, WINED3DPOOL Pool,
955 IWineD3DVolume** ppVolume,
956 HANDLE* pSharedHandle, IUnknown *parent) {
958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
959 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
960 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
962 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
964 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
965 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
967 object->currentDesc.Width = Width;
968 object->currentDesc.Height = Height;
969 object->currentDesc.Depth = Depth;
970 object->bytesPerPixel = formatDesc->bpp;
972 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
973 object->lockable = TRUE;
974 object->locked = FALSE;
975 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
976 object->dirty = TRUE;
978 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
981 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
982 UINT Levels, DWORD Usage,
983 WINED3DFORMAT Format, WINED3DPOOL Pool,
984 IWineD3DCubeTexture **ppCubeTexture,
985 HANDLE *pSharedHandle, IUnknown *parent,
986 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
989 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
990 unsigned int i, j;
991 UINT tmpW;
992 HRESULT hr;
993 unsigned int pow2EdgeLength = EdgeLength;
995 /* TODO: It should only be possible to create textures for formats
996 that are reported as supported */
997 if (WINED3DFMT_UNKNOWN >= Format) {
998 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
999 return WINED3DERR_INVALIDCALL;
1002 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1003 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1005 TRACE("(%p) Create Cube Texture\n", This);
1007 /** Non-power2 support **/
1009 /* Find the nearest pow2 match */
1010 pow2EdgeLength = 1;
1011 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1013 object->edgeLength = EdgeLength;
1014 /* TODO: support for native non-power 2 */
1015 /* Precalculated scaling for 'faked' non power of two texture coords */
1016 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1017 object->baseTexture.format = Format;
1019 /* Calculate levels for mip mapping */
1020 if (Levels == 0) {
1021 object->baseTexture.levels++;
1022 tmpW = EdgeLength;
1023 while (tmpW > 1) {
1024 tmpW = max(1, tmpW >> 1);
1025 object->baseTexture.levels++;
1027 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1030 /* Generate all the surfaces */
1031 tmpW = EdgeLength;
1032 for (i = 0; i < object->baseTexture.levels; i++) {
1034 /* Create the 6 faces */
1035 for (j = 0; j < 6; j++) {
1037 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1038 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1040 if(hr!= WINED3D_OK) {
1041 /* clean up */
1042 int k;
1043 int l;
1044 for (l = 0; l < j; l++) {
1045 IWineD3DSurface_Release(object->surfaces[j][i]);
1047 for (k = 0; k < i; k++) {
1048 for (l = 0; l < 6; l++) {
1049 IWineD3DSurface_Release(object->surfaces[l][j]);
1053 FIXME("(%p) Failed to create surface\n",object);
1054 HeapFree(GetProcessHeap(),0,object);
1055 *ppCubeTexture = NULL;
1056 return hr;
1058 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1059 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1061 tmpW = max(1, tmpW >> 1);
1064 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1065 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1066 return WINED3D_OK;
1069 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1071 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1072 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1074 /* Just a check to see if we support this type of query */
1075 switch(Type) {
1076 case WINED3DQUERYTYPE_OCCLUSION:
1077 TRACE("(%p) occlusion query\n", This);
1078 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1079 hr = WINED3D_OK;
1080 else
1081 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1082 break;
1084 case WINED3DQUERYTYPE_EVENT:
1085 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1086 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1087 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1089 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1091 hr = WINED3D_OK;
1092 break;
1094 case WINED3DQUERYTYPE_VCACHE:
1095 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1096 case WINED3DQUERYTYPE_VERTEXSTATS:
1097 case WINED3DQUERYTYPE_TIMESTAMP:
1098 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1099 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1100 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1101 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1102 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1103 case WINED3DQUERYTYPE_PIXELTIMINGS:
1104 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1105 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1106 default:
1107 FIXME("(%p) Unhandled query type %d\n", This, Type);
1109 if(NULL == ppQuery || hr != WINED3D_OK) {
1110 return hr;
1113 D3DCREATEOBJECTINSTANCE(object, Query)
1114 object->type = Type;
1115 /* allocated the 'extended' data based on the type of query requested */
1116 switch(Type){
1117 case WINED3DQUERYTYPE_OCCLUSION:
1118 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1119 TRACE("(%p) Allocating data for an occlusion query\n", This);
1120 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1121 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1122 break;
1124 case WINED3DQUERYTYPE_EVENT:
1125 /* TODO: GL_APPLE_fence */
1126 if(GL_SUPPORT(APPLE_FENCE)) {
1127 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1128 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1129 checkGLcall("glGenFencesAPPLE");
1130 } else if(GL_SUPPORT(NV_FENCE)) {
1131 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1132 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1133 checkGLcall("glGenFencesNV");
1135 break;
1137 case WINED3DQUERYTYPE_VCACHE:
1138 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1139 case WINED3DQUERYTYPE_VERTEXSTATS:
1140 case WINED3DQUERYTYPE_TIMESTAMP:
1141 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1142 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1143 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1144 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1145 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1146 case WINED3DQUERYTYPE_PIXELTIMINGS:
1147 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1148 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1149 default:
1150 object->extendedData = 0;
1151 FIXME("(%p) Unhandled query type %d\n",This , Type);
1153 TRACE("(%p) : Created Query %p\n", This, object);
1154 return WINED3D_OK;
1157 /*****************************************************************************
1158 * IWineD3DDeviceImpl_SetupFullscreenWindow
1160 * Helper function that modifies a HWND's Style and ExStyle for proper
1161 * fullscreen use.
1163 * Params:
1164 * iface: Pointer to the IWineD3DDevice interface
1165 * window: Window to setup
1167 *****************************************************************************/
1168 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1171 LONG style, exStyle;
1172 /* Don't do anything if an original style is stored.
1173 * That shouldn't happen
1175 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1176 if (This->style || This->exStyle) {
1177 ERR("(%p): Want to change the window parameters of HWND %p, but "
1178 "another style is stored for restoration afterwards\n", This, window);
1181 /* Get the parameters and save them */
1182 style = GetWindowLongW(window, GWL_STYLE);
1183 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1184 This->style = style;
1185 This->exStyle = exStyle;
1187 /* Filter out window decorations */
1188 style &= ~WS_CAPTION;
1189 style &= ~WS_THICKFRAME;
1190 exStyle &= ~WS_EX_WINDOWEDGE;
1191 exStyle &= ~WS_EX_CLIENTEDGE;
1193 /* Make sure the window is managed, otherwise we won't get keyboard input */
1194 style |= WS_POPUP | WS_SYSMENU;
1196 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1197 This->style, This->exStyle, style, exStyle);
1199 SetWindowLongW(window, GWL_STYLE, style);
1200 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1202 /* Inform the window about the update. */
1203 SetWindowPos(window, HWND_TOP, 0, 0,
1204 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1205 ShowWindow(window, SW_NORMAL);
1208 /*****************************************************************************
1209 * IWineD3DDeviceImpl_RestoreWindow
1211 * Helper function that restores a windows' properties when taking it out
1212 * of fullscreen mode
1214 * Params:
1215 * iface: Pointer to the IWineD3DDevice interface
1216 * window: Window to setup
1218 *****************************************************************************/
1219 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1222 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1223 * switch, do nothing
1225 if (!This->style && !This->exStyle) return;
1227 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1228 This, window, This->style, This->exStyle);
1230 SetWindowLongW(window, GWL_STYLE, This->style);
1231 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1233 /* Delete the old values */
1234 This->style = 0;
1235 This->exStyle = 0;
1237 /* Inform the window about the update */
1238 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1239 0, 0, 0, 0, /* Pos, Size, ignored */
1240 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1243 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1244 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1245 IUnknown* parent,
1246 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1247 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1250 HDC hDc;
1251 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1252 HRESULT hr = WINED3D_OK;
1253 IUnknown *bufferParent;
1254 Display *display;
1256 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1258 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1259 * does a device hold a reference to a swap chain giving them a lifetime of the device
1260 * or does the swap chain notify the device of its destruction.
1261 *******************************/
1263 /* Check the params */
1264 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1265 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1266 return WINED3DERR_INVALIDCALL;
1267 } else if (pPresentationParameters->BackBufferCount > 1) {
1268 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");
1271 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1273 /*********************
1274 * Lookup the window Handle and the relating X window handle
1275 ********************/
1277 /* Setup hwnd we are using, plus which display this equates to */
1278 object->win_handle = pPresentationParameters->hDeviceWindow;
1279 if (!object->win_handle) {
1280 object->win_handle = This->createParms.hFocusWindow;
1283 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1284 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1285 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1286 return WINED3DERR_NOTAVAILABLE;
1288 hDc = GetDC(object->win_handle);
1289 display = get_display(hDc);
1290 ReleaseDC(object->win_handle, hDc);
1291 TRACE("Using a display of %p %p\n", display, hDc);
1293 if (NULL == display || NULL == hDc) {
1294 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1295 return WINED3DERR_NOTAVAILABLE;
1298 if (object->win == 0) {
1299 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1300 return WINED3DERR_NOTAVAILABLE;
1303 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1304 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1305 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1307 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1308 * then the corresponding dimension of the client area of the hDeviceWindow
1309 * (or the focus window, if hDeviceWindow is NULL) is taken.
1310 **********************/
1312 if (pPresentationParameters->Windowed &&
1313 ((pPresentationParameters->BackBufferWidth == 0) ||
1314 (pPresentationParameters->BackBufferHeight == 0))) {
1316 RECT Rect;
1317 GetClientRect(object->win_handle, &Rect);
1319 if (pPresentationParameters->BackBufferWidth == 0) {
1320 pPresentationParameters->BackBufferWidth = Rect.right;
1321 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1323 if (pPresentationParameters->BackBufferHeight == 0) {
1324 pPresentationParameters->BackBufferHeight = Rect.bottom;
1325 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1329 /* Put the correct figures in the presentation parameters */
1330 TRACE("Copying across presentation parameters\n");
1331 object->presentParms = *pPresentationParameters;
1333 TRACE("calling rendertarget CB\n");
1334 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1335 parent,
1336 object->presentParms.BackBufferWidth,
1337 object->presentParms.BackBufferHeight,
1338 object->presentParms.BackBufferFormat,
1339 object->presentParms.MultiSampleType,
1340 object->presentParms.MultiSampleQuality,
1341 TRUE /* Lockable */,
1342 &object->frontBuffer,
1343 NULL /* pShared (always null)*/);
1344 if (object->frontBuffer != NULL) {
1345 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1346 } else {
1347 ERR("Failed to create the front buffer\n");
1348 goto error;
1352 * Create an opengl context for the display visual
1353 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1354 * use different properties after that point in time. FIXME: How to handle when requested format
1355 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1356 * it chooses is identical to the one already being used!
1357 **********************************/
1358 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1360 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1361 if(!object->context) {
1363 object->num_contexts = 1;
1365 ENTER_GL();
1366 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1367 LEAVE_GL();
1369 if (!object->context) {
1370 ERR("Failed to create a new context\n");
1371 hr = WINED3DERR_NOTAVAILABLE;
1372 goto error;
1373 } else {
1374 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1375 object->win_handle, object->context[0]->glCtx, object->win);
1378 /*********************
1379 * Windowed / Fullscreen
1380 *******************/
1383 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1384 * so we should really check to see if there is a fullscreen swapchain already
1385 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1386 **************************************/
1388 if (!pPresentationParameters->Windowed) {
1390 DEVMODEW devmode;
1391 HDC hdc;
1392 int bpp = 0;
1393 RECT clip_rc;
1395 /* Get info on the current display setup */
1396 hdc = GetDC(0);
1397 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1398 ReleaseDC(0, hdc);
1400 /* Change the display settings */
1401 memset(&devmode, 0, sizeof(DEVMODEW));
1402 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1403 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1404 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1405 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1406 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1407 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1409 /* For GetDisplayMode */
1410 This->ddraw_width = devmode.dmPelsWidth;
1411 This->ddraw_height = devmode.dmPelsHeight;
1412 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1414 IWineD3DDevice_SetFullscreen(iface, TRUE);
1416 /* And finally clip mouse to our screen */
1417 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1418 ClipCursor(&clip_rc);
1421 /*********************
1422 * Create the back, front and stencil buffers
1423 *******************/
1424 if(object->presentParms.BackBufferCount > 0) {
1425 int i;
1427 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1428 if(!object->backBuffer) {
1429 ERR("Out of memory\n");
1430 hr = E_OUTOFMEMORY;
1431 goto error;
1434 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1435 TRACE("calling rendertarget CB\n");
1436 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1437 parent,
1438 object->presentParms.BackBufferWidth,
1439 object->presentParms.BackBufferHeight,
1440 object->presentParms.BackBufferFormat,
1441 object->presentParms.MultiSampleType,
1442 object->presentParms.MultiSampleQuality,
1443 TRUE /* Lockable */,
1444 &object->backBuffer[i],
1445 NULL /* pShared (always null)*/);
1446 if(hr == WINED3D_OK && object->backBuffer[i]) {
1447 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1448 } else {
1449 ERR("Cannot create new back buffer\n");
1450 goto error;
1452 ENTER_GL();
1453 glDrawBuffer(GL_BACK);
1454 checkGLcall("glDrawBuffer(GL_BACK)");
1455 LEAVE_GL();
1457 } else {
1458 object->backBuffer = NULL;
1460 /* Single buffering - draw to front buffer */
1461 ENTER_GL();
1462 glDrawBuffer(GL_FRONT);
1463 checkGLcall("glDrawBuffer(GL_FRONT)");
1464 LEAVE_GL();
1467 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1468 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1469 TRACE("Creating depth stencil buffer\n");
1470 if (This->depthStencilBuffer == NULL ) {
1471 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1472 parent,
1473 object->presentParms.BackBufferWidth,
1474 object->presentParms.BackBufferHeight,
1475 object->presentParms.AutoDepthStencilFormat,
1476 object->presentParms.MultiSampleType,
1477 object->presentParms.MultiSampleQuality,
1478 FALSE /* FIXME: Discard */,
1479 &This->depthStencilBuffer,
1480 NULL /* pShared (always null)*/ );
1481 if (This->depthStencilBuffer != NULL)
1482 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1485 /** TODO: A check on width, height and multisample types
1486 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1487 ****************************/
1488 object->wantsDepthStencilBuffer = TRUE;
1489 } else {
1490 object->wantsDepthStencilBuffer = FALSE;
1493 TRACE("Created swapchain %p\n", object);
1494 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1495 return WINED3D_OK;
1497 error:
1498 if (object->backBuffer) {
1499 int i;
1500 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1501 if(object->backBuffer[i]) {
1502 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1503 IUnknown_Release(bufferParent); /* once for the get parent */
1504 if (IUnknown_Release(bufferParent) > 0) {
1505 FIXME("(%p) Something's still holding the back buffer\n",This);
1509 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1510 object->backBuffer = NULL;
1512 if(object->context) {
1513 DestroyContext(This, object->context[0]);
1515 if(object->frontBuffer) {
1516 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1517 IUnknown_Release(bufferParent); /* once for the get parent */
1518 if (IUnknown_Release(bufferParent) > 0) {
1519 FIXME("(%p) Something's still holding the front buffer\n",This);
1522 HeapFree(GetProcessHeap(), 0, object);
1523 return hr;
1526 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1527 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1529 TRACE("(%p)\n", This);
1531 return This->NumberOfSwapChains;
1534 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1536 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1538 if(iSwapChain < This->NumberOfSwapChains) {
1539 *pSwapChain = This->swapchains[iSwapChain];
1540 IWineD3DSwapChain_AddRef(*pSwapChain);
1541 TRACE("(%p) returning %p\n", This, *pSwapChain);
1542 return WINED3D_OK;
1543 } else {
1544 TRACE("Swapchain out of range\n");
1545 *pSwapChain = NULL;
1546 return WINED3DERR_INVALIDCALL;
1550 /*****
1551 * Vertex Declaration
1552 *****/
1553 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1554 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1556 IWineD3DVertexDeclarationImpl *object = NULL;
1557 HRESULT hr = WINED3D_OK;
1559 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1560 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1562 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1564 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1566 return hr;
1569 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1570 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1572 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1573 HRESULT hr = WINED3D_OK;
1574 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1575 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1577 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1579 if (vertex_declaration) {
1580 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1583 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1585 if (WINED3D_OK != hr) {
1586 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1587 IWineD3DVertexShader_Release(*ppVertexShader);
1588 return WINED3DERR_INVALIDCALL;
1591 return WINED3D_OK;
1594 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1596 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1597 HRESULT hr = WINED3D_OK;
1599 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1600 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1601 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1602 if (WINED3D_OK == hr) {
1603 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1604 } else {
1605 WARN("(%p) : Failed to create pixel shader\n", This);
1608 return hr;
1611 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1613 IWineD3DPaletteImpl *object;
1614 HRESULT hr;
1615 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1617 /* Create the new object */
1618 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1619 if(!object) {
1620 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1621 return E_OUTOFMEMORY;
1624 object->lpVtbl = &IWineD3DPalette_Vtbl;
1625 object->ref = 1;
1626 object->Flags = Flags;
1627 object->parent = Parent;
1628 object->wineD3DDevice = This;
1629 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1631 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1633 if(!object->hpal) {
1634 HeapFree( GetProcessHeap(), 0, object);
1635 return E_OUTOFMEMORY;
1638 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1639 if(FAILED(hr)) {
1640 IWineD3DPalette_Release((IWineD3DPalette *) object);
1641 return hr;
1644 *Palette = (IWineD3DPalette *) object;
1646 return WINED3D_OK;
1649 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1651 IWineD3DSwapChainImpl *swapchain;
1652 DWORD state;
1654 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1655 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1657 /* TODO: Test if OpenGL is compiled in and loaded */
1659 /* Initialize the texture unit mapping to a 1:1 mapping */
1660 for(state = 0; state < MAX_SAMPLERS; state++) {
1661 This->texUnitMap[state] = state;
1663 This->oneToOneTexUnitMap = TRUE;
1665 /* Setup the implicit swapchain */
1666 TRACE("Creating implicit swapchain\n");
1667 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1668 WARN("Failed to create implicit swapchain\n");
1669 return WINED3DERR_INVALIDCALL;
1672 This->NumberOfSwapChains = 1;
1673 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1674 if(!This->swapchains) {
1675 ERR("Out of memory!\n");
1676 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1677 return E_OUTOFMEMORY;
1679 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1681 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1683 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1684 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1685 This->render_targets[0] = swapchain->backBuffer[0];
1686 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1688 else {
1689 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1690 This->render_targets[0] = swapchain->frontBuffer;
1691 This->lastActiveRenderTarget = swapchain->frontBuffer;
1693 IWineD3DSurface_AddRef(This->render_targets[0]);
1694 This->activeContext = swapchain->context[0];
1696 /* Depth Stencil support */
1697 This->stencilBufferTarget = This->depthStencilBuffer;
1698 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1699 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1701 if (NULL != This->stencilBufferTarget) {
1702 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1705 /* Set up some starting GL setup */
1706 ENTER_GL();
1708 * Initialize openGL extension related variables
1709 * with Default values
1712 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1713 /* Setup all the devices defaults */
1714 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1715 #if 0
1716 IWineD3DImpl_CheckGraphicsMemory();
1717 #endif
1719 { /* Set a default viewport */
1720 WINED3DVIEWPORT vp;
1721 vp.X = 0;
1722 vp.Y = 0;
1723 vp.Width = pPresentationParameters->BackBufferWidth;
1724 vp.Height = pPresentationParameters->BackBufferHeight;
1725 vp.MinZ = 0.0f;
1726 vp.MaxZ = 1.0f;
1727 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1730 /* Initialize the current view state */
1731 This->view_ident = 1;
1732 This->contexts[0]->last_was_rhw = 0;
1733 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1734 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1736 switch(wined3d_settings.offscreen_rendering_mode) {
1737 case ORM_FBO:
1738 case ORM_PBUFFER:
1739 This->offscreenBuffer = GL_BACK;
1740 break;
1742 case ORM_BACKBUFFER:
1744 if(GL_LIMITS(aux_buffers) > 0) {
1745 TRACE("Using auxilliary buffer for offscreen rendering\n");
1746 This->offscreenBuffer = GL_AUX0;
1747 } else {
1748 TRACE("Using back buffer for offscreen rendering\n");
1749 This->offscreenBuffer = GL_BACK;
1754 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1755 LEAVE_GL();
1757 /* Clear the screen */
1758 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1759 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1760 0x00, 1.0, 0);
1762 This->d3d_initialized = TRUE;
1763 return WINED3D_OK;
1766 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1768 int sampler;
1769 uint i;
1770 TRACE("(%p)\n", This);
1772 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1774 ENTER_GL();
1775 /* I don't think that the interface guarants that the device is destroyed from the same thread
1776 * it was created. Thus make sure a context is active for the glDelete* calls
1778 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1779 LEAVE_GL();
1781 /* Delete the pbuffer context if there is any */
1782 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1784 /* Delete the mouse cursor texture */
1785 if(This->cursorTexture) {
1786 ENTER_GL();
1787 glDeleteTextures(1, &This->cursorTexture);
1788 LEAVE_GL();
1789 This->cursorTexture = 0;
1792 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1793 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1796 /* Release the buffers (with sanity checks)*/
1797 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1798 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1799 if(This->depthStencilBuffer != This->stencilBufferTarget)
1800 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1802 This->stencilBufferTarget = NULL;
1804 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1805 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1806 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1808 TRACE("Setting rendertarget to NULL\n");
1809 This->render_targets[0] = NULL;
1811 if (This->depthStencilBuffer) {
1812 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1813 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1815 This->depthStencilBuffer = NULL;
1818 for(i=0; i < This->NumberOfSwapChains; i++) {
1819 TRACE("Releasing the implicit swapchain %d\n", i);
1820 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1821 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1825 HeapFree(GetProcessHeap(), 0, This->swapchains);
1826 This->swapchains = NULL;
1827 This->NumberOfSwapChains = 0;
1829 This->d3d_initialized = FALSE;
1830 return WINED3D_OK;
1833 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1835 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1837 /* Setup the window for fullscreen mode */
1838 if(fullscreen && !This->ddraw_fullscreen) {
1839 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1840 } else if(!fullscreen && This->ddraw_fullscreen) {
1841 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1844 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1845 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1846 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1847 * separately.
1849 This->ddraw_fullscreen = fullscreen;
1852 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1853 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1854 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1856 * There is no way to deactivate thread safety once it is enabled
1858 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1860 FIXME("No thread safety in wined3d yet\n");
1862 /*For now just store the flag(needed in case of ddraw) */
1863 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1865 return;
1868 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1869 DEVMODEW devmode;
1870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1871 LONG ret;
1872 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1873 RECT clip_rc;
1875 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1877 /* Resize the screen even without a window:
1878 * The app could have unset it with SetCooperativeLevel, but not called
1879 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1880 * but we don't have any hwnd
1883 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1884 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1885 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1886 devmode.dmPelsWidth = pMode->Width;
1887 devmode.dmPelsHeight = pMode->Height;
1889 devmode.dmDisplayFrequency = pMode->RefreshRate;
1890 if (pMode->RefreshRate != 0) {
1891 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1894 /* Only change the mode if necessary */
1895 if( (This->ddraw_width == pMode->Width) &&
1896 (This->ddraw_height == pMode->Height) &&
1897 (This->ddraw_format == pMode->Format) &&
1898 (pMode->RefreshRate == 0) ) {
1899 return WINED3D_OK;
1902 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1903 if (ret != DISP_CHANGE_SUCCESSFUL) {
1904 if(devmode.dmDisplayFrequency != 0) {
1905 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1906 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1907 devmode.dmDisplayFrequency = 0;
1908 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1910 if(ret != DISP_CHANGE_SUCCESSFUL) {
1911 return DDERR_INVALIDMODE;
1915 /* Store the new values */
1916 This->ddraw_width = pMode->Width;
1917 This->ddraw_height = pMode->Height;
1918 This->ddraw_format = pMode->Format;
1920 /* Only do this with a window of course */
1921 if(This->ddraw_window)
1922 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1924 /* And finally clip mouse to our screen */
1925 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1926 ClipCursor(&clip_rc);
1928 return WINED3D_OK;
1931 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1933 *ppD3D= This->wineD3D;
1934 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1935 IWineD3D_AddRef(*ppD3D);
1936 return WINED3D_OK;
1939 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1940 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1941 * into the video ram as possible and seeing how many fit
1942 * you can also get the correct initial value from nvidia and ATI's driver via X
1943 * texture memory is video memory + AGP memory
1944 *******************/
1945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1946 static BOOL showfixmes = TRUE;
1947 if (showfixmes) {
1948 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1949 (wined3d_settings.emulated_textureram/(1024*1024)),
1950 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1951 showfixmes = FALSE;
1953 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1954 (wined3d_settings.emulated_textureram/(1024*1024)),
1955 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1956 /* return simulated texture memory left */
1957 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1962 /*****
1963 * Get / Set FVF
1964 *****/
1965 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1968 /* Update the current state block */
1969 This->updateStateBlock->changed.fvf = TRUE;
1970 This->updateStateBlock->set.fvf = TRUE;
1972 if(This->updateStateBlock->fvf == fvf) {
1973 TRACE("Application is setting the old fvf over, nothing to do\n");
1974 return WINED3D_OK;
1977 This->updateStateBlock->fvf = fvf;
1978 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1980 return WINED3D_OK;
1984 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1986 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1987 *pfvf = This->stateBlock->fvf;
1988 return WINED3D_OK;
1991 /*****
1992 * Get / Set Stream Source
1993 *****/
1994 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1996 IWineD3DVertexBuffer *oldSrc;
1998 if (StreamNumber >= MAX_STREAMS) {
1999 WARN("Stream out of range %d\n", StreamNumber);
2000 return WINED3DERR_INVALIDCALL;
2003 oldSrc = This->stateBlock->streamSource[StreamNumber];
2004 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2006 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2007 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2009 if(oldSrc == pStreamData &&
2010 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2011 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2012 TRACE("Application is setting the old values over, nothing to do\n");
2013 return WINED3D_OK;
2016 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2017 if (pStreamData) {
2018 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2019 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2022 /* Handle recording of state blocks */
2023 if (This->isRecordingState) {
2024 TRACE("Recording... not performing anything\n");
2025 return WINED3D_OK;
2028 /* Need to do a getParent and pass the reffs up */
2029 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2030 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2031 so for now, just count internally */
2032 if (pStreamData != NULL) {
2033 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2034 InterlockedIncrement(&vbImpl->bindCount);
2036 if (oldSrc != NULL) {
2037 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2042 return WINED3D_OK;
2045 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2048 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2049 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2051 if (StreamNumber >= MAX_STREAMS) {
2052 WARN("Stream out of range %d\n", StreamNumber);
2053 return WINED3DERR_INVALIDCALL;
2055 *pStream = This->stateBlock->streamSource[StreamNumber];
2056 *pStride = This->stateBlock->streamStride[StreamNumber];
2057 if (pOffset) {
2058 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2061 if (*pStream != NULL) {
2062 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2064 return WINED3D_OK;
2067 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2069 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2070 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2072 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2073 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2075 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2076 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2077 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2079 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2080 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2081 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2084 return WINED3D_OK;
2087 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2090 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2091 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2093 TRACE("(%p) : returning %d\n", This, *Divider);
2095 return WINED3D_OK;
2098 /*****
2099 * Get / Set & Multiply Transform
2100 *****/
2101 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2104 /* Most of this routine, comments included copied from ddraw tree initially: */
2105 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2107 /* Handle recording of state blocks */
2108 if (This->isRecordingState) {
2109 TRACE("Recording... not performing anything\n");
2110 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2111 This->updateStateBlock->set.transform[d3dts] = TRUE;
2112 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2113 return WINED3D_OK;
2117 * If the new matrix is the same as the current one,
2118 * we cut off any further processing. this seems to be a reasonable
2119 * optimization because as was noticed, some apps (warcraft3 for example)
2120 * tend towards setting the same matrix repeatedly for some reason.
2122 * From here on we assume that the new matrix is different, wherever it matters.
2124 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2125 TRACE("The app is setting the same matrix over again\n");
2126 return WINED3D_OK;
2127 } else {
2128 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2132 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2133 where ViewMat = Camera space, WorldMat = world space.
2135 In OpenGL, camera and world space is combined into GL_MODELVIEW
2136 matrix. The Projection matrix stay projection matrix.
2139 /* Capture the times we can just ignore the change for now */
2140 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2141 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2142 /* Handled by the state manager */
2145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2146 return WINED3D_OK;
2149 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2151 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2152 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2153 return WINED3D_OK;
2156 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2157 WINED3DMATRIX *mat = NULL;
2158 WINED3DMATRIX temp;
2160 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2161 * below means it will be recorded in a state block change, but it
2162 * works regardless where it is recorded.
2163 * If this is found to be wrong, change to StateBlock.
2165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2166 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2168 if (State < HIGHEST_TRANSFORMSTATE)
2170 mat = &This->updateStateBlock->transforms[State];
2171 } else {
2172 FIXME("Unhandled transform state!!\n");
2175 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2177 /* Apply change via set transform - will reapply to eg. lights this way */
2178 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2181 /*****
2182 * Get / Set Light
2183 *****/
2184 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2185 you can reference any indexes you want as long as that number max are enabled at any
2186 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2187 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2188 but when recording, just build a chain pretty much of commands to be replayed. */
2190 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2191 float rho;
2192 PLIGHTINFOEL *object = NULL;
2193 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2194 struct list *e;
2196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2197 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2199 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2200 * the gl driver.
2202 if(!pLight) {
2203 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2204 return WINED3DERR_INVALIDCALL;
2207 switch(pLight->Type) {
2208 case WINED3DLIGHT_POINT:
2209 case WINED3DLIGHT_SPOT:
2210 case WINED3DLIGHT_PARALLELPOINT:
2211 case WINED3DLIGHT_GLSPOT:
2212 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2213 * most wanted
2215 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2216 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2217 return WINED3DERR_INVALIDCALL;
2219 break;
2221 case WINED3DLIGHT_DIRECTIONAL:
2222 /* Ignores attenuation */
2223 break;
2225 default:
2226 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2227 return WINED3DERR_INVALIDCALL;
2230 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2231 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2232 if(object->OriginalIndex == Index) break;
2233 object = NULL;
2236 if(!object) {
2237 TRACE("Adding new light\n");
2238 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2239 if(!object) {
2240 ERR("Out of memory error when allocating a light\n");
2241 return E_OUTOFMEMORY;
2243 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2244 object->glIndex = -1;
2245 object->OriginalIndex = Index;
2246 object->changed = TRUE;
2249 /* Initialize the object */
2250 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,
2251 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2252 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2253 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2254 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2255 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2256 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2258 /* Save away the information */
2259 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2261 switch (pLight->Type) {
2262 case WINED3DLIGHT_POINT:
2263 /* Position */
2264 object->lightPosn[0] = pLight->Position.x;
2265 object->lightPosn[1] = pLight->Position.y;
2266 object->lightPosn[2] = pLight->Position.z;
2267 object->lightPosn[3] = 1.0f;
2268 object->cutoff = 180.0f;
2269 /* FIXME: Range */
2270 break;
2272 case WINED3DLIGHT_DIRECTIONAL:
2273 /* Direction */
2274 object->lightPosn[0] = -pLight->Direction.x;
2275 object->lightPosn[1] = -pLight->Direction.y;
2276 object->lightPosn[2] = -pLight->Direction.z;
2277 object->lightPosn[3] = 0.0;
2278 object->exponent = 0.0f;
2279 object->cutoff = 180.0f;
2280 break;
2282 case WINED3DLIGHT_SPOT:
2283 /* Position */
2284 object->lightPosn[0] = pLight->Position.x;
2285 object->lightPosn[1] = pLight->Position.y;
2286 object->lightPosn[2] = pLight->Position.z;
2287 object->lightPosn[3] = 1.0;
2289 /* Direction */
2290 object->lightDirn[0] = pLight->Direction.x;
2291 object->lightDirn[1] = pLight->Direction.y;
2292 object->lightDirn[2] = pLight->Direction.z;
2293 object->lightDirn[3] = 1.0;
2296 * opengl-ish and d3d-ish spot lights use too different models for the
2297 * light "intensity" as a function of the angle towards the main light direction,
2298 * so we only can approximate very roughly.
2299 * however spot lights are rather rarely used in games (if ever used at all).
2300 * furthermore if still used, probably nobody pays attention to such details.
2302 if (pLight->Falloff == 0) {
2303 rho = 6.28f;
2304 } else {
2305 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2307 if (rho < 0.0001) rho = 0.0001f;
2308 object->exponent = -0.3/log(cos(rho/2));
2309 if (object->exponent > 128.0) {
2310 object->exponent = 128.0;
2312 object->cutoff = pLight->Phi*90/M_PI;
2314 /* FIXME: Range */
2315 break;
2317 default:
2318 FIXME("Unrecognized light type %d\n", pLight->Type);
2321 /* Update the live definitions if the light is currently assigned a glIndex */
2322 if (object->glIndex != -1 && !This->isRecordingState) {
2323 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2325 return WINED3D_OK;
2328 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2329 PLIGHTINFOEL *lightInfo = NULL;
2330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2331 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2332 struct list *e;
2333 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2335 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2336 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2337 if(lightInfo->OriginalIndex == Index) break;
2338 lightInfo = NULL;
2341 if (lightInfo == NULL) {
2342 TRACE("Light information requested but light not defined\n");
2343 return WINED3DERR_INVALIDCALL;
2346 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2347 return WINED3D_OK;
2350 /*****
2351 * Get / Set Light Enable
2352 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2353 *****/
2354 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2355 PLIGHTINFOEL *lightInfo = NULL;
2356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2357 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2358 struct list *e;
2359 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2361 /* Tests show true = 128...not clear why */
2362 Enable = Enable? 128: 0;
2364 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2365 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2366 if(lightInfo->OriginalIndex == Index) break;
2367 lightInfo = NULL;
2369 TRACE("Found light: %p\n", lightInfo);
2371 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2372 if (lightInfo == NULL) {
2374 TRACE("Light enabled requested but light not defined, so defining one!\n");
2375 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2377 /* Search for it again! Should be fairly quick as near head of list */
2378 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2379 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2380 if(lightInfo->OriginalIndex == Index) break;
2381 lightInfo = NULL;
2383 if (lightInfo == NULL) {
2384 FIXME("Adding default lights has failed dismally\n");
2385 return WINED3DERR_INVALIDCALL;
2389 lightInfo->enabledChanged = TRUE;
2390 if(!Enable) {
2391 if(lightInfo->glIndex != -1) {
2392 if(!This->isRecordingState) {
2393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2396 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2397 lightInfo->glIndex = -1;
2398 } else {
2399 TRACE("Light already disabled, nothing to do\n");
2401 } else {
2402 if (lightInfo->glIndex != -1) {
2403 /* nop */
2404 TRACE("Nothing to do as light was enabled\n");
2405 } else {
2406 int i;
2407 /* Find a free gl light */
2408 for(i = 0; i < This->maxConcurrentLights; i++) {
2409 if(This->stateBlock->activeLights[i] == NULL) {
2410 This->stateBlock->activeLights[i] = lightInfo;
2411 lightInfo->glIndex = i;
2412 break;
2415 if(lightInfo->glIndex == -1) {
2416 ERR("Too many concurrently active lights\n");
2417 return WINED3DERR_INVALIDCALL;
2420 /* i == lightInfo->glIndex */
2421 if(!This->isRecordingState) {
2422 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2427 return WINED3D_OK;
2430 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2432 PLIGHTINFOEL *lightInfo = NULL;
2433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2434 struct list *e;
2435 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2436 TRACE("(%p) : for idx(%d)\n", This, Index);
2438 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2439 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2440 if(lightInfo->OriginalIndex == Index) break;
2441 lightInfo = NULL;
2444 if (lightInfo == NULL) {
2445 TRACE("Light enabled state requested but light not defined\n");
2446 return WINED3DERR_INVALIDCALL;
2448 /* true is 128 according to SetLightEnable */
2449 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2450 return WINED3D_OK;
2453 /*****
2454 * Get / Set Clip Planes
2455 *****/
2456 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2460 /* Validate Index */
2461 if (Index >= GL_LIMITS(clipplanes)) {
2462 TRACE("Application has requested clipplane this device doesn't support\n");
2463 return WINED3DERR_INVALIDCALL;
2466 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2467 This->updateStateBlock->set.clipplane[Index] = TRUE;
2469 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2470 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2471 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2472 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2473 TRACE("Application is setting old values over, nothing to do\n");
2474 return WINED3D_OK;
2477 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2478 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2479 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2480 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2482 /* Handle recording of state blocks */
2483 if (This->isRecordingState) {
2484 TRACE("Recording... not performing anything\n");
2485 return WINED3D_OK;
2488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2490 return WINED3D_OK;
2493 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2495 TRACE("(%p) : for idx %d\n", This, Index);
2497 /* Validate Index */
2498 if (Index >= GL_LIMITS(clipplanes)) {
2499 TRACE("Application has requested clipplane this device doesn't support\n");
2500 return WINED3DERR_INVALIDCALL;
2503 pPlane[0] = This->stateBlock->clipplane[Index][0];
2504 pPlane[1] = This->stateBlock->clipplane[Index][1];
2505 pPlane[2] = This->stateBlock->clipplane[Index][2];
2506 pPlane[3] = This->stateBlock->clipplane[Index][3];
2507 return WINED3D_OK;
2510 /*****
2511 * Get / Set Clip Plane Status
2512 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2513 *****/
2514 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2516 FIXME("(%p) : stub\n", This);
2517 if (NULL == pClipStatus) {
2518 return WINED3DERR_INVALIDCALL;
2520 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2521 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2522 return WINED3D_OK;
2525 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2527 FIXME("(%p) : stub\n", This);
2528 if (NULL == pClipStatus) {
2529 return WINED3DERR_INVALIDCALL;
2531 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2532 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2533 return WINED3D_OK;
2536 /*****
2537 * Get / Set Material
2538 *****/
2539 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 This->updateStateBlock->changed.material = TRUE;
2543 This->updateStateBlock->set.material = TRUE;
2544 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2546 /* Handle recording of state blocks */
2547 if (This->isRecordingState) {
2548 TRACE("Recording... not performing anything\n");
2549 return WINED3D_OK;
2552 ENTER_GL();
2553 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2554 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2555 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2556 pMaterial->Ambient.b, pMaterial->Ambient.a);
2557 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2558 pMaterial->Specular.b, pMaterial->Specular.a);
2559 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2560 pMaterial->Emissive.b, pMaterial->Emissive.a);
2561 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2563 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2564 checkGLcall("glMaterialfv(GL_AMBIENT)");
2565 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2566 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2568 /* Only change material color if specular is enabled, otherwise it is set to black */
2569 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2570 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2571 checkGLcall("glMaterialfv(GL_SPECULAR");
2572 } else {
2573 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2574 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2575 checkGLcall("glMaterialfv(GL_SPECULAR");
2577 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2578 checkGLcall("glMaterialfv(GL_EMISSION)");
2579 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2580 checkGLcall("glMaterialf(GL_SHININESS");
2582 LEAVE_GL();
2583 return WINED3D_OK;
2586 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2589 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2590 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2591 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2592 pMaterial->Ambient.b, pMaterial->Ambient.a);
2593 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2594 pMaterial->Specular.b, pMaterial->Specular.a);
2595 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2596 pMaterial->Emissive.b, pMaterial->Emissive.a);
2597 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2599 return WINED3D_OK;
2602 /*****
2603 * Get / Set Indices
2604 *****/
2605 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2606 UINT BaseVertexIndex) {
2607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2608 IWineD3DIndexBuffer *oldIdxs;
2609 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2611 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2612 oldIdxs = This->updateStateBlock->pIndexData;
2614 This->updateStateBlock->changed.indices = TRUE;
2615 This->updateStateBlock->set.indices = TRUE;
2616 This->updateStateBlock->pIndexData = pIndexData;
2617 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2619 /* Handle recording of state blocks */
2620 if (This->isRecordingState) {
2621 TRACE("Recording... not performing anything\n");
2622 return WINED3D_OK;
2625 /* The base vertex index affects the stream sources, while
2626 * The index buffer is a seperate index buffer state
2628 if(BaseVertexIndex != oldBaseIndex) {
2629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2631 if(oldIdxs != pIndexData) {
2632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2634 return WINED3D_OK;
2637 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2640 *ppIndexData = This->stateBlock->pIndexData;
2642 /* up ref count on ppindexdata */
2643 if (*ppIndexData) {
2644 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2645 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2646 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2647 }else{
2648 TRACE("(%p) No index data set\n", This);
2650 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2652 return WINED3D_OK;
2655 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2656 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 TRACE("(%p)->(%d)\n", This, BaseIndex);
2660 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2661 TRACE("Application is setting the old value over, nothing to do\n");
2662 return WINED3D_OK;
2665 This->updateStateBlock->baseVertexIndex = BaseIndex;
2667 if (This->isRecordingState) {
2668 TRACE("Recording... not performing anything\n");
2669 return WINED3D_OK;
2671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2672 return WINED3D_OK;
2675 /*****
2676 * Get / Set Viewports
2677 *****/
2678 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2681 TRACE("(%p)\n", This);
2682 This->updateStateBlock->changed.viewport = TRUE;
2683 This->updateStateBlock->set.viewport = TRUE;
2684 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2686 /* Handle recording of state blocks */
2687 if (This->isRecordingState) {
2688 TRACE("Recording... not performing anything\n");
2689 return WINED3D_OK;
2692 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2693 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2696 return WINED3D_OK;
2700 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2702 TRACE("(%p)\n", This);
2703 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2704 return WINED3D_OK;
2707 /*****
2708 * Get / Set Render States
2709 * TODO: Verify against dx9 definitions
2710 *****/
2711 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2714 DWORD oldValue = This->stateBlock->renderState[State];
2716 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2718 This->updateStateBlock->changed.renderState[State] = TRUE;
2719 This->updateStateBlock->set.renderState[State] = TRUE;
2720 This->updateStateBlock->renderState[State] = Value;
2722 /* Handle recording of state blocks */
2723 if (This->isRecordingState) {
2724 TRACE("Recording... not performing anything\n");
2725 return WINED3D_OK;
2728 /* Compared here and not before the assignment to allow proper stateblock recording */
2729 if(Value == oldValue) {
2730 TRACE("Application is setting the old value over, nothing to do\n");
2731 } else {
2732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2735 return WINED3D_OK;
2738 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2740 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2741 *pValue = This->stateBlock->renderState[State];
2742 return WINED3D_OK;
2745 /*****
2746 * Get / Set Sampler States
2747 * TODO: Verify against dx9 definitions
2748 *****/
2750 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2755 * SetSampler is designed to allow for more than the standard up to 8 textures
2756 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2757 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2759 * http://developer.nvidia.com/object/General_FAQ.html#t6
2761 * There are two new settings for GForce
2762 * the sampler one:
2763 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2764 * and the texture one:
2765 * GL_MAX_TEXTURE_COORDS_ARB.
2766 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2767 ******************/
2769 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2770 debug_d3dsamplerstate(Type), Type, Value);
2771 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2772 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2773 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2775 /* Handle recording of state blocks */
2776 if (This->isRecordingState) {
2777 TRACE("Recording... not performing anything\n");
2778 return WINED3D_OK;
2781 if(oldValue == Value) {
2782 TRACE("Application is setting the old value over, nothing to do\n");
2783 return WINED3D_OK;
2786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2788 return WINED3D_OK;
2791 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2793 *Value = This->stateBlock->samplerState[Sampler][Type];
2794 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2796 return WINED3D_OK;
2799 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802 This->updateStateBlock->set.scissorRect = TRUE;
2803 This->updateStateBlock->changed.scissorRect = TRUE;
2804 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2805 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2806 return WINED3D_OK;
2808 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2810 if(This->isRecordingState) {
2811 TRACE("Recording... not performing anything\n");
2812 return WINED3D_OK;
2815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2817 return WINED3D_OK;
2820 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2823 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2824 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2825 return WINED3D_OK;
2828 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2830 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2832 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2834 This->updateStateBlock->vertexDecl = pDecl;
2835 This->updateStateBlock->changed.vertexDecl = TRUE;
2836 This->updateStateBlock->set.vertexDecl = TRUE;
2838 if (This->isRecordingState) {
2839 TRACE("Recording... not performing anything\n");
2840 return WINED3D_OK;
2841 } else if(pDecl == oldDecl) {
2842 /* Checked after the assignment to allow proper stateblock recording */
2843 TRACE("Application is setting the old declaration over, nothing to do\n");
2844 return WINED3D_OK;
2847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2848 return WINED3D_OK;
2851 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2854 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2856 *ppDecl = This->stateBlock->vertexDecl;
2857 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2858 return WINED3D_OK;
2861 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2865 This->updateStateBlock->vertexShader = pShader;
2866 This->updateStateBlock->changed.vertexShader = TRUE;
2867 This->updateStateBlock->set.vertexShader = TRUE;
2869 if (This->isRecordingState) {
2870 TRACE("Recording... not performing anything\n");
2871 return WINED3D_OK;
2872 } else if(oldShader == pShader) {
2873 /* Checked here to allow proper stateblock recording */
2874 TRACE("App is setting the old shader over, nothing to do\n");
2875 return WINED3D_OK;
2878 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2882 return WINED3D_OK;
2885 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 if (NULL == ppShader) {
2889 return WINED3DERR_INVALIDCALL;
2891 *ppShader = This->stateBlock->vertexShader;
2892 if( NULL != *ppShader)
2893 IWineD3DVertexShader_AddRef(*ppShader);
2895 TRACE("(%p) : returning %p\n", This, *ppShader);
2896 return WINED3D_OK;
2899 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2900 IWineD3DDevice *iface,
2901 UINT start,
2902 CONST BOOL *srcData,
2903 UINT count) {
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 int i, cnt = min(count, MAX_CONST_B - start);
2908 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2909 iface, srcData, start, count);
2911 if (srcData == NULL || cnt < 0)
2912 return WINED3DERR_INVALIDCALL;
2914 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2915 for (i = 0; i < cnt; i++)
2916 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2918 for (i = start; i < cnt + start; ++i) {
2919 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2920 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2925 return WINED3D_OK;
2928 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2929 IWineD3DDevice *iface,
2930 UINT start,
2931 BOOL *dstData,
2932 UINT count) {
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 int cnt = min(count, MAX_CONST_B - start);
2937 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2938 iface, dstData, start, count);
2940 if (dstData == NULL || cnt < 0)
2941 return WINED3DERR_INVALIDCALL;
2943 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2944 return WINED3D_OK;
2947 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2948 IWineD3DDevice *iface,
2949 UINT start,
2950 CONST int *srcData,
2951 UINT count) {
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2954 int i, cnt = min(count, MAX_CONST_I - start);
2956 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2957 iface, srcData, start, count);
2959 if (srcData == NULL || cnt < 0)
2960 return WINED3DERR_INVALIDCALL;
2962 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2963 for (i = 0; i < cnt; i++)
2964 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2965 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2967 for (i = start; i < cnt + start; ++i) {
2968 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2969 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2978 IWineD3DDevice *iface,
2979 UINT start,
2980 int *dstData,
2981 UINT count) {
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2984 int cnt = min(count, MAX_CONST_I - start);
2986 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2987 iface, dstData, start, count);
2989 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2990 return WINED3DERR_INVALIDCALL;
2992 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2993 return WINED3D_OK;
2996 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2997 IWineD3DDevice *iface,
2998 UINT start,
2999 CONST float *srcData,
3000 UINT count) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 int i;
3005 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3006 iface, srcData, start, count);
3008 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3009 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3010 return WINED3DERR_INVALIDCALL;
3012 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3013 if(TRACE_ON(d3d)) {
3014 for (i = 0; i < count; i++)
3015 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3016 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3019 for (i = start; i < count + start; ++i) {
3020 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3021 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3022 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3023 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3024 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3026 ptr->idx[ptr->count++] = i;
3027 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3029 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3034 return WINED3D_OK;
3037 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3038 IWineD3DDevice *iface,
3039 UINT start,
3040 float *dstData,
3041 UINT count) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3044 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3046 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3047 iface, dstData, start, count);
3049 if (dstData == NULL || cnt < 0)
3050 return WINED3DERR_INVALIDCALL;
3052 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3053 return WINED3D_OK;
3056 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3057 DWORD i;
3058 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3063 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3064 DWORD i, tex;
3065 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3066 * it is never called.
3068 * Rules are:
3069 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3070 * that would be really messy and require shader recompilation
3071 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3072 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3073 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3074 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3076 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3077 if(This->oneToOneTexUnitMap) {
3078 TRACE("Not touching 1:1 map\n");
3079 return;
3081 TRACE("Restoring 1:1 texture unit mapping\n");
3082 /* Restore a 1:1 mapping */
3083 for(i = 0; i < MAX_SAMPLERS; i++) {
3084 if(This->texUnitMap[i] != i) {
3085 This->texUnitMap[i] = i;
3086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3087 markTextureStagesDirty(This, i);
3090 This->oneToOneTexUnitMap = TRUE;
3091 return;
3092 } else {
3093 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3094 * First, see if we can succeed at all
3096 tex = 0;
3097 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3098 if(This->stateBlock->textures[i] == NULL) tex++;
3101 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3102 FIXME("Too many bound textures to support the combiner settings\n");
3103 return;
3106 /* Now work out the mapping */
3107 tex = 0;
3108 This->oneToOneTexUnitMap = FALSE;
3109 WARN("Non 1:1 mapping UNTESTED!\n");
3110 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3111 /* Skip NULL textures */
3112 if (!This->stateBlock->textures[i]) {
3113 /* Map to -1, so the check below doesn't fail if a non-NULL
3114 * texture is set on this stage */
3115 TRACE("Mapping texture stage %d to -1\n", i);
3116 This->texUnitMap[i] = -1;
3118 continue;
3121 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3122 if(This->texUnitMap[i] != tex) {
3123 This->texUnitMap[i] = tex;
3124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3125 markTextureStagesDirty(This, i);
3128 ++tex;
3133 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3136 This->updateStateBlock->pixelShader = pShader;
3137 This->updateStateBlock->changed.pixelShader = TRUE;
3138 This->updateStateBlock->set.pixelShader = TRUE;
3140 /* Handle recording of state blocks */
3141 if (This->isRecordingState) {
3142 TRACE("Recording... not performing anything\n");
3145 if (This->isRecordingState) {
3146 TRACE("Recording... not performing anything\n");
3147 return WINED3D_OK;
3150 if(pShader == oldShader) {
3151 TRACE("App is setting the old pixel shader over, nothing to do\n");
3152 return WINED3D_OK;
3155 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3158 /* Rebuild the texture unit mapping if nvrc's are supported */
3159 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3160 IWineD3DDeviceImpl_FindTexUnitMap(This);
3163 return WINED3D_OK;
3166 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3169 if (NULL == ppShader) {
3170 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3171 return WINED3DERR_INVALIDCALL;
3174 *ppShader = This->stateBlock->pixelShader;
3175 if (NULL != *ppShader) {
3176 IWineD3DPixelShader_AddRef(*ppShader);
3178 TRACE("(%p) : returning %p\n", This, *ppShader);
3179 return WINED3D_OK;
3182 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3183 IWineD3DDevice *iface,
3184 UINT start,
3185 CONST BOOL *srcData,
3186 UINT count) {
3188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 int i, cnt = min(count, MAX_CONST_B - start);
3191 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3192 iface, srcData, start, count);
3194 if (srcData == NULL || cnt < 0)
3195 return WINED3DERR_INVALIDCALL;
3197 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3198 for (i = 0; i < cnt; i++)
3199 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3201 for (i = start; i < cnt + start; ++i) {
3202 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3203 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3208 return WINED3D_OK;
3211 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3212 IWineD3DDevice *iface,
3213 UINT start,
3214 BOOL *dstData,
3215 UINT count) {
3217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3218 int cnt = min(count, MAX_CONST_B - start);
3220 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3221 iface, dstData, start, count);
3223 if (dstData == NULL || cnt < 0)
3224 return WINED3DERR_INVALIDCALL;
3226 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3227 return WINED3D_OK;
3230 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3231 IWineD3DDevice *iface,
3232 UINT start,
3233 CONST int *srcData,
3234 UINT count) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 int i, cnt = min(count, MAX_CONST_I - start);
3239 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3240 iface, srcData, start, count);
3242 if (srcData == NULL || cnt < 0)
3243 return WINED3DERR_INVALIDCALL;
3245 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3246 for (i = 0; i < cnt; i++)
3247 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3248 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3250 for (i = start; i < cnt + start; ++i) {
3251 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3252 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3257 return WINED3D_OK;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3261 IWineD3DDevice *iface,
3262 UINT start,
3263 int *dstData,
3264 UINT count) {
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 int cnt = min(count, MAX_CONST_I - start);
3269 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3270 iface, dstData, start, count);
3272 if (dstData == NULL || cnt < 0)
3273 return WINED3DERR_INVALIDCALL;
3275 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3276 return WINED3D_OK;
3279 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3280 IWineD3DDevice *iface,
3281 UINT start,
3282 CONST float *srcData,
3283 UINT count) {
3285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3286 int i;
3288 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3289 iface, srcData, start, count);
3291 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3292 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3293 return WINED3DERR_INVALIDCALL;
3295 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3296 if(TRACE_ON(d3d)) {
3297 for (i = 0; i < count; i++)
3298 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3299 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3302 for (i = start; i < count + start; ++i) {
3303 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3304 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3305 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3306 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3307 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3309 ptr->idx[ptr->count++] = i;
3310 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3312 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3317 return WINED3D_OK;
3320 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3321 IWineD3DDevice *iface,
3322 UINT start,
3323 float *dstData,
3324 UINT count) {
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3327 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3329 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3330 iface, dstData, start, count);
3332 if (dstData == NULL || cnt < 0)
3333 return WINED3DERR_INVALIDCALL;
3335 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3336 return WINED3D_OK;
3339 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3340 static HRESULT
3341 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3342 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3343 unsigned int i;
3344 DWORD DestFVF = dest->fvf;
3345 WINED3DVIEWPORT vp;
3346 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3347 BOOL doClip;
3348 int numTextures;
3350 if (SrcFVF & WINED3DFVF_NORMAL) {
3351 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3354 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3355 ERR("Source has no position mask\n");
3356 return WINED3DERR_INVALIDCALL;
3359 /* We might access VBOs from this code, so hold the lock */
3360 ENTER_GL();
3362 if (dest->resource.allocatedMemory == NULL) {
3363 /* This may happen if we do direct locking into a vbo. Unlikely,
3364 * but theoretically possible(ddraw processvertices test)
3366 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3367 if(!dest->resource.allocatedMemory) {
3368 LEAVE_GL();
3369 ERR("Out of memory\n");
3370 return E_OUTOFMEMORY;
3372 if(dest->vbo) {
3373 void *src;
3374 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3375 checkGLcall("glBindBufferARB");
3376 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3377 if(src) {
3378 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3380 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3381 checkGLcall("glUnmapBufferARB");
3385 /* Get a pointer into the destination vbo(create one if none exists) and
3386 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3388 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3389 CreateVBO(dest);
3392 if(dest->vbo) {
3393 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3394 if(!dest_conv_addr) {
3395 ERR("Out of memory\n");
3396 /* Continue without storing converted vertices */
3398 dest_conv = dest_conv_addr;
3401 /* Should I clip?
3402 * a) WINED3DRS_CLIPPING is enabled
3403 * b) WINED3DVOP_CLIP is passed
3405 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3406 static BOOL warned = FALSE;
3408 * The clipping code is not quite correct. Some things need
3409 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3410 * so disable clipping for now.
3411 * (The graphics in Half-Life are broken, and my processvertices
3412 * test crashes with IDirect3DDevice3)
3413 doClip = TRUE;
3415 doClip = FALSE;
3416 if(!warned) {
3417 warned = TRUE;
3418 FIXME("Clipping is broken and disabled for now\n");
3420 } else doClip = FALSE;
3421 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3423 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3424 WINED3DTS_VIEW,
3425 &view_mat);
3426 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3427 WINED3DTS_PROJECTION,
3428 &proj_mat);
3429 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3430 WINED3DTS_WORLDMATRIX(0),
3431 &world_mat);
3433 TRACE("View mat:\n");
3434 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);
3435 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);
3436 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);
3437 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);
3439 TRACE("Proj mat:\n");
3440 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);
3441 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);
3442 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);
3443 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);
3445 TRACE("World mat:\n");
3446 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);
3447 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);
3448 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);
3449 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);
3451 /* Get the viewport */
3452 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3453 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3454 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3456 multiply_matrix(&mat,&view_mat,&world_mat);
3457 multiply_matrix(&mat,&proj_mat,&mat);
3459 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3461 for (i = 0; i < dwCount; i+= 1) {
3462 unsigned int tex_index;
3464 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3465 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3466 /* The position first */
3467 float *p =
3468 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3469 float x, y, z, rhw;
3470 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3472 /* Multiplication with world, view and projection matrix */
3473 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);
3474 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);
3475 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);
3476 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);
3478 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3480 /* WARNING: The following things are taken from d3d7 and were not yet checked
3481 * against d3d8 or d3d9!
3484 /* Clipping conditions: From
3485 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3487 * A vertex is clipped if it does not match the following requirements
3488 * -rhw < x <= rhw
3489 * -rhw < y <= rhw
3490 * 0 < z <= rhw
3491 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3493 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3494 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3498 if( !doClip ||
3499 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3500 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3501 ( rhw > eps ) ) ) {
3503 /* "Normal" viewport transformation (not clipped)
3504 * 1) The values are divided by rhw
3505 * 2) The y axis is negative, so multiply it with -1
3506 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3507 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3508 * 4) Multiply x with Width/2 and add Width/2
3509 * 5) The same for the height
3510 * 6) Add the viewpoint X and Y to the 2D coordinates and
3511 * The minimum Z value to z
3512 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3514 * Well, basically it's simply a linear transformation into viewport
3515 * coordinates
3518 x /= rhw;
3519 y /= rhw;
3520 z /= rhw;
3522 y *= -1;
3524 x *= vp.Width / 2;
3525 y *= vp.Height / 2;
3526 z *= vp.MaxZ - vp.MinZ;
3528 x += vp.Width / 2 + vp.X;
3529 y += vp.Height / 2 + vp.Y;
3530 z += vp.MinZ;
3532 rhw = 1 / rhw;
3533 } else {
3534 /* That vertex got clipped
3535 * Contrary to OpenGL it is not dropped completely, it just
3536 * undergoes a different calculation.
3538 TRACE("Vertex got clipped\n");
3539 x += rhw;
3540 y += rhw;
3542 x /= 2;
3543 y /= 2;
3545 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3546 * outside of the main vertex buffer memory. That needs some more
3547 * investigation...
3551 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3554 ( (float *) dest_ptr)[0] = x;
3555 ( (float *) dest_ptr)[1] = y;
3556 ( (float *) dest_ptr)[2] = z;
3557 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3559 dest_ptr += 3 * sizeof(float);
3561 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3562 dest_ptr += sizeof(float);
3565 if(dest_conv) {
3566 float w = 1 / rhw;
3567 ( (float *) dest_conv)[0] = x * w;
3568 ( (float *) dest_conv)[1] = y * w;
3569 ( (float *) dest_conv)[2] = z * w;
3570 ( (float *) dest_conv)[3] = w;
3572 dest_conv += 3 * sizeof(float);
3574 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3575 dest_conv += sizeof(float);
3579 if (DestFVF & WINED3DFVF_PSIZE) {
3580 dest_ptr += sizeof(DWORD);
3581 if(dest_conv) dest_conv += sizeof(DWORD);
3583 if (DestFVF & WINED3DFVF_NORMAL) {
3584 float *normal =
3585 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3586 /* AFAIK this should go into the lighting information */
3587 FIXME("Didn't expect the destination to have a normal\n");
3588 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3589 if(dest_conv) {
3590 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3594 if (DestFVF & WINED3DFVF_DIFFUSE) {
3595 DWORD *color_d =
3596 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3597 if(!color_d) {
3598 static BOOL warned = FALSE;
3600 if(!warned) {
3601 ERR("No diffuse color in source, but destination has one\n");
3602 warned = TRUE;
3605 *( (DWORD *) dest_ptr) = 0xffffffff;
3606 dest_ptr += sizeof(DWORD);
3608 if(dest_conv) {
3609 *( (DWORD *) dest_conv) = 0xffffffff;
3610 dest_conv += sizeof(DWORD);
3613 else {
3614 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3615 if(dest_conv) {
3616 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3617 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3618 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3619 dest_conv += sizeof(DWORD);
3624 if (DestFVF & WINED3DFVF_SPECULAR) {
3625 /* What's the color value in the feedback buffer? */
3626 DWORD *color_s =
3627 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3628 if(!color_s) {
3629 static BOOL warned = FALSE;
3631 if(!warned) {
3632 ERR("No specular color in source, but destination has one\n");
3633 warned = TRUE;
3636 *( (DWORD *) dest_ptr) = 0xFF000000;
3637 dest_ptr += sizeof(DWORD);
3639 if(dest_conv) {
3640 *( (DWORD *) dest_conv) = 0xFF000000;
3641 dest_conv += sizeof(DWORD);
3644 else {
3645 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3646 if(dest_conv) {
3647 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3648 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3649 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3650 dest_conv += sizeof(DWORD);
3655 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3656 float *tex_coord =
3657 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3658 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3659 if(!tex_coord) {
3660 ERR("No source texture, but destination requests one\n");
3661 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3662 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3664 else {
3665 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3666 if(dest_conv) {
3667 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3673 if(dest_conv) {
3674 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3675 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3676 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3677 dwCount * get_flexible_vertex_size(DestFVF),
3678 dest_conv_addr));
3679 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3680 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3683 LEAVE_GL();
3685 return WINED3D_OK;
3687 #undef copy_and_next
3689 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3691 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3692 WineDirect3DVertexStridedData strided;
3693 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3695 if (!SrcImpl) {
3696 WARN("NULL source vertex buffer\n");
3697 return WINED3DERR_INVALIDCALL;
3700 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3701 * and this call is quite performance critical, so don't call needlessly
3703 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3704 ENTER_GL();
3705 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3706 LEAVE_GL();
3709 /* We don't need the source vbo because this buffer is only used as
3710 * a source for ProcessVertices. Avoid wasting resources by converting the
3711 * buffer and loading the VBO
3713 if(SrcImpl->vbo) {
3714 TRACE("Releasing the source vbo, it won't be needed\n");
3716 if(!SrcImpl->resource.allocatedMemory) {
3717 /* Rescue the data from the buffer */
3718 void *src;
3719 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3720 if(!SrcImpl->resource.allocatedMemory) {
3721 ERR("Out of memory\n");
3722 return E_OUTOFMEMORY;
3725 ENTER_GL();
3726 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3727 checkGLcall("glBindBufferARB");
3729 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3730 if(src) {
3731 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3734 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3735 checkGLcall("glUnmapBufferARB");
3736 } else {
3737 ENTER_GL();
3740 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3741 checkGLcall("glBindBufferARB");
3742 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3743 checkGLcall("glDeleteBuffersARB");
3744 LEAVE_GL();
3746 SrcImpl->vbo = 0;
3749 memset(&strided, 0, sizeof(strided));
3750 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3752 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3755 /*****
3756 * Get / Set Texture Stage States
3757 * TODO: Verify against dx9 definitions
3758 *****/
3759 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3763 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3765 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3767 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3768 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3769 This->updateStateBlock->textureState[Stage][Type] = Value;
3771 if (This->isRecordingState) {
3772 TRACE("Recording... not performing anything\n");
3773 return WINED3D_OK;
3776 /* Checked after the assignments to allow proper stateblock recording */
3777 if(oldValue == Value) {
3778 TRACE("App is setting the old value over, nothing to do\n");
3779 return WINED3D_OK;
3782 if(Stage > This->stateBlock->lowest_disabled_stage &&
3783 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3784 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3785 * Changes in other states are important on disabled stages too
3787 return WINED3D_OK;
3790 if(Type == WINED3DTSS_COLOROP) {
3791 int i;
3793 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3794 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3795 * they have to be disabled
3797 * The current stage is dirtified below.
3799 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3800 TRACE("Additionally dirtifying stage %d\n", i);
3801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3803 This->stateBlock->lowest_disabled_stage = Stage;
3804 TRACE("New lowest disabled: %d\n", Stage);
3805 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3806 /* Previously disabled stage enabled. Stages above it may need enabling
3807 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3808 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3810 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3813 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3814 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3815 break;
3817 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3820 This->stateBlock->lowest_disabled_stage = i;
3821 TRACE("New lowest disabled: %d\n", i);
3823 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3824 /* TODO: Built a stage -> texture unit mapping for register combiners */
3828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3830 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3831 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3832 * will call FindTexUnitMap too.
3834 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3835 IWineD3DDeviceImpl_FindTexUnitMap(This);
3837 return WINED3D_OK;
3840 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3843 *pValue = This->updateStateBlock->textureState[Stage][Type];
3844 return WINED3D_OK;
3847 /*****
3848 * Get / Set Texture
3849 *****/
3850 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 IWineD3DBaseTexture *oldTexture;
3855 oldTexture = This->updateStateBlock->textures[Stage];
3856 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3858 #if 0 /* TODO: check so vertex textures */
3859 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3860 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3861 return WINED3D_OK;
3863 #endif
3865 if(pTexture != NULL) {
3866 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3868 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3869 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3870 return WINED3DERR_INVALIDCALL;
3872 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3875 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3876 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3878 This->updateStateBlock->set.textures[Stage] = TRUE;
3879 This->updateStateBlock->changed.textures[Stage] = TRUE;
3880 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3881 This->updateStateBlock->textures[Stage] = pTexture;
3883 /* Handle recording of state blocks */
3884 if (This->isRecordingState) {
3885 TRACE("Recording... not performing anything\n");
3886 return WINED3D_OK;
3889 if(oldTexture == pTexture) {
3890 TRACE("App is setting the same texture again, nothing to do\n");
3891 return WINED3D_OK;
3894 /** NOTE: MSDN says that setTexture increases the reference count,
3895 * and the the application nust set the texture back to null (or have a leaky application),
3896 * This means we should pass the refcount up to the parent
3897 *******************************/
3898 if (NULL != This->updateStateBlock->textures[Stage]) {
3899 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3900 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3902 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3903 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3904 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3905 * so the COLOROP and ALPHAOP have to be dirtified.
3907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3908 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3910 if(bindCount == 1) {
3911 new->baseTexture.sampler = Stage;
3913 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3917 if (NULL != oldTexture) {
3918 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3919 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3921 IWineD3DBaseTexture_Release(oldTexture);
3922 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3927 if(bindCount && old->baseTexture.sampler == Stage) {
3928 int i;
3929 /* Have to do a search for the other sampler(s) where the texture is bound to
3930 * Shouldn't happen as long as apps bind a texture only to one stage
3932 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3933 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3934 if(This->updateStateBlock->textures[i] == oldTexture) {
3935 old->baseTexture.sampler = i;
3936 break;
3942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3944 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3945 * pixel shader is used
3947 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3948 IWineD3DDeviceImpl_FindTexUnitMap(This);
3951 return WINED3D_OK;
3954 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3956 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3958 *ppTexture=This->stateBlock->textures[Stage];
3959 if (*ppTexture)
3960 IWineD3DBaseTexture_AddRef(*ppTexture);
3962 return WINED3D_OK;
3965 /*****
3966 * Get Back Buffer
3967 *****/
3968 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3969 IWineD3DSurface **ppBackBuffer) {
3970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3971 IWineD3DSwapChain *swapChain;
3972 HRESULT hr;
3974 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3976 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3977 if (hr == WINED3D_OK) {
3978 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3979 IWineD3DSwapChain_Release(swapChain);
3980 } else {
3981 *ppBackBuffer = NULL;
3983 return hr;
3986 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3988 WARN("(%p) : stub, calling idirect3d for now\n", This);
3989 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3992 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3994 IWineD3DSwapChain *swapChain;
3995 HRESULT hr;
3997 if(iSwapChain > 0) {
3998 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3999 if (hr == WINED3D_OK) {
4000 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4001 IWineD3DSwapChain_Release(swapChain);
4002 } else {
4003 FIXME("(%p) Error getting display mode\n", This);
4005 } else {
4006 /* Don't read the real display mode,
4007 but return the stored mode instead. X11 can't change the color
4008 depth, and some apps are pretty angry if they SetDisplayMode from
4009 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4011 Also don't relay to the swapchain because with ddraw it's possible
4012 that there isn't a swapchain at all */
4013 pMode->Width = This->ddraw_width;
4014 pMode->Height = This->ddraw_height;
4015 pMode->Format = This->ddraw_format;
4016 pMode->RefreshRate = 0;
4017 hr = WINED3D_OK;
4020 return hr;
4023 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4025 TRACE("(%p)->(%p)\n", This, hWnd);
4027 if(This->ddraw_fullscreen) {
4028 if(This->ddraw_window && This->ddraw_window != hWnd) {
4029 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4031 if(hWnd && This->ddraw_window != hWnd) {
4032 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4036 This->ddraw_window = hWnd;
4037 return WINED3D_OK;
4040 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4042 TRACE("(%p)->(%p)\n", This, hWnd);
4044 *hWnd = This->ddraw_window;
4045 return WINED3D_OK;
4048 /*****
4049 * Stateblock related functions
4050 *****/
4052 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4054 IWineD3DStateBlockImpl *object;
4055 HRESULT temp_result;
4056 int i;
4058 TRACE("(%p)\n", This);
4060 if (This->isRecordingState) {
4061 return WINED3DERR_INVALIDCALL;
4064 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4065 if (NULL == object ) {
4066 FIXME("(%p)Error allocating memory for stateblock\n", This);
4067 return E_OUTOFMEMORY;
4069 TRACE("(%p) created object %p\n", This, object);
4070 object->wineD3DDevice= This;
4071 /** FIXME: object->parent = parent; **/
4072 object->parent = NULL;
4073 object->blockType = WINED3DSBT_ALL;
4074 object->ref = 1;
4075 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4077 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4078 list_init(&object->lightMap[i]);
4081 temp_result = allocate_shader_constants(object);
4082 if (WINED3D_OK != temp_result)
4083 return temp_result;
4085 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4086 This->updateStateBlock = object;
4087 This->isRecordingState = TRUE;
4089 TRACE("(%p) recording stateblock %p\n",This , object);
4090 return WINED3D_OK;
4093 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4096 if (!This->isRecordingState) {
4097 FIXME("(%p) not recording! returning error\n", This);
4098 *ppStateBlock = NULL;
4099 return WINED3DERR_INVALIDCALL;
4102 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4103 This->isRecordingState = FALSE;
4104 This->updateStateBlock = This->stateBlock;
4105 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4106 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4107 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4108 return WINED3D_OK;
4111 /*****
4112 * Scene related functions
4113 *****/
4114 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4115 /* At the moment we have no need for any functionality at the beginning
4116 of a scene */
4117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4118 TRACE("(%p)\n", This);
4120 if(This->inScene) {
4121 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4122 return WINED3DERR_INVALIDCALL;
4124 This->inScene = TRUE;
4125 return WINED3D_OK;
4128 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4130 TRACE("(%p)\n", This);
4132 if(!This->inScene) {
4133 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4134 return WINED3DERR_INVALIDCALL;
4137 ENTER_GL();
4138 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4139 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4141 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4142 glFlush();
4143 checkGLcall("glFlush");
4144 LEAVE_GL();
4146 This->inScene = FALSE;
4147 return WINED3D_OK;
4150 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4151 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4152 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4154 IWineD3DSwapChain *swapChain = NULL;
4155 int i;
4156 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4158 TRACE("(%p) Presenting the frame\n", This);
4160 for(i = 0 ; i < swapchains ; i ++) {
4162 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4163 TRACE("presentinng chain %d, %p\n", i, swapChain);
4164 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4165 IWineD3DSwapChain_Release(swapChain);
4168 return WINED3D_OK;
4171 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4172 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4174 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4176 GLbitfield glMask = 0;
4177 unsigned int i;
4178 CONST WINED3DRECT* curRect;
4180 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4181 Count, pRects, Flags, Z, Stencil);
4183 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4184 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4185 /* TODO: What about depth stencil buffers without stencil bits? */
4186 return WINED3DERR_INVALIDCALL;
4189 ENTER_GL();
4190 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4191 * and not the last active one.
4193 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4195 glEnable(GL_SCISSOR_TEST);
4196 checkGLcall("glEnable GL_SCISSOR_TEST");
4197 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4200 if (Count > 0 && pRects) {
4201 curRect = pRects;
4202 } else {
4203 curRect = NULL;
4206 /* Only set the values up once, as they are not changing */
4207 if (Flags & WINED3DCLEAR_STENCIL) {
4208 glClearStencil(Stencil);
4209 checkGLcall("glClearStencil");
4210 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4211 glStencilMask(0xFFFFFFFF);
4214 if (Flags & WINED3DCLEAR_ZBUFFER) {
4215 glDepthMask(GL_TRUE);
4216 glClearDepth(Z);
4217 checkGLcall("glClearDepth");
4218 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4222 if (Flags & WINED3DCLEAR_TARGET) {
4223 TRACE("Clearing screen with glClear to color %x\n", Color);
4224 glClearColor(D3DCOLOR_R(Color),
4225 D3DCOLOR_G(Color),
4226 D3DCOLOR_B(Color),
4227 D3DCOLOR_A(Color));
4228 checkGLcall("glClearColor");
4230 /* Clear ALL colors! */
4231 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4232 glMask = glMask | GL_COLOR_BUFFER_BIT;
4235 if (!curRect) {
4236 /* In drawable flag is set below */
4238 glScissor(This->stateBlock->viewport.X,
4239 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4240 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4241 This->stateBlock->viewport.Width,
4242 This->stateBlock->viewport.Height);
4243 checkGLcall("glScissor");
4244 glClear(glMask);
4245 checkGLcall("glClear");
4246 } else {
4247 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4248 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4250 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4251 curRect[0].x2 < target->currentDesc.Width ||
4252 curRect[0].y2 < target->currentDesc.Height) {
4253 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4254 blt_to_drawable(This, target);
4258 /* Now process each rect in turn */
4259 for (i = 0; i < Count; i++) {
4260 /* Note gl uses lower left, width/height */
4261 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4262 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4263 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4264 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4266 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4267 * The rectangle is not cleared, no error is returned, but further rectanlges are
4268 * still cleared if they are valid
4270 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4271 TRACE("Rectangle with negative dimensions, ignoring\n");
4272 continue;
4275 if(This->render_offscreen) {
4276 glScissor(curRect[i].x1, curRect[i].y1,
4277 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4278 } else {
4279 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4280 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4282 checkGLcall("glScissor");
4284 glClear(glMask);
4285 checkGLcall("glClear");
4289 /* Restore the old values (why..?) */
4290 if (Flags & WINED3DCLEAR_STENCIL) {
4291 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4293 if (Flags & WINED3DCLEAR_TARGET) {
4294 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4295 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4296 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4297 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4298 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4301 LEAVE_GL();
4303 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4304 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4306 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4307 target->Flags |= SFLAG_INTEXTURE;
4308 target->Flags &= ~SFLAG_INSYSMEM;
4309 } else {
4310 target->Flags |= SFLAG_INDRAWABLE;
4311 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4313 return WINED3D_OK;
4316 /*****
4317 * Drawing functions
4318 *****/
4319 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4320 UINT PrimitiveCount) {
4322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4324 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4325 debug_d3dprimitivetype(PrimitiveType),
4326 StartVertex, PrimitiveCount);
4328 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4329 if(This->stateBlock->streamIsUP) {
4330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4331 This->stateBlock->streamIsUP = FALSE;
4334 if(This->stateBlock->loadBaseVertexIndex != 0) {
4335 This->stateBlock->loadBaseVertexIndex = 0;
4336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4338 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4339 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4340 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4341 return WINED3D_OK;
4344 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4345 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4346 WINED3DPRIMITIVETYPE PrimitiveType,
4347 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4350 UINT idxStride = 2;
4351 IWineD3DIndexBuffer *pIB;
4352 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4353 GLuint vbo;
4355 if(This->stateBlock->streamIsUP) {
4356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4357 This->stateBlock->streamIsUP = FALSE;
4359 pIB = This->stateBlock->pIndexData;
4360 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4362 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4363 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4364 minIndex, NumVertices, startIndex, primCount);
4366 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4367 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4368 idxStride = 2;
4369 } else {
4370 idxStride = 4;
4373 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4374 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4378 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4379 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4381 return WINED3D_OK;
4384 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4385 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4386 UINT VertexStreamZeroStride) {
4387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4389 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4390 debug_d3dprimitivetype(PrimitiveType),
4391 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4393 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4394 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4395 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4396 This->stateBlock->streamIsUP = TRUE;
4397 This->stateBlock->loadBaseVertexIndex = 0;
4399 /* TODO: Only mark dirty if drawing from a different UP address */
4400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4402 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4403 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4405 /* MSDN specifies stream zero settings must be set to NULL */
4406 This->stateBlock->streamStride[0] = 0;
4407 This->stateBlock->streamSource[0] = NULL;
4409 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4410 * the new stream sources or use UP drawing again
4412 return WINED3D_OK;
4415 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4416 UINT MinVertexIndex, UINT NumVertices,
4417 UINT PrimitiveCount, CONST void* pIndexData,
4418 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4419 UINT VertexStreamZeroStride) {
4420 int idxStride;
4421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4423 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4424 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4425 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4426 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4428 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4429 idxStride = 2;
4430 } else {
4431 idxStride = 4;
4434 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4435 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4436 This->stateBlock->streamIsUP = TRUE;
4437 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4439 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4440 This->stateBlock->baseVertexIndex = 0;
4441 This->stateBlock->loadBaseVertexIndex = 0;
4442 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4446 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4448 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4449 This->stateBlock->streamSource[0] = NULL;
4450 This->stateBlock->streamStride[0] = 0;
4451 This->stateBlock->pIndexData = NULL;
4452 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4453 * SetStreamSource to specify a vertex buffer
4456 return WINED3D_OK;
4459 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4462 /* Mark the state dirty until we have nicer tracking
4463 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4464 * that value.
4466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4468 This->stateBlock->baseVertexIndex = 0;
4469 This->up_strided = DrawPrimStrideData;
4470 This->stateBlock->streamIsUP = TRUE;
4471 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4472 This->up_strided = NULL;
4473 return WINED3D_OK;
4475 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4476 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4478 HRESULT hr = WINED3D_OK;
4479 WINED3DRESOURCETYPE sourceType;
4480 WINED3DRESOURCETYPE destinationType;
4481 int i ,levels;
4483 /* TODO: think about moving the code into IWineD3DBaseTexture */
4485 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4487 /* verify that the source and destination textures aren't NULL */
4488 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4489 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4490 This, pSourceTexture, pDestinationTexture);
4491 hr = WINED3DERR_INVALIDCALL;
4494 if (pSourceTexture == pDestinationTexture) {
4495 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4496 This, pSourceTexture, pDestinationTexture);
4497 hr = WINED3DERR_INVALIDCALL;
4499 /* Verify that the source and destination textures are the same type */
4500 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4501 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4503 if (sourceType != destinationType) {
4504 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4505 This);
4506 hr = WINED3DERR_INVALIDCALL;
4509 /* check that both textures have the identical numbers of levels */
4510 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4511 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4512 hr = WINED3DERR_INVALIDCALL;
4515 if (WINED3D_OK == hr) {
4517 /* Make sure that the destination texture is loaded */
4518 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4520 /* Update every surface level of the texture */
4521 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4523 switch (sourceType) {
4524 case WINED3DRTYPE_TEXTURE:
4526 IWineD3DSurface *srcSurface;
4527 IWineD3DSurface *destSurface;
4529 for (i = 0 ; i < levels ; ++i) {
4530 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4531 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4532 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4533 IWineD3DSurface_Release(srcSurface);
4534 IWineD3DSurface_Release(destSurface);
4535 if (WINED3D_OK != hr) {
4536 WARN("(%p) : Call to update surface failed\n", This);
4537 return hr;
4541 break;
4542 case WINED3DRTYPE_CUBETEXTURE:
4544 IWineD3DSurface *srcSurface;
4545 IWineD3DSurface *destSurface;
4546 WINED3DCUBEMAP_FACES faceType;
4548 for (i = 0 ; i < levels ; ++i) {
4549 /* Update each cube face */
4550 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4551 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4552 if (WINED3D_OK != hr) {
4553 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4554 } else {
4555 TRACE("Got srcSurface %p\n", srcSurface);
4557 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4558 if (WINED3D_OK != hr) {
4559 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4560 } else {
4561 TRACE("Got desrSurface %p\n", destSurface);
4563 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4564 IWineD3DSurface_Release(srcSurface);
4565 IWineD3DSurface_Release(destSurface);
4566 if (WINED3D_OK != hr) {
4567 WARN("(%p) : Call to update surface failed\n", This);
4568 return hr;
4573 break;
4574 #if 0 /* TODO: Add support for volume textures */
4575 case WINED3DRTYPE_VOLUMETEXTURE:
4577 IWineD3DVolume srcVolume = NULL;
4578 IWineD3DSurface destVolume = NULL;
4580 for (i = 0 ; i < levels ; ++i) {
4581 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4582 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4583 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4584 IWineD3DVolume_Release(srcSurface);
4585 IWineD3DVolume_Release(destSurface);
4586 if (WINED3D_OK != hr) {
4587 WARN("(%p) : Call to update volume failed\n", This);
4588 return hr;
4592 break;
4593 #endif
4594 default:
4595 FIXME("(%p) : Unsupported source and destination type\n", This);
4596 hr = WINED3DERR_INVALIDCALL;
4600 return hr;
4603 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4604 IWineD3DSwapChain *swapChain;
4605 HRESULT hr;
4606 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4607 if(hr == WINED3D_OK) {
4608 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4609 IWineD3DSwapChain_Release(swapChain);
4611 return hr;
4614 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 /* return a sensible default */
4617 *pNumPasses = 1;
4618 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4619 FIXME("(%p) : stub\n", This);
4620 return WINED3D_OK;
4623 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4625 int j;
4626 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4627 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4628 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4629 return WINED3DERR_INVALIDCALL;
4631 for (j = 0; j < 256; ++j) {
4632 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4633 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4634 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4635 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4637 TRACE("(%p) : returning\n", This);
4638 return WINED3D_OK;
4641 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4643 int j;
4644 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4645 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4646 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4647 return WINED3DERR_INVALIDCALL;
4649 for (j = 0; j < 256; ++j) {
4650 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4651 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4652 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4653 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4655 TRACE("(%p) : returning\n", This);
4656 return WINED3D_OK;
4659 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4661 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4662 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4663 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4664 return WINED3DERR_INVALIDCALL;
4666 /*TODO: stateblocks */
4667 This->currentPalette = PaletteNumber;
4668 TRACE("(%p) : returning\n", This);
4669 return WINED3D_OK;
4672 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4674 if (PaletteNumber == NULL) {
4675 WARN("(%p) : returning Invalid Call\n", This);
4676 return WINED3DERR_INVALIDCALL;
4678 /*TODO: stateblocks */
4679 *PaletteNumber = This->currentPalette;
4680 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4681 return WINED3D_OK;
4684 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4686 static BOOL showFixmes = TRUE;
4687 if (showFixmes) {
4688 FIXME("(%p) : stub\n", This);
4689 showFixmes = FALSE;
4692 This->softwareVertexProcessing = bSoftware;
4693 return WINED3D_OK;
4697 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4699 static BOOL showFixmes = TRUE;
4700 if (showFixmes) {
4701 FIXME("(%p) : stub\n", This);
4702 showFixmes = FALSE;
4704 return This->softwareVertexProcessing;
4708 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4710 IWineD3DSwapChain *swapChain;
4711 HRESULT hr;
4713 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4715 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4716 if(hr == WINED3D_OK){
4717 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4718 IWineD3DSwapChain_Release(swapChain);
4719 }else{
4720 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4722 return hr;
4726 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4728 static BOOL showfixmes = TRUE;
4729 if(nSegments != 0.0f) {
4730 if( showfixmes) {
4731 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4732 showfixmes = FALSE;
4735 return WINED3D_OK;
4738 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 static BOOL showfixmes = TRUE;
4741 if( showfixmes) {
4742 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4743 showfixmes = FALSE;
4745 return 0.0f;
4748 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4750 /** TODO: remove casts to IWineD3DSurfaceImpl
4751 * NOTE: move code to surface to accomplish this
4752 ****************************************/
4753 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4754 int srcWidth, srcHeight;
4755 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4756 WINED3DFORMAT destFormat, srcFormat;
4757 UINT destSize;
4758 int srcLeft, destLeft, destTop;
4759 WINED3DPOOL srcPool, destPool;
4760 int offset = 0;
4761 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4762 glDescriptor *glDescription = NULL;
4764 WINED3DSURFACE_DESC winedesc;
4766 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4767 memset(&winedesc, 0, sizeof(winedesc));
4768 winedesc.Width = &srcSurfaceWidth;
4769 winedesc.Height = &srcSurfaceHeight;
4770 winedesc.Pool = &srcPool;
4771 winedesc.Format = &srcFormat;
4773 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4775 winedesc.Width = &destSurfaceWidth;
4776 winedesc.Height = &destSurfaceHeight;
4777 winedesc.Pool = &destPool;
4778 winedesc.Format = &destFormat;
4779 winedesc.Size = &destSize;
4781 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4783 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4784 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4785 return WINED3DERR_INVALIDCALL;
4788 if (destFormat == WINED3DFMT_UNKNOWN) {
4789 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4790 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4792 /* Get the update surface description */
4793 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4796 ENTER_GL();
4798 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4800 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4801 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4802 checkGLcall("glActiveTextureARB");
4805 /* Make sure the surface is loaded and up to date */
4806 IWineD3DSurface_PreLoad(pDestinationSurface);
4808 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4810 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4811 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4812 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4813 srcLeft = pSourceRect ? pSourceRect->left : 0;
4814 destLeft = pDestPoint ? pDestPoint->x : 0;
4815 destTop = pDestPoint ? pDestPoint->y : 0;
4818 /* This function doesn't support compressed textures
4819 the pitch is just bytesPerPixel * width */
4820 if(srcWidth != srcSurfaceWidth || srcLeft ){
4821 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4822 offset += srcLeft * pSrcSurface->bytesPerPixel;
4823 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4825 /* TODO DXT formats */
4827 if(pSourceRect != NULL && pSourceRect->top != 0){
4828 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4830 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4831 ,This
4832 ,glDescription->level
4833 ,destLeft
4834 ,destTop
4835 ,srcWidth
4836 ,srcHeight
4837 ,glDescription->glFormat
4838 ,glDescription->glType
4839 ,IWineD3DSurface_GetData(pSourceSurface)
4842 /* Sanity check */
4843 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4845 /* need to lock the surface to get the data */
4846 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4849 /* TODO: Cube and volume support */
4850 if(rowoffset != 0){
4851 /* not a whole row so we have to do it a line at a time */
4852 int j;
4854 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4855 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4857 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4859 glTexSubImage2D(glDescription->target
4860 ,glDescription->level
4861 ,destLeft
4863 ,srcWidth
4865 ,glDescription->glFormat
4866 ,glDescription->glType
4867 ,data /* could be quicker using */
4869 data += rowoffset;
4872 } else { /* Full width, so just write out the whole texture */
4874 if (WINED3DFMT_DXT1 == destFormat ||
4875 WINED3DFMT_DXT2 == destFormat ||
4876 WINED3DFMT_DXT3 == destFormat ||
4877 WINED3DFMT_DXT4 == destFormat ||
4878 WINED3DFMT_DXT5 == destFormat) {
4879 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4880 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4881 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4882 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4883 } if (destFormat != srcFormat) {
4884 FIXME("Updating mixed format compressed texture is not curretly support\n");
4885 } else {
4886 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4887 glDescription->level,
4888 glDescription->glFormatInternal,
4889 srcWidth,
4890 srcHeight,
4892 destSize,
4893 IWineD3DSurface_GetData(pSourceSurface));
4895 } else {
4896 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4900 } else {
4901 glTexSubImage2D(glDescription->target
4902 ,glDescription->level
4903 ,destLeft
4904 ,destTop
4905 ,srcWidth
4906 ,srcHeight
4907 ,glDescription->glFormat
4908 ,glDescription->glType
4909 ,IWineD3DSurface_GetData(pSourceSurface)
4913 checkGLcall("glTexSubImage2D");
4915 LEAVE_GL();
4917 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
4918 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
4919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4921 return WINED3D_OK;
4924 /* Implementation details at http://developer.nvidia.com/attach/6494
4926 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4927 hmm.. no longer supported use
4928 OpenGL evaluators or tessellate surfaces within your application.
4931 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4932 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4934 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4935 FIXME("(%p) : Stub\n", This);
4936 return WINED3D_OK;
4940 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4941 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4943 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4944 FIXME("(%p) : Stub\n", This);
4945 return WINED3D_OK;
4948 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4950 TRACE("(%p) Handle(%d)\n", This, Handle);
4951 FIXME("(%p) : Stub\n", This);
4952 return WINED3D_OK;
4955 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4957 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4958 DDBLTFX BltFx;
4959 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4961 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4962 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4963 return WINED3DERR_INVALIDCALL;
4966 /* Just forward this to the DirectDraw blitting engine */
4967 memset(&BltFx, 0, sizeof(BltFx));
4968 BltFx.dwSize = sizeof(BltFx);
4969 BltFx.u5.dwFillColor = color;
4970 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4973 /* rendertarget and deptth stencil functions */
4974 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4977 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4978 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4979 return WINED3DERR_INVALIDCALL;
4982 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4983 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4984 /* Note inc ref on returned surface */
4985 if(*ppRenderTarget != NULL)
4986 IWineD3DSurface_AddRef(*ppRenderTarget);
4987 return WINED3D_OK;
4990 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4992 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4993 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4994 IWineD3DSwapChainImpl *Swapchain;
4995 HRESULT hr;
4997 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4999 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5000 if(hr != WINED3D_OK) {
5001 ERR("Can't get the swapchain\n");
5002 return hr;
5005 /* Make sure to release the swapchain */
5006 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5008 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5009 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5010 return WINED3DERR_INVALIDCALL;
5012 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5013 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5014 return WINED3DERR_INVALIDCALL;
5017 if(Swapchain->frontBuffer != Front) {
5018 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5020 if(Swapchain->frontBuffer)
5021 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5022 Swapchain->frontBuffer = Front;
5024 if(Swapchain->frontBuffer) {
5025 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5029 if(Back && !Swapchain->backBuffer) {
5030 /* We need memory for the back buffer array - only one back buffer this way */
5031 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5032 if(!Swapchain->backBuffer) {
5033 ERR("Out of memory\n");
5034 return E_OUTOFMEMORY;
5038 if(Swapchain->backBuffer[0] != Back) {
5039 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5041 /* What to do about the context here in the case of multithreading? Not sure.
5042 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5044 ENTER_GL();
5045 if(!Swapchain->backBuffer[0]) {
5046 /* GL was told to draw to the front buffer at creation,
5047 * undo that
5049 glDrawBuffer(GL_BACK);
5050 checkGLcall("glDrawBuffer(GL_BACK)");
5051 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5052 Swapchain->presentParms.BackBufferCount = 1;
5053 } else if (!Back) {
5054 /* That makes problems - disable for now */
5055 /* glDrawBuffer(GL_FRONT); */
5056 checkGLcall("glDrawBuffer(GL_FRONT)");
5057 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5058 Swapchain->presentParms.BackBufferCount = 0;
5060 LEAVE_GL();
5062 if(Swapchain->backBuffer[0])
5063 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5064 Swapchain->backBuffer[0] = Back;
5066 if(Swapchain->backBuffer[0]) {
5067 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5068 } else {
5069 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5074 return WINED3D_OK;
5077 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5079 *ppZStencilSurface = This->depthStencilBuffer;
5080 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5082 if(*ppZStencilSurface != NULL) {
5083 /* Note inc ref on returned surface */
5084 IWineD3DSurface_AddRef(*ppZStencilSurface);
5086 return WINED3D_OK;
5089 static void bind_fbo(IWineD3DDevice *iface) {
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5092 if (!This->fbo) {
5093 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5094 checkGLcall("glGenFramebuffersEXT()");
5096 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5097 checkGLcall("glBindFramebuffer()");
5100 /* TODO: Handle stencil attachments */
5101 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5103 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5105 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5107 bind_fbo(iface);
5109 if (depth_stencil_impl) {
5110 GLenum texttarget, target;
5111 GLint old_binding = 0;
5113 IWineD3DSurface_PreLoad(depth_stencil);
5114 texttarget = depth_stencil_impl->glDescription.target;
5115 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5117 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5118 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5119 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5120 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5121 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5122 glBindTexture(target, old_binding);
5124 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5125 checkGLcall("glFramebufferTexture2DEXT()");
5126 } else {
5127 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5128 checkGLcall("glFramebufferTexture2DEXT()");
5131 if (!This->render_offscreen) {
5132 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5133 checkGLcall("glBindFramebuffer()");
5137 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5139 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5141 if (idx >= GL_LIMITS(buffers)) {
5142 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5145 bind_fbo(iface);
5147 if (rtimpl) {
5148 GLenum texttarget, target;
5149 GLint old_binding = 0;
5151 IWineD3DSurface_PreLoad(render_target);
5152 texttarget = rtimpl->glDescription.target;
5153 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5155 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5156 glBindTexture(target, rtimpl->glDescription.textureName);
5157 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5158 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5159 glBindTexture(target, old_binding);
5161 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5162 checkGLcall("glFramebufferTexture2DEXT()");
5164 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5165 } else {
5166 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5167 checkGLcall("glFramebufferTexture2DEXT()");
5169 This->draw_buffers[idx] = GL_NONE;
5172 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5173 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5174 checkGLcall("glDrawBuffers()");
5177 if (!This->render_offscreen) {
5178 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5179 checkGLcall("glBindFramebuffer()");
5183 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5185 WINED3DVIEWPORT viewport;
5187 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5189 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5190 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5191 return WINED3DERR_INVALIDCALL;
5194 /* MSDN says that null disables the render target
5195 but a device must always be associated with a render target
5196 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5198 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5199 for more details
5201 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5202 FIXME("Trying to set render target 0 to NULL\n");
5203 return WINED3DERR_INVALIDCALL;
5205 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5206 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);
5207 return WINED3DERR_INVALIDCALL;
5210 /* If we are trying to set what we already have, don't bother */
5211 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5212 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5213 return WINED3D_OK;
5215 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5216 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5217 This->render_targets[RenderTargetIndex] = pRenderTarget;
5219 /* Render target 0 is special */
5220 if(RenderTargetIndex == 0) {
5221 /* Finally, reset the viewport as the MSDN states. */
5222 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5223 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5224 viewport.X = 0;
5225 viewport.Y = 0;
5226 viewport.MaxZ = 1.0f;
5227 viewport.MinZ = 0.0f;
5228 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5229 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5230 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5234 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5235 * ctx properly.
5236 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5237 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5239 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5240 } else {
5241 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5242 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5244 return WINED3D_OK;
5247 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5248 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5249 HRESULT hr = WINED3D_OK;
5250 IWineD3DSurface *tmp;
5252 TRACE("(%p) Swapping z-buffer\n",This);
5254 if (pNewZStencil == This->stencilBufferTarget) {
5255 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5256 } else {
5257 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5258 * depending on the renter target implementation being used.
5259 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5260 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5261 * stencil buffer and incure an extra memory overhead
5262 ******************************************************/
5264 tmp = This->stencilBufferTarget;
5265 This->stencilBufferTarget = pNewZStencil;
5266 /* should we be calling the parent or the wined3d surface? */
5267 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5268 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5269 hr = WINED3D_OK;
5271 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5272 set_depth_stencil_fbo(iface, pNewZStencil);
5275 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5276 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5277 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5283 return hr;
5286 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5287 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5289 /* TODO: the use of Impl is deprecated. */
5290 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5292 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5294 /* some basic validation checks */
5295 if(This->cursorTexture) {
5296 ENTER_GL();
5297 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5298 glDeleteTextures(1, &This->cursorTexture);
5299 LEAVE_GL();
5300 This->cursorTexture = 0;
5303 if(pCursorBitmap) {
5304 WINED3DLOCKED_RECT rect;
5306 /* MSDN: Cursor must be A8R8G8B8 */
5307 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5308 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5309 return WINED3DERR_INVALIDCALL;
5312 /* MSDN: Cursor must be smaller than the display mode */
5313 if(pSur->currentDesc.Width > This->ddraw_width ||
5314 pSur->currentDesc.Height > This->ddraw_height) {
5315 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);
5316 return WINED3DERR_INVALIDCALL;
5319 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5321 /* Do not store the surface's pointer because the application may release
5322 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5323 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5325 This->cursorWidth = pSur->currentDesc.Width;
5326 This->cursorHeight = pSur->currentDesc.Height;
5327 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5329 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5330 char *mem, *bits = (char *)rect.pBits;
5331 GLint intfmt = tableEntry->glInternal;
5332 GLint format = tableEntry->glFormat;
5333 GLint type = tableEntry->glType;
5334 INT height = This->cursorHeight;
5335 INT width = This->cursorWidth;
5336 INT bpp = tableEntry->bpp;
5337 INT i;
5339 /* Reformat the texture memory (pitch and width can be different) */
5340 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5341 for(i = 0; i < height; i++)
5342 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5343 IWineD3DSurface_UnlockRect(pCursorBitmap);
5344 ENTER_GL();
5345 /* Make sure that a proper texture unit is selected */
5346 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5347 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5348 checkGLcall("glActiveTextureARB");
5350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5351 /* Create a new cursor texture */
5352 glGenTextures(1, &This->cursorTexture);
5353 checkGLcall("glGenTextures");
5354 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5355 checkGLcall("glBindTexture");
5356 /* Copy the bitmap memory into the cursor texture */
5357 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5358 HeapFree(GetProcessHeap(), 0, mem);
5359 checkGLcall("glTexImage2D");
5360 LEAVE_GL();
5362 else
5364 FIXME("A cursor texture was not returned.\n");
5365 This->cursorTexture = 0;
5370 This->xHotSpot = XHotSpot;
5371 This->yHotSpot = YHotSpot;
5372 return WINED3D_OK;
5375 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5377 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5379 This->xScreenSpace = XScreenSpace;
5380 This->yScreenSpace = YScreenSpace;
5382 return;
5386 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5388 BOOL oldVisible = This->bCursorVisible;
5389 POINT pt;
5391 TRACE("(%p) : visible(%d)\n", This, bShow);
5393 if(This->cursorTexture)
5394 This->bCursorVisible = bShow;
5396 * When ShowCursor is first called it should make the cursor appear at the OS's last
5397 * known cursor position. Because of this, some applications just repetitively call
5398 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5400 GetCursorPos(&pt);
5401 This->xScreenSpace = pt.x;
5402 This->yScreenSpace = pt.y;
5404 return oldVisible;
5407 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5409 TRACE("(%p) : state (%u)\n", This, This->state);
5410 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5411 switch (This->state) {
5412 case WINED3D_OK:
5413 return WINED3D_OK;
5414 case WINED3DERR_DEVICELOST:
5416 ResourceList *resourceList = This->resources;
5417 while (NULL != resourceList) {
5418 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5419 return WINED3DERR_DEVICENOTRESET;
5420 resourceList = resourceList->next;
5422 return WINED3DERR_DEVICELOST;
5424 case WINED3DERR_DRIVERINTERNALERROR:
5425 return WINED3DERR_DRIVERINTERNALERROR;
5428 /* Unknown state */
5429 return WINED3DERR_DRIVERINTERNALERROR;
5433 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5435 /** FIXME: Resource tracking needs to be done,
5436 * The closes we can do to this is set the priorities of all managed textures low
5437 * and then reset them.
5438 ***********************************************************/
5439 FIXME("(%p) : stub\n", This);
5440 return WINED3D_OK;
5443 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5444 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5446 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5447 if(surface->Flags & SFLAG_DIBSECTION) {
5448 /* Release the DC */
5449 SelectObject(surface->hDC, surface->dib.holdbitmap);
5450 DeleteDC(surface->hDC);
5451 /* Release the DIB section */
5452 DeleteObject(surface->dib.DIBsection);
5453 surface->dib.bitmap_data = NULL;
5454 surface->resource.allocatedMemory = NULL;
5455 surface->Flags &= ~SFLAG_DIBSECTION;
5457 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5458 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5459 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5460 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5461 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5462 } else {
5463 surface->pow2Width = surface->pow2Height = 1;
5464 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5465 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5467 if(surface->glDescription.textureName) {
5468 ENTER_GL();
5469 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5470 glDeleteTextures(1, &surface->glDescription.textureName);
5471 LEAVE_GL();
5472 surface->glDescription.textureName = 0;
5474 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5475 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5476 surface->Flags |= SFLAG_NONPOW2;
5477 } else {
5478 surface->Flags &= ~SFLAG_NONPOW2;
5480 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5481 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5484 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5486 IWineD3DSwapChainImpl *swapchain;
5487 HRESULT hr;
5488 BOOL DisplayModeChanged = FALSE;
5489 WINED3DDISPLAYMODE mode;
5490 TRACE("(%p)\n", This);
5492 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5493 if(FAILED(hr)) {
5494 ERR("Failed to get the first implicit swapchain\n");
5495 return hr;
5498 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5499 * on an existing gl context, so there's no real need for recreation.
5501 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5503 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5505 TRACE("New params:\n");
5506 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5507 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5508 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5509 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5510 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5511 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5512 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5513 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5514 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5515 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5516 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5517 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5518 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5520 /* No special treatment of these parameters. Just store them */
5521 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5522 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5523 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5524 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5526 /* What to do about these? */
5527 if(pPresentationParameters->BackBufferCount != 0 &&
5528 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5529 ERR("Cannot change the back buffer count yet\n");
5531 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5532 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5533 ERR("Cannot change the back buffer format yet\n");
5535 if(pPresentationParameters->hDeviceWindow != NULL &&
5536 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5537 ERR("Cannot change the device window yet\n");
5539 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5540 ERR("What do do about a changed auto depth stencil parameter?\n");
5543 if(pPresentationParameters->Windowed) {
5544 mode.Width = swapchain->orig_width;
5545 mode.Height = swapchain->orig_height;
5546 mode.RefreshRate = 0;
5547 mode.Format = swapchain->presentParms.BackBufferFormat;
5548 } else {
5549 mode.Width = pPresentationParameters->BackBufferWidth;
5550 mode.Height = pPresentationParameters->BackBufferHeight;
5551 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5552 mode.Format = swapchain->presentParms.BackBufferFormat;
5555 /* Should Width == 800 && Height == 0 set 800x600? */
5556 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5557 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5558 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5560 WINED3DVIEWPORT vp;
5561 int i;
5563 vp.X = 0;
5564 vp.Y = 0;
5565 vp.Width = pPresentationParameters->BackBufferWidth;
5566 vp.Height = pPresentationParameters->BackBufferHeight;
5567 vp.MinZ = 0;
5568 vp.MaxZ = 1;
5570 if(!pPresentationParameters->Windowed) {
5571 DisplayModeChanged = TRUE;
5573 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5574 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5576 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5577 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5578 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5581 /* Now set the new viewport */
5582 IWineD3DDevice_SetViewport(iface, &vp);
5585 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5586 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5587 DisplayModeChanged) {
5589 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5590 if(!pPresentationParameters->Windowed) {
5591 IWineD3DDevice_SetFullscreen(iface, TRUE);
5594 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5596 /* Switching out of fullscreen mode? First set the original res, then change the window */
5597 if(pPresentationParameters->Windowed) {
5598 IWineD3DDevice_SetFullscreen(iface, FALSE);
5600 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5603 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5604 return WINED3D_OK;
5607 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5609 /** FIXME: always true at the moment **/
5610 if(!bEnableDialogs) {
5611 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5613 return WINED3D_OK;
5617 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5619 TRACE("(%p) : pParameters %p\n", This, pParameters);
5621 *pParameters = This->createParms;
5622 return WINED3D_OK;
5625 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5626 IWineD3DSwapChain *swapchain;
5627 HRESULT hrc = WINED3D_OK;
5629 TRACE("Relaying to swapchain\n");
5631 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5632 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5633 IWineD3DSwapChain_Release(swapchain);
5635 return;
5638 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5639 IWineD3DSwapChain *swapchain;
5640 HRESULT hrc = WINED3D_OK;
5642 TRACE("Relaying to swapchain\n");
5644 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5645 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5646 IWineD3DSwapChain_Release(swapchain);
5648 return;
5652 /** ********************************************************
5653 * Notification functions
5654 ** ********************************************************/
5655 /** This function must be called in the release of a resource when ref == 0,
5656 * the contents of resource must still be correct,
5657 * any handels to other resource held by the caller must be closed
5658 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5659 *****************************************************/
5660 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 ResourceList* resourceList;
5664 TRACE("(%p) : resource %p\n", This, resource);
5665 #if 0
5666 EnterCriticalSection(&resourceStoreCriticalSection);
5667 #endif
5668 /* add a new texture to the frot of the linked list */
5669 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5670 resourceList->resource = resource;
5672 /* Get the old head */
5673 resourceList->next = This->resources;
5675 This->resources = resourceList;
5676 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5678 #if 0
5679 LeaveCriticalSection(&resourceStoreCriticalSection);
5680 #endif
5681 return;
5684 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5686 ResourceList* resourceList = NULL;
5687 ResourceList* previousResourceList = NULL;
5689 TRACE("(%p) : resource %p\n", This, resource);
5691 #if 0
5692 EnterCriticalSection(&resourceStoreCriticalSection);
5693 #endif
5694 resourceList = This->resources;
5696 while (resourceList != NULL) {
5697 if(resourceList->resource == resource) break;
5698 previousResourceList = resourceList;
5699 resourceList = resourceList->next;
5702 if (resourceList == NULL) {
5703 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5704 #if 0
5705 LeaveCriticalSection(&resourceStoreCriticalSection);
5706 #endif
5707 return;
5708 } else {
5709 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5711 /* make sure we don't leave a hole in the list */
5712 if (previousResourceList != NULL) {
5713 previousResourceList->next = resourceList->next;
5714 } else {
5715 This->resources = resourceList->next;
5718 #if 0
5719 LeaveCriticalSection(&resourceStoreCriticalSection);
5720 #endif
5721 return;
5725 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5727 int counter;
5729 TRACE("(%p) : resource %p\n", This, resource);
5730 switch(IWineD3DResource_GetType(resource)){
5731 case WINED3DRTYPE_SURFACE:
5732 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5733 break;
5734 case WINED3DRTYPE_TEXTURE:
5735 case WINED3DRTYPE_CUBETEXTURE:
5736 case WINED3DRTYPE_VOLUMETEXTURE:
5737 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5738 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5739 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5740 This->stateBlock->textures[counter] = NULL;
5742 if (This->updateStateBlock != This->stateBlock ){
5743 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5744 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5745 This->updateStateBlock->textures[counter] = NULL;
5749 break;
5750 case WINED3DRTYPE_VOLUME:
5751 /* TODO: nothing really? */
5752 break;
5753 case WINED3DRTYPE_VERTEXBUFFER:
5754 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5756 int streamNumber;
5757 TRACE("Cleaning up stream pointers\n");
5759 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5760 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5761 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5763 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5764 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5765 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5766 This->updateStateBlock->streamSource[streamNumber] = 0;
5767 /* Set changed flag? */
5770 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) */
5771 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5772 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5773 This->stateBlock->streamSource[streamNumber] = 0;
5776 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5777 else { /* This shouldn't happen */
5778 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5780 #endif
5784 break;
5785 case WINED3DRTYPE_INDEXBUFFER:
5786 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5787 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5788 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5789 This->updateStateBlock->pIndexData = NULL;
5792 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5793 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5794 This->stateBlock->pIndexData = NULL;
5798 break;
5799 default:
5800 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5801 break;
5805 /* Remove the resoruce from the resourceStore */
5806 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5808 TRACE("Resource released\n");
5812 /**********************************************************
5813 * IWineD3DDevice VTbl follows
5814 **********************************************************/
5816 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5818 /*** IUnknown methods ***/
5819 IWineD3DDeviceImpl_QueryInterface,
5820 IWineD3DDeviceImpl_AddRef,
5821 IWineD3DDeviceImpl_Release,
5822 /*** IWineD3DDevice methods ***/
5823 IWineD3DDeviceImpl_GetParent,
5824 /*** Creation methods**/
5825 IWineD3DDeviceImpl_CreateVertexBuffer,
5826 IWineD3DDeviceImpl_CreateIndexBuffer,
5827 IWineD3DDeviceImpl_CreateStateBlock,
5828 IWineD3DDeviceImpl_CreateSurface,
5829 IWineD3DDeviceImpl_CreateTexture,
5830 IWineD3DDeviceImpl_CreateVolumeTexture,
5831 IWineD3DDeviceImpl_CreateVolume,
5832 IWineD3DDeviceImpl_CreateCubeTexture,
5833 IWineD3DDeviceImpl_CreateQuery,
5834 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5835 IWineD3DDeviceImpl_CreateVertexDeclaration,
5836 IWineD3DDeviceImpl_CreateVertexShader,
5837 IWineD3DDeviceImpl_CreatePixelShader,
5838 IWineD3DDeviceImpl_CreatePalette,
5839 /*** Odd functions **/
5840 IWineD3DDeviceImpl_Init3D,
5841 IWineD3DDeviceImpl_Uninit3D,
5842 IWineD3DDeviceImpl_SetFullscreen,
5843 IWineD3DDeviceImpl_SetMultithreaded,
5844 IWineD3DDeviceImpl_EvictManagedResources,
5845 IWineD3DDeviceImpl_GetAvailableTextureMem,
5846 IWineD3DDeviceImpl_GetBackBuffer,
5847 IWineD3DDeviceImpl_GetCreationParameters,
5848 IWineD3DDeviceImpl_GetDeviceCaps,
5849 IWineD3DDeviceImpl_GetDirect3D,
5850 IWineD3DDeviceImpl_GetDisplayMode,
5851 IWineD3DDeviceImpl_SetDisplayMode,
5852 IWineD3DDeviceImpl_GetHWND,
5853 IWineD3DDeviceImpl_SetHWND,
5854 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5855 IWineD3DDeviceImpl_GetRasterStatus,
5856 IWineD3DDeviceImpl_GetSwapChain,
5857 IWineD3DDeviceImpl_Reset,
5858 IWineD3DDeviceImpl_SetDialogBoxMode,
5859 IWineD3DDeviceImpl_SetCursorProperties,
5860 IWineD3DDeviceImpl_SetCursorPosition,
5861 IWineD3DDeviceImpl_ShowCursor,
5862 IWineD3DDeviceImpl_TestCooperativeLevel,
5863 /*** Getters and setters **/
5864 IWineD3DDeviceImpl_SetClipPlane,
5865 IWineD3DDeviceImpl_GetClipPlane,
5866 IWineD3DDeviceImpl_SetClipStatus,
5867 IWineD3DDeviceImpl_GetClipStatus,
5868 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5869 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5870 IWineD3DDeviceImpl_SetDepthStencilSurface,
5871 IWineD3DDeviceImpl_GetDepthStencilSurface,
5872 IWineD3DDeviceImpl_SetFVF,
5873 IWineD3DDeviceImpl_GetFVF,
5874 IWineD3DDeviceImpl_SetGammaRamp,
5875 IWineD3DDeviceImpl_GetGammaRamp,
5876 IWineD3DDeviceImpl_SetIndices,
5877 IWineD3DDeviceImpl_GetIndices,
5878 IWineD3DDeviceImpl_SetBasevertexIndex,
5879 IWineD3DDeviceImpl_SetLight,
5880 IWineD3DDeviceImpl_GetLight,
5881 IWineD3DDeviceImpl_SetLightEnable,
5882 IWineD3DDeviceImpl_GetLightEnable,
5883 IWineD3DDeviceImpl_SetMaterial,
5884 IWineD3DDeviceImpl_GetMaterial,
5885 IWineD3DDeviceImpl_SetNPatchMode,
5886 IWineD3DDeviceImpl_GetNPatchMode,
5887 IWineD3DDeviceImpl_SetPaletteEntries,
5888 IWineD3DDeviceImpl_GetPaletteEntries,
5889 IWineD3DDeviceImpl_SetPixelShader,
5890 IWineD3DDeviceImpl_GetPixelShader,
5891 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5892 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5893 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5894 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5895 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5896 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5897 IWineD3DDeviceImpl_SetRenderState,
5898 IWineD3DDeviceImpl_GetRenderState,
5899 IWineD3DDeviceImpl_SetRenderTarget,
5900 IWineD3DDeviceImpl_GetRenderTarget,
5901 IWineD3DDeviceImpl_SetFrontBackBuffers,
5902 IWineD3DDeviceImpl_SetSamplerState,
5903 IWineD3DDeviceImpl_GetSamplerState,
5904 IWineD3DDeviceImpl_SetScissorRect,
5905 IWineD3DDeviceImpl_GetScissorRect,
5906 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5907 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5908 IWineD3DDeviceImpl_SetStreamSource,
5909 IWineD3DDeviceImpl_GetStreamSource,
5910 IWineD3DDeviceImpl_SetStreamSourceFreq,
5911 IWineD3DDeviceImpl_GetStreamSourceFreq,
5912 IWineD3DDeviceImpl_SetTexture,
5913 IWineD3DDeviceImpl_GetTexture,
5914 IWineD3DDeviceImpl_SetTextureStageState,
5915 IWineD3DDeviceImpl_GetTextureStageState,
5916 IWineD3DDeviceImpl_SetTransform,
5917 IWineD3DDeviceImpl_GetTransform,
5918 IWineD3DDeviceImpl_SetVertexDeclaration,
5919 IWineD3DDeviceImpl_GetVertexDeclaration,
5920 IWineD3DDeviceImpl_SetVertexShader,
5921 IWineD3DDeviceImpl_GetVertexShader,
5922 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5923 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5924 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5925 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5926 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5927 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5928 IWineD3DDeviceImpl_SetViewport,
5929 IWineD3DDeviceImpl_GetViewport,
5930 IWineD3DDeviceImpl_MultiplyTransform,
5931 IWineD3DDeviceImpl_ValidateDevice,
5932 IWineD3DDeviceImpl_ProcessVertices,
5933 /*** State block ***/
5934 IWineD3DDeviceImpl_BeginStateBlock,
5935 IWineD3DDeviceImpl_EndStateBlock,
5936 /*** Scene management ***/
5937 IWineD3DDeviceImpl_BeginScene,
5938 IWineD3DDeviceImpl_EndScene,
5939 IWineD3DDeviceImpl_Present,
5940 IWineD3DDeviceImpl_Clear,
5941 /*** Drawing ***/
5942 IWineD3DDeviceImpl_DrawPrimitive,
5943 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5944 IWineD3DDeviceImpl_DrawPrimitiveUP,
5945 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5946 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5947 IWineD3DDeviceImpl_DrawRectPatch,
5948 IWineD3DDeviceImpl_DrawTriPatch,
5949 IWineD3DDeviceImpl_DeletePatch,
5950 IWineD3DDeviceImpl_ColorFill,
5951 IWineD3DDeviceImpl_UpdateTexture,
5952 IWineD3DDeviceImpl_UpdateSurface,
5953 IWineD3DDeviceImpl_GetFrontBufferData,
5954 /*** object tracking ***/
5955 IWineD3DDeviceImpl_ResourceReleased
5959 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5960 WINED3DRS_ALPHABLENDENABLE ,
5961 WINED3DRS_ALPHAFUNC ,
5962 WINED3DRS_ALPHAREF ,
5963 WINED3DRS_ALPHATESTENABLE ,
5964 WINED3DRS_BLENDOP ,
5965 WINED3DRS_COLORWRITEENABLE ,
5966 WINED3DRS_DESTBLEND ,
5967 WINED3DRS_DITHERENABLE ,
5968 WINED3DRS_FILLMODE ,
5969 WINED3DRS_FOGDENSITY ,
5970 WINED3DRS_FOGEND ,
5971 WINED3DRS_FOGSTART ,
5972 WINED3DRS_LASTPIXEL ,
5973 WINED3DRS_SHADEMODE ,
5974 WINED3DRS_SRCBLEND ,
5975 WINED3DRS_STENCILENABLE ,
5976 WINED3DRS_STENCILFAIL ,
5977 WINED3DRS_STENCILFUNC ,
5978 WINED3DRS_STENCILMASK ,
5979 WINED3DRS_STENCILPASS ,
5980 WINED3DRS_STENCILREF ,
5981 WINED3DRS_STENCILWRITEMASK ,
5982 WINED3DRS_STENCILZFAIL ,
5983 WINED3DRS_TEXTUREFACTOR ,
5984 WINED3DRS_WRAP0 ,
5985 WINED3DRS_WRAP1 ,
5986 WINED3DRS_WRAP2 ,
5987 WINED3DRS_WRAP3 ,
5988 WINED3DRS_WRAP4 ,
5989 WINED3DRS_WRAP5 ,
5990 WINED3DRS_WRAP6 ,
5991 WINED3DRS_WRAP7 ,
5992 WINED3DRS_ZENABLE ,
5993 WINED3DRS_ZFUNC ,
5994 WINED3DRS_ZWRITEENABLE
5997 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5998 WINED3DTSS_ADDRESSW ,
5999 WINED3DTSS_ALPHAARG0 ,
6000 WINED3DTSS_ALPHAARG1 ,
6001 WINED3DTSS_ALPHAARG2 ,
6002 WINED3DTSS_ALPHAOP ,
6003 WINED3DTSS_BUMPENVLOFFSET ,
6004 WINED3DTSS_BUMPENVLSCALE ,
6005 WINED3DTSS_BUMPENVMAT00 ,
6006 WINED3DTSS_BUMPENVMAT01 ,
6007 WINED3DTSS_BUMPENVMAT10 ,
6008 WINED3DTSS_BUMPENVMAT11 ,
6009 WINED3DTSS_COLORARG0 ,
6010 WINED3DTSS_COLORARG1 ,
6011 WINED3DTSS_COLORARG2 ,
6012 WINED3DTSS_COLOROP ,
6013 WINED3DTSS_RESULTARG ,
6014 WINED3DTSS_TEXCOORDINDEX ,
6015 WINED3DTSS_TEXTURETRANSFORMFLAGS
6018 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6019 WINED3DSAMP_ADDRESSU ,
6020 WINED3DSAMP_ADDRESSV ,
6021 WINED3DSAMP_ADDRESSW ,
6022 WINED3DSAMP_BORDERCOLOR ,
6023 WINED3DSAMP_MAGFILTER ,
6024 WINED3DSAMP_MINFILTER ,
6025 WINED3DSAMP_MIPFILTER ,
6026 WINED3DSAMP_MIPMAPLODBIAS ,
6027 WINED3DSAMP_MAXMIPLEVEL ,
6028 WINED3DSAMP_MAXANISOTROPY ,
6029 WINED3DSAMP_SRGBTEXTURE ,
6030 WINED3DSAMP_ELEMENTINDEX
6033 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6034 WINED3DRS_AMBIENT ,
6035 WINED3DRS_AMBIENTMATERIALSOURCE ,
6036 WINED3DRS_CLIPPING ,
6037 WINED3DRS_CLIPPLANEENABLE ,
6038 WINED3DRS_COLORVERTEX ,
6039 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6040 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6041 WINED3DRS_FOGDENSITY ,
6042 WINED3DRS_FOGEND ,
6043 WINED3DRS_FOGSTART ,
6044 WINED3DRS_FOGTABLEMODE ,
6045 WINED3DRS_FOGVERTEXMODE ,
6046 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6047 WINED3DRS_LIGHTING ,
6048 WINED3DRS_LOCALVIEWER ,
6049 WINED3DRS_MULTISAMPLEANTIALIAS ,
6050 WINED3DRS_MULTISAMPLEMASK ,
6051 WINED3DRS_NORMALIZENORMALS ,
6052 WINED3DRS_PATCHEDGESTYLE ,
6053 WINED3DRS_POINTSCALE_A ,
6054 WINED3DRS_POINTSCALE_B ,
6055 WINED3DRS_POINTSCALE_C ,
6056 WINED3DRS_POINTSCALEENABLE ,
6057 WINED3DRS_POINTSIZE ,
6058 WINED3DRS_POINTSIZE_MAX ,
6059 WINED3DRS_POINTSIZE_MIN ,
6060 WINED3DRS_POINTSPRITEENABLE ,
6061 WINED3DRS_RANGEFOGENABLE ,
6062 WINED3DRS_SPECULARMATERIALSOURCE ,
6063 WINED3DRS_TWEENFACTOR ,
6064 WINED3DRS_VERTEXBLEND
6067 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6068 WINED3DTSS_TEXCOORDINDEX ,
6069 WINED3DTSS_TEXTURETRANSFORMFLAGS
6072 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6073 WINED3DSAMP_DMAPOFFSET
6076 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6077 DWORD rep = StateTable[state].representative;
6078 DWORD idx;
6079 BYTE shift;
6080 UINT i;
6081 WineD3DContext *context;
6083 if(!rep) return;
6084 for(i = 0; i < This->numContexts; i++) {
6085 context = This->contexts[i];
6086 if(isStateDirty(context, rep)) continue;
6088 context->dirtyArray[context->numDirtyEntries++] = rep;
6089 idx = rep >> 5;
6090 shift = rep & 0x1f;
6091 context->isStateDirty[idx] |= (1 << shift);