Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / wined3d / device.c
blob20c408f560f9ad61272c3c17ab554a2612804340
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) && wined3d_settings.vbo_mode != VBO_NONE &&
367 Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
368 (dxVersion > 7 || !conv) ) {
369 CreateVBO(object);
371 return WINED3D_OK;
374 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
375 GLenum error, glUsage;
376 TRACE("Creating VBO for Index Buffer %p\n", object);
378 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
379 * restored on the next draw
381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
383 ENTER_GL();
384 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
385 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
387 while(glGetError());
389 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
390 error = glGetError();
391 if(error != GL_NO_ERROR || object->vbo == 0) {
392 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
393 goto out;
396 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
397 error = glGetError();
398 if(error != GL_NO_ERROR) {
399 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
400 goto out;
403 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
404 * copy no readback will be needed
406 glUsage = GL_STATIC_DRAW_ARB;
407 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
408 error = glGetError();
409 if(error != GL_NO_ERROR) {
410 ERR("Failed to initialize the index buffer\n");
411 goto out;
413 LEAVE_GL();
414 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
415 return;
417 out:
418 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
419 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
420 LEAVE_GL();
421 object->vbo = 0;
424 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
425 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
426 HANDLE *sharedHandle, IUnknown *parent) {
427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
428 IWineD3DIndexBufferImpl *object;
429 TRACE("(%p) Creating index buffer\n", This);
431 /* Allocate the storage for the device */
432 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
434 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
435 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
438 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
439 CreateIndexBufferVBO(This, object);
442 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
443 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
444 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
446 return WINED3D_OK;
449 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
452 IWineD3DStateBlockImpl *object;
453 int i, j;
454 HRESULT temp_result;
456 D3DCREATEOBJECTINSTANCE(object, StateBlock)
457 object->blockType = Type;
459 for(i = 0; i < LIGHTMAP_SIZE; i++) {
460 list_init(&object->lightMap[i]);
463 /* Special case - Used during initialization to produce a placeholder stateblock
464 so other functions called can update a state block */
465 if (Type == WINED3DSBT_INIT) {
466 /* Don't bother increasing the reference count otherwise a device will never
467 be freed due to circular dependencies */
468 return WINED3D_OK;
471 temp_result = allocate_shader_constants(object);
472 if (WINED3D_OK != temp_result)
473 return temp_result;
475 /* Otherwise, might as well set the whole state block to the appropriate values */
476 if (This->stateBlock != NULL)
477 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
478 else
479 memset(object->streamFreq, 1, sizeof(object->streamFreq));
481 /* Reset the ref and type after kludging it */
482 object->wineD3DDevice = This;
483 object->ref = 1;
484 object->blockType = Type;
486 TRACE("Updating changed flags appropriate for type %d\n", Type);
488 if (Type == WINED3DSBT_ALL) {
490 TRACE("ALL => Pretend everything has changed\n");
491 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
493 /* Lights are not part of the changed / set structure */
494 for(j = 0; j < LIGHTMAP_SIZE; j++) {
495 struct list *e;
496 LIST_FOR_EACH(e, &object->lightMap[j]) {
497 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
498 light->changed = TRUE;
499 light->enabledChanged = TRUE;
502 } else if (Type == WINED3DSBT_PIXELSTATE) {
504 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
505 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
507 object->changed.pixelShader = TRUE;
509 /* Pixel Shader Constants */
510 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
511 object->changed.pixelShaderConstantsF[i] = TRUE;
512 for (i = 0; i < MAX_CONST_B; ++i)
513 object->changed.pixelShaderConstantsB[i] = TRUE;
514 for (i = 0; i < MAX_CONST_I; ++i)
515 object->changed.pixelShaderConstantsI[i] = TRUE;
517 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
518 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
520 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
521 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
522 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
525 for (j = 0 ; j < 16; j++) {
526 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
528 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
532 } else if (Type == WINED3DSBT_VERTEXSTATE) {
534 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.vertexShader = TRUE;
539 /* Vertex Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
541 object->changed.vertexShaderConstantsF[i] = TRUE;
542 for (i = 0; i < MAX_CONST_B; ++i)
543 object->changed.vertexShaderConstantsB[i] = TRUE;
544 for (i = 0; i < MAX_CONST_I; ++i)
545 object->changed.vertexShaderConstantsI[i] = TRUE;
547 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
548 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
550 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
551 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
552 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
555 for (j = 0 ; j < 16; j++){
556 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
557 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
561 for(j = 0; j < LIGHTMAP_SIZE; j++) {
562 struct list *e;
563 LIST_FOR_EACH(e, &object->lightMap[j]) {
564 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
565 light->changed = TRUE;
566 light->enabledChanged = TRUE;
569 } else {
570 FIXME("Unrecognized state block type %d\n", Type);
573 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
574 return WINED3D_OK;
578 /* ************************************
579 MSDN:
580 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
582 Discard
583 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
585 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.
587 ******************************** */
589 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) {
590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
591 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
592 unsigned int pow2Width, pow2Height;
593 unsigned int Size = 1;
594 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
595 TRACE("(%p) Create surface\n",This);
597 /** FIXME: Check ranges on the inputs are valid
598 * MSDN
599 * MultisampleQuality
600 * [in] Quality level. The valid range is between zero and one less than the level
601 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
602 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
603 * values of paired render targets, depth stencil surfaces, and the MultiSample type
604 * must all match.
605 *******************************/
609 * TODO: Discard MSDN
610 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
612 * If this flag is set, the contents of the depth stencil buffer will be
613 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
614 * with a different depth surface.
616 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
617 ***************************/
619 if(MultisampleQuality < 0) {
620 FIXME("Invalid multisample level %d\n", MultisampleQuality);
621 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
624 if(MultisampleQuality > 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
626 MultisampleQuality=0;
629 /** FIXME: Check that the format is supported
630 * by the device.
631 *******************************/
633 /* Non-power2 support */
634 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
635 pow2Width = Width;
636 pow2Height = Height;
637 } else {
638 /* Find the nearest pow2 match */
639 pow2Width = pow2Height = 1;
640 while (pow2Width < Width) pow2Width <<= 1;
641 while (pow2Height < Height) pow2Height <<= 1;
644 if (pow2Width > Width || pow2Height > Height) {
645 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
646 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
647 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
648 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
649 This, Width, Height);
650 return WINED3DERR_NOTAVAILABLE;
654 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
655 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
656 * space!
657 *********************************/
658 if (WINED3DFMT_UNKNOWN == Format) {
659 Size = 0;
660 } else if (Format == WINED3DFMT_DXT1) {
661 /* DXT1 is half byte per pixel */
662 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
664 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
665 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
666 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
667 } else {
668 /* The pitch is a multiple of 4 bytes */
669 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
670 Size *= Height;
673 /** Create and initialise the surface resource **/
674 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
675 /* "Standalone" surface */
676 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
678 object->currentDesc.Width = Width;
679 object->currentDesc.Height = Height;
680 object->currentDesc.MultiSampleType = MultiSample;
681 object->currentDesc.MultiSampleQuality = MultisampleQuality;
683 /* Setup some glformat defaults */
684 object->glDescription.glFormat = tableEntry->glFormat;
685 object->glDescription.glFormatInternal = tableEntry->glInternal;
686 object->glDescription.glType = tableEntry->glType;
688 object->glDescription.textureName = 0;
689 object->glDescription.level = Level;
690 object->glDescription.target = GL_TEXTURE_2D;
692 /* Internal data */
693 object->pow2Width = pow2Width;
694 object->pow2Height = pow2Height;
696 /* Flags */
697 object->Flags = SFLAG_DYNLOCK;
698 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
699 object->Flags |= Discard ? SFLAG_DISCARD : 0;
700 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
701 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
704 if (WINED3DFMT_UNKNOWN != Format) {
705 object->bytesPerPixel = tableEntry->bpp;
706 } else {
707 object->bytesPerPixel = 0;
710 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
712 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
714 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
715 * this function is too deep to need to care about things like this.
716 * Levels need to be checked too, and possibly Type since they all affect what can be done.
717 * ****************************************/
718 switch(Pool) {
719 case WINED3DPOOL_SCRATCH:
720 if(!Lockable)
721 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
722 "which are mutually exclusive, setting lockable to TRUE\n");
723 Lockable = TRUE;
724 break;
725 case WINED3DPOOL_SYSTEMMEM:
726 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
727 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
728 case WINED3DPOOL_MANAGED:
729 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
730 "Usage of DYNAMIC which are mutually exclusive, not doing "
731 "anything just telling you.\n");
732 break;
733 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
734 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
735 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
736 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
737 break;
738 default:
739 FIXME("(%p) Unknown pool %d\n", This, Pool);
740 break;
743 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
744 FIXME("Trying to create a render target that isn't in the default pool\n");
747 /* mark the texture as dirty so that it gets loaded first time around*/
748 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
749 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
750 This, Width, Height, Format, debug_d3dformat(Format),
751 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
753 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
754 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
755 This->ddraw_primary = (IWineD3DSurface *) object;
757 /* Look at the implementation and set the correct Vtable */
758 switch(Impl) {
759 case SURFACE_OPENGL:
760 /* Nothing to do, it's set already */
761 break;
763 case SURFACE_GDI:
764 object->lpVtbl = &IWineGDISurface_Vtbl;
765 break;
767 default:
768 /* To be sure to catch this */
769 ERR("Unknown requested surface implementation %d!\n", Impl);
770 IWineD3DSurface_Release((IWineD3DSurface *) object);
771 return WINED3DERR_INVALIDCALL;
774 /* Call the private setup routine */
775 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
779 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
780 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
781 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
782 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
784 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
785 IWineD3DTextureImpl *object;
786 unsigned int i;
787 UINT tmpW;
788 UINT tmpH;
789 HRESULT hr;
790 unsigned int pow2Width;
791 unsigned int pow2Height;
794 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
795 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
796 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
798 /* TODO: It should only be possible to create textures for formats
799 that are reported as supported */
800 if (WINED3DFMT_UNKNOWN >= Format) {
801 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
802 return WINED3DERR_INVALIDCALL;
805 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
806 D3DINITIALIZEBASETEXTURE(object->baseTexture);
807 object->width = Width;
808 object->height = Height;
810 /** Non-power2 support **/
811 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
812 pow2Width = Width;
813 pow2Height = Height;
814 } else {
815 /* Find the nearest pow2 match */
816 pow2Width = pow2Height = 1;
817 while (pow2Width < Width) pow2Width <<= 1;
818 while (pow2Height < Height) pow2Height <<= 1;
821 /** FIXME: add support for real non-power-two if it's provided by the video card **/
822 /* Precalculated scaling for 'faked' non power of two texture coords */
823 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
824 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
825 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
827 object->baseTexture.format = Format;
829 /* Calculate levels for mip mapping */
830 if (Levels == 0) {
831 TRACE("calculating levels %d\n", object->baseTexture.levels);
832 object->baseTexture.levels++;
833 tmpW = Width;
834 tmpH = Height;
835 while (tmpW > 1 || tmpH > 1) {
836 tmpW = max(1, tmpW >> 1);
837 tmpH = max(1, tmpH >> 1);
838 object->baseTexture.levels++;
840 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
843 /* Generate all the surfaces */
844 tmpW = Width;
845 tmpH = Height;
846 for (i = 0; i < object->baseTexture.levels; i++)
848 /* use the callback to create the texture surface */
849 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
850 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
851 FIXME("Failed to create surface %p\n", object);
852 /* clean up */
853 object->surfaces[i] = NULL;
854 IWineD3DTexture_Release((IWineD3DTexture *)object);
856 *ppTexture = NULL;
857 return hr;
860 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
861 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
862 /* calculate the next mipmap level */
863 tmpW = max(1, tmpW >> 1);
864 tmpH = max(1, tmpH >> 1);
867 TRACE("(%p) : Created texture %p\n", This, object);
868 return WINED3D_OK;
871 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
872 UINT Width, UINT Height, UINT Depth,
873 UINT Levels, DWORD Usage,
874 WINED3DFORMAT Format, WINED3DPOOL Pool,
875 IWineD3DVolumeTexture **ppVolumeTexture,
876 HANDLE *pSharedHandle, IUnknown *parent,
877 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
880 IWineD3DVolumeTextureImpl *object;
881 unsigned int i;
882 UINT tmpW;
883 UINT tmpH;
884 UINT tmpD;
886 /* TODO: It should only be possible to create textures for formats
887 that are reported as supported */
888 if (WINED3DFMT_UNKNOWN >= Format) {
889 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
890 return WINED3DERR_INVALIDCALL;
893 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
894 D3DINITIALIZEBASETEXTURE(object->baseTexture);
896 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
897 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
899 object->width = Width;
900 object->height = Height;
901 object->depth = Depth;
902 object->baseTexture.format = Format;
904 /* Calculate levels for mip mapping */
905 if (Levels == 0) {
906 object->baseTexture.levels++;
907 tmpW = Width;
908 tmpH = Height;
909 tmpD = Depth;
910 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
911 tmpW = max(1, tmpW >> 1);
912 tmpH = max(1, tmpH >> 1);
913 tmpD = max(1, tmpD >> 1);
914 object->baseTexture.levels++;
916 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
919 /* Generate all the surfaces */
920 tmpW = Width;
921 tmpH = Height;
922 tmpD = Depth;
924 for (i = 0; i < object->baseTexture.levels; i++)
926 HRESULT hr;
927 /* Create the volume */
928 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
929 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
931 if(FAILED(hr)) {
932 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
933 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
934 *ppVolumeTexture = NULL;
935 return hr;
938 /* Set its container to this object */
939 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
941 /* calcualte the next mipmap level */
942 tmpW = max(1, tmpW >> 1);
943 tmpH = max(1, tmpH >> 1);
944 tmpD = max(1, tmpD >> 1);
947 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
948 TRACE("(%p) : Created volume texture %p\n", This, object);
949 return WINED3D_OK;
952 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
953 UINT Width, UINT Height, UINT Depth,
954 DWORD Usage,
955 WINED3DFORMAT Format, WINED3DPOOL Pool,
956 IWineD3DVolume** ppVolume,
957 HANDLE* pSharedHandle, IUnknown *parent) {
959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
960 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
961 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
963 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
965 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
966 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
968 object->currentDesc.Width = Width;
969 object->currentDesc.Height = Height;
970 object->currentDesc.Depth = Depth;
971 object->bytesPerPixel = formatDesc->bpp;
973 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
974 object->lockable = TRUE;
975 object->locked = FALSE;
976 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
977 object->dirty = TRUE;
979 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
982 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
983 UINT Levels, DWORD Usage,
984 WINED3DFORMAT Format, WINED3DPOOL Pool,
985 IWineD3DCubeTexture **ppCubeTexture,
986 HANDLE *pSharedHandle, IUnknown *parent,
987 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
990 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
991 unsigned int i, j;
992 UINT tmpW;
993 HRESULT hr;
994 unsigned int pow2EdgeLength = EdgeLength;
996 /* TODO: It should only be possible to create textures for formats
997 that are reported as supported */
998 if (WINED3DFMT_UNKNOWN >= Format) {
999 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1000 return WINED3DERR_INVALIDCALL;
1003 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1004 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1006 TRACE("(%p) Create Cube Texture\n", This);
1008 /** Non-power2 support **/
1010 /* Find the nearest pow2 match */
1011 pow2EdgeLength = 1;
1012 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1014 object->edgeLength = EdgeLength;
1015 /* TODO: support for native non-power 2 */
1016 /* Precalculated scaling for 'faked' non power of two texture coords */
1017 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1018 object->baseTexture.format = Format;
1020 /* Calculate levels for mip mapping */
1021 if (Levels == 0) {
1022 object->baseTexture.levels++;
1023 tmpW = EdgeLength;
1024 while (tmpW > 1) {
1025 tmpW = max(1, tmpW >> 1);
1026 object->baseTexture.levels++;
1028 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1031 /* Generate all the surfaces */
1032 tmpW = EdgeLength;
1033 for (i = 0; i < object->baseTexture.levels; i++) {
1035 /* Create the 6 faces */
1036 for (j = 0; j < 6; j++) {
1038 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1039 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1041 if(hr!= WINED3D_OK) {
1042 /* clean up */
1043 int k;
1044 int l;
1045 for (l = 0; l < j; l++) {
1046 IWineD3DSurface_Release(object->surfaces[j][i]);
1048 for (k = 0; k < i; k++) {
1049 for (l = 0; l < 6; l++) {
1050 IWineD3DSurface_Release(object->surfaces[l][j]);
1054 FIXME("(%p) Failed to create surface\n",object);
1055 HeapFree(GetProcessHeap(),0,object);
1056 *ppCubeTexture = NULL;
1057 return hr;
1059 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1060 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1062 tmpW = max(1, tmpW >> 1);
1065 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1066 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1067 return WINED3D_OK;
1070 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1072 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1073 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1075 /* Just a check to see if we support this type of query */
1076 switch(Type) {
1077 case WINED3DQUERYTYPE_OCCLUSION:
1078 TRACE("(%p) occlusion query\n", This);
1079 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1080 hr = WINED3D_OK;
1081 else
1082 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1083 break;
1085 case WINED3DQUERYTYPE_EVENT:
1086 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1087 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1088 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1090 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1092 hr = WINED3D_OK;
1093 break;
1095 case WINED3DQUERYTYPE_VCACHE:
1096 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1097 case WINED3DQUERYTYPE_VERTEXSTATS:
1098 case WINED3DQUERYTYPE_TIMESTAMP:
1099 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1100 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1101 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1102 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1103 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1104 case WINED3DQUERYTYPE_PIXELTIMINGS:
1105 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1106 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1107 default:
1108 FIXME("(%p) Unhandled query type %d\n", This, Type);
1110 if(NULL == ppQuery || hr != WINED3D_OK) {
1111 return hr;
1114 D3DCREATEOBJECTINSTANCE(object, Query)
1115 object->type = Type;
1116 /* allocated the 'extended' data based on the type of query requested */
1117 switch(Type){
1118 case WINED3DQUERYTYPE_OCCLUSION:
1119 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1120 TRACE("(%p) Allocating data for an occlusion query\n", This);
1121 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1122 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1123 break;
1125 case WINED3DQUERYTYPE_EVENT:
1126 /* TODO: GL_APPLE_fence */
1127 if(GL_SUPPORT(APPLE_FENCE)) {
1128 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1129 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1130 checkGLcall("glGenFencesAPPLE");
1131 } else if(GL_SUPPORT(NV_FENCE)) {
1132 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1133 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1134 checkGLcall("glGenFencesNV");
1136 break;
1138 case WINED3DQUERYTYPE_VCACHE:
1139 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1140 case WINED3DQUERYTYPE_VERTEXSTATS:
1141 case WINED3DQUERYTYPE_TIMESTAMP:
1142 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1143 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1144 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1145 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1146 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1147 case WINED3DQUERYTYPE_PIXELTIMINGS:
1148 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1149 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1150 default:
1151 object->extendedData = 0;
1152 FIXME("(%p) Unhandled query type %d\n",This , Type);
1154 TRACE("(%p) : Created Query %p\n", This, object);
1155 return WINED3D_OK;
1158 /*****************************************************************************
1159 * IWineD3DDeviceImpl_SetupFullscreenWindow
1161 * Helper function that modifies a HWND's Style and ExStyle for proper
1162 * fullscreen use.
1164 * Params:
1165 * iface: Pointer to the IWineD3DDevice interface
1166 * window: Window to setup
1168 *****************************************************************************/
1169 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1172 LONG style, exStyle;
1173 /* Don't do anything if an original style is stored.
1174 * That shouldn't happen
1176 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1177 if (This->style || This->exStyle) {
1178 ERR("(%p): Want to change the window parameters of HWND %p, but "
1179 "another style is stored for restoration afterwards\n", This, window);
1182 /* Get the parameters and save them */
1183 style = GetWindowLongW(window, GWL_STYLE);
1184 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1185 This->style = style;
1186 This->exStyle = exStyle;
1188 /* Filter out window decorations */
1189 style &= ~WS_CAPTION;
1190 style &= ~WS_THICKFRAME;
1191 exStyle &= ~WS_EX_WINDOWEDGE;
1192 exStyle &= ~WS_EX_CLIENTEDGE;
1194 /* Make sure the window is managed, otherwise we won't get keyboard input */
1195 style |= WS_POPUP | WS_SYSMENU;
1197 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1198 This->style, This->exStyle, style, exStyle);
1200 SetWindowLongW(window, GWL_STYLE, style);
1201 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1203 /* Inform the window about the update. */
1204 SetWindowPos(window, HWND_TOP, 0, 0,
1205 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1206 ShowWindow(window, SW_NORMAL);
1209 /*****************************************************************************
1210 * IWineD3DDeviceImpl_RestoreWindow
1212 * Helper function that restores a windows' properties when taking it out
1213 * of fullscreen mode
1215 * Params:
1216 * iface: Pointer to the IWineD3DDevice interface
1217 * window: Window to setup
1219 *****************************************************************************/
1220 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1223 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1224 * switch, do nothing
1226 if (!This->style && !This->exStyle) return;
1228 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1229 This, window, This->style, This->exStyle);
1231 SetWindowLongW(window, GWL_STYLE, This->style);
1232 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1234 /* Delete the old values */
1235 This->style = 0;
1236 This->exStyle = 0;
1238 /* Inform the window about the update */
1239 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1240 0, 0, 0, 0, /* Pos, Size, ignored */
1241 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1244 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1245 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1246 IUnknown* parent,
1247 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1248 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1251 HDC hDc;
1252 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1253 HRESULT hr = WINED3D_OK;
1254 IUnknown *bufferParent;
1255 Display *display;
1257 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1259 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1260 * does a device hold a reference to a swap chain giving them a lifetime of the device
1261 * or does the swap chain notify the device of its destruction.
1262 *******************************/
1264 /* Check the params */
1265 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1266 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1267 return WINED3DERR_INVALIDCALL;
1268 } else if (pPresentationParameters->BackBufferCount > 1) {
1269 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");
1272 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1274 /*********************
1275 * Lookup the window Handle and the relating X window handle
1276 ********************/
1278 /* Setup hwnd we are using, plus which display this equates to */
1279 object->win_handle = pPresentationParameters->hDeviceWindow;
1280 if (!object->win_handle) {
1281 object->win_handle = This->createParms.hFocusWindow;
1284 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1285 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1286 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1287 return WINED3DERR_NOTAVAILABLE;
1289 hDc = GetDC(object->win_handle);
1290 display = get_display(hDc);
1291 ReleaseDC(object->win_handle, hDc);
1292 TRACE("Using a display of %p %p\n", display, hDc);
1294 if (NULL == display || NULL == hDc) {
1295 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1296 return WINED3DERR_NOTAVAILABLE;
1299 if (object->win == 0) {
1300 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1301 return WINED3DERR_NOTAVAILABLE;
1304 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1305 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1306 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1308 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1309 * then the corresponding dimension of the client area of the hDeviceWindow
1310 * (or the focus window, if hDeviceWindow is NULL) is taken.
1311 **********************/
1313 if (pPresentationParameters->Windowed &&
1314 ((pPresentationParameters->BackBufferWidth == 0) ||
1315 (pPresentationParameters->BackBufferHeight == 0))) {
1317 RECT Rect;
1318 GetClientRect(object->win_handle, &Rect);
1320 if (pPresentationParameters->BackBufferWidth == 0) {
1321 pPresentationParameters->BackBufferWidth = Rect.right;
1322 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1324 if (pPresentationParameters->BackBufferHeight == 0) {
1325 pPresentationParameters->BackBufferHeight = Rect.bottom;
1326 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1330 /* Put the correct figures in the presentation parameters */
1331 TRACE("Copying across presentation parameters\n");
1332 object->presentParms = *pPresentationParameters;
1334 TRACE("calling rendertarget CB\n");
1335 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1336 parent,
1337 object->presentParms.BackBufferWidth,
1338 object->presentParms.BackBufferHeight,
1339 object->presentParms.BackBufferFormat,
1340 object->presentParms.MultiSampleType,
1341 object->presentParms.MultiSampleQuality,
1342 TRUE /* Lockable */,
1343 &object->frontBuffer,
1344 NULL /* pShared (always null)*/);
1345 if (object->frontBuffer != NULL) {
1346 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1347 } else {
1348 ERR("Failed to create the front buffer\n");
1349 goto error;
1353 * Create an opengl context for the display visual
1354 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1355 * use different properties after that point in time. FIXME: How to handle when requested format
1356 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1357 * it chooses is identical to the one already being used!
1358 **********************************/
1359 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1361 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1362 if(!object->context) {
1364 object->num_contexts = 1;
1366 ENTER_GL();
1367 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1368 LEAVE_GL();
1370 if (!object->context) {
1371 ERR("Failed to create a new context\n");
1372 hr = WINED3DERR_NOTAVAILABLE;
1373 goto error;
1374 } else {
1375 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1376 object->win_handle, object->context[0]->glCtx, object->win);
1379 /*********************
1380 * Windowed / Fullscreen
1381 *******************/
1384 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1385 * so we should really check to see if there is a fullscreen swapchain already
1386 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1387 **************************************/
1389 if (!pPresentationParameters->Windowed) {
1391 DEVMODEW devmode;
1392 HDC hdc;
1393 int bpp = 0;
1394 RECT clip_rc;
1396 /* Get info on the current display setup */
1397 hdc = GetDC(0);
1398 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1399 ReleaseDC(0, hdc);
1401 /* Change the display settings */
1402 memset(&devmode, 0, sizeof(DEVMODEW));
1403 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1404 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1405 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1406 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1407 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1408 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1410 /* For GetDisplayMode */
1411 This->ddraw_width = devmode.dmPelsWidth;
1412 This->ddraw_height = devmode.dmPelsHeight;
1413 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1415 IWineD3DDevice_SetFullscreen(iface, TRUE);
1417 /* And finally clip mouse to our screen */
1418 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1419 ClipCursor(&clip_rc);
1422 /*********************
1423 * Create the back, front and stencil buffers
1424 *******************/
1425 if(object->presentParms.BackBufferCount > 0) {
1426 int i;
1428 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1429 if(!object->backBuffer) {
1430 ERR("Out of memory\n");
1431 hr = E_OUTOFMEMORY;
1432 goto error;
1435 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1436 TRACE("calling rendertarget CB\n");
1437 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1438 parent,
1439 object->presentParms.BackBufferWidth,
1440 object->presentParms.BackBufferHeight,
1441 object->presentParms.BackBufferFormat,
1442 object->presentParms.MultiSampleType,
1443 object->presentParms.MultiSampleQuality,
1444 TRUE /* Lockable */,
1445 &object->backBuffer[i],
1446 NULL /* pShared (always null)*/);
1447 if(hr == WINED3D_OK && object->backBuffer[i]) {
1448 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1449 } else {
1450 ERR("Cannot create new back buffer\n");
1451 goto error;
1453 ENTER_GL();
1454 glDrawBuffer(GL_BACK);
1455 checkGLcall("glDrawBuffer(GL_BACK)");
1456 LEAVE_GL();
1458 } else {
1459 object->backBuffer = NULL;
1461 /* Single buffering - draw to front buffer */
1462 ENTER_GL();
1463 glDrawBuffer(GL_FRONT);
1464 checkGLcall("glDrawBuffer(GL_FRONT)");
1465 LEAVE_GL();
1468 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1469 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1470 TRACE("Creating depth stencil buffer\n");
1471 if (This->depthStencilBuffer == NULL ) {
1472 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1473 parent,
1474 object->presentParms.BackBufferWidth,
1475 object->presentParms.BackBufferHeight,
1476 object->presentParms.AutoDepthStencilFormat,
1477 object->presentParms.MultiSampleType,
1478 object->presentParms.MultiSampleQuality,
1479 FALSE /* FIXME: Discard */,
1480 &This->depthStencilBuffer,
1481 NULL /* pShared (always null)*/ );
1482 if (This->depthStencilBuffer != NULL)
1483 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1486 /** TODO: A check on width, height and multisample types
1487 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1488 ****************************/
1489 object->wantsDepthStencilBuffer = TRUE;
1490 } else {
1491 object->wantsDepthStencilBuffer = FALSE;
1494 TRACE("Created swapchain %p\n", object);
1495 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1496 return WINED3D_OK;
1498 error:
1499 if (object->backBuffer) {
1500 int i;
1501 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1502 if(object->backBuffer[i]) {
1503 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1504 IUnknown_Release(bufferParent); /* once for the get parent */
1505 if (IUnknown_Release(bufferParent) > 0) {
1506 FIXME("(%p) Something's still holding the back buffer\n",This);
1510 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1511 object->backBuffer = NULL;
1513 if(object->context) {
1514 DestroyContext(This, object->context[0]);
1516 if(object->frontBuffer) {
1517 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1518 IUnknown_Release(bufferParent); /* once for the get parent */
1519 if (IUnknown_Release(bufferParent) > 0) {
1520 FIXME("(%p) Something's still holding the front buffer\n",This);
1523 HeapFree(GetProcessHeap(), 0, object);
1524 return hr;
1527 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1528 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1530 TRACE("(%p)\n", This);
1532 return This->NumberOfSwapChains;
1535 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1537 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1539 if(iSwapChain < This->NumberOfSwapChains) {
1540 *pSwapChain = This->swapchains[iSwapChain];
1541 IWineD3DSwapChain_AddRef(*pSwapChain);
1542 TRACE("(%p) returning %p\n", This, *pSwapChain);
1543 return WINED3D_OK;
1544 } else {
1545 TRACE("Swapchain out of range\n");
1546 *pSwapChain = NULL;
1547 return WINED3DERR_INVALIDCALL;
1551 /*****
1552 * Vertex Declaration
1553 *****/
1554 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1555 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1557 IWineD3DVertexDeclarationImpl *object = NULL;
1558 HRESULT hr = WINED3D_OK;
1560 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1561 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1563 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1565 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1567 return hr;
1570 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1571 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1573 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1574 HRESULT hr = WINED3D_OK;
1575 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1576 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1578 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1580 if (vertex_declaration) {
1581 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1584 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1586 if (WINED3D_OK != hr) {
1587 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1588 IWineD3DVertexShader_Release(*ppVertexShader);
1589 return WINED3DERR_INVALIDCALL;
1592 return WINED3D_OK;
1595 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1597 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1598 HRESULT hr = WINED3D_OK;
1600 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1601 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1602 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1603 if (WINED3D_OK == hr) {
1604 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1605 } else {
1606 WARN("(%p) : Failed to create pixel shader\n", This);
1609 return hr;
1612 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1614 IWineD3DPaletteImpl *object;
1615 HRESULT hr;
1616 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1618 /* Create the new object */
1619 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1620 if(!object) {
1621 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1622 return E_OUTOFMEMORY;
1625 object->lpVtbl = &IWineD3DPalette_Vtbl;
1626 object->ref = 1;
1627 object->Flags = Flags;
1628 object->parent = Parent;
1629 object->wineD3DDevice = This;
1630 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1632 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1634 if(!object->hpal) {
1635 HeapFree( GetProcessHeap(), 0, object);
1636 return E_OUTOFMEMORY;
1639 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1640 if(FAILED(hr)) {
1641 IWineD3DPalette_Release((IWineD3DPalette *) object);
1642 return hr;
1645 *Palette = (IWineD3DPalette *) object;
1647 return WINED3D_OK;
1650 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1652 IWineD3DSwapChainImpl *swapchain;
1653 DWORD state;
1655 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1656 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1658 /* TODO: Test if OpenGL is compiled in and loaded */
1660 /* Initialize the texture unit mapping to a 1:1 mapping */
1661 for(state = 0; state < MAX_SAMPLERS; state++) {
1662 This->texUnitMap[state] = state;
1664 This->oneToOneTexUnitMap = TRUE;
1666 /* Setup the implicit swapchain */
1667 TRACE("Creating implicit swapchain\n");
1668 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1669 WARN("Failed to create implicit swapchain\n");
1670 return WINED3DERR_INVALIDCALL;
1673 This->NumberOfSwapChains = 1;
1674 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1675 if(!This->swapchains) {
1676 ERR("Out of memory!\n");
1677 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1678 return E_OUTOFMEMORY;
1680 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1682 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1684 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1685 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1686 This->render_targets[0] = swapchain->backBuffer[0];
1687 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1689 else {
1690 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1691 This->render_targets[0] = swapchain->frontBuffer;
1692 This->lastActiveRenderTarget = swapchain->frontBuffer;
1694 IWineD3DSurface_AddRef(This->render_targets[0]);
1695 This->activeContext = swapchain->context[0];
1697 /* Depth Stencil support */
1698 This->stencilBufferTarget = This->depthStencilBuffer;
1699 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1700 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1702 if (NULL != This->stencilBufferTarget) {
1703 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1706 /* Set up some starting GL setup */
1707 ENTER_GL();
1709 * Initialize openGL extension related variables
1710 * with Default values
1713 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1714 /* Setup all the devices defaults */
1715 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1716 #if 0
1717 IWineD3DImpl_CheckGraphicsMemory();
1718 #endif
1720 { /* Set a default viewport */
1721 WINED3DVIEWPORT vp;
1722 vp.X = 0;
1723 vp.Y = 0;
1724 vp.Width = pPresentationParameters->BackBufferWidth;
1725 vp.Height = pPresentationParameters->BackBufferHeight;
1726 vp.MinZ = 0.0f;
1727 vp.MaxZ = 1.0f;
1728 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1731 /* Initialize the current view state */
1732 This->view_ident = 1;
1733 This->contexts[0]->last_was_rhw = 0;
1734 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1735 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1737 switch(wined3d_settings.offscreen_rendering_mode) {
1738 case ORM_FBO:
1739 case ORM_PBUFFER:
1740 This->offscreenBuffer = GL_BACK;
1741 break;
1743 case ORM_BACKBUFFER:
1745 if(GL_LIMITS(aux_buffers) > 0) {
1746 TRACE("Using auxilliary buffer for offscreen rendering\n");
1747 This->offscreenBuffer = GL_AUX0;
1748 } else {
1749 TRACE("Using back buffer for offscreen rendering\n");
1750 This->offscreenBuffer = GL_BACK;
1755 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1756 LEAVE_GL();
1758 /* Clear the screen */
1759 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1760 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1761 0x00, 1.0, 0);
1763 This->d3d_initialized = TRUE;
1764 return WINED3D_OK;
1767 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1769 int sampler;
1770 uint i;
1771 TRACE("(%p)\n", This);
1773 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1775 ENTER_GL();
1776 /* I don't think that the interface guarants that the device is destroyed from the same thread
1777 * it was created. Thus make sure a context is active for the glDelete* calls
1779 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1780 LEAVE_GL();
1782 /* Delete the pbuffer context if there is any */
1783 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1785 /* Delete the mouse cursor texture */
1786 if(This->cursorTexture) {
1787 ENTER_GL();
1788 glDeleteTextures(1, &This->cursorTexture);
1789 LEAVE_GL();
1790 This->cursorTexture = 0;
1793 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1794 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1797 /* Release the buffers (with sanity checks)*/
1798 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1799 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1800 if(This->depthStencilBuffer != This->stencilBufferTarget)
1801 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1803 This->stencilBufferTarget = NULL;
1805 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1806 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1807 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1809 TRACE("Setting rendertarget to NULL\n");
1810 This->render_targets[0] = NULL;
1812 if (This->depthStencilBuffer) {
1813 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1814 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1816 This->depthStencilBuffer = NULL;
1819 for(i=0; i < This->NumberOfSwapChains; i++) {
1820 TRACE("Releasing the implicit swapchain %d\n", i);
1821 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1822 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1826 HeapFree(GetProcessHeap(), 0, This->swapchains);
1827 This->swapchains = NULL;
1828 This->NumberOfSwapChains = 0;
1830 This->d3d_initialized = FALSE;
1831 return WINED3D_OK;
1834 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1836 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1838 /* Setup the window for fullscreen mode */
1839 if(fullscreen && !This->ddraw_fullscreen) {
1840 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1841 } else if(!fullscreen && This->ddraw_fullscreen) {
1842 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1845 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1846 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1847 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1848 * separately.
1850 This->ddraw_fullscreen = fullscreen;
1853 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1854 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1855 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1857 * There is no way to deactivate thread safety once it is enabled
1859 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1861 FIXME("No thread safety in wined3d yet\n");
1863 /*For now just store the flag(needed in case of ddraw) */
1864 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
1866 return;
1869 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1870 DEVMODEW devmode;
1871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1872 LONG ret;
1873 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1874 RECT clip_rc;
1876 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1878 /* Resize the screen even without a window:
1879 * The app could have unset it with SetCooperativeLevel, but not called
1880 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1881 * but we don't have any hwnd
1884 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1885 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1886 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1887 devmode.dmPelsWidth = pMode->Width;
1888 devmode.dmPelsHeight = pMode->Height;
1890 devmode.dmDisplayFrequency = pMode->RefreshRate;
1891 if (pMode->RefreshRate != 0) {
1892 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1895 /* Only change the mode if necessary */
1896 if( (This->ddraw_width == pMode->Width) &&
1897 (This->ddraw_height == pMode->Height) &&
1898 (This->ddraw_format == pMode->Format) &&
1899 (pMode->RefreshRate == 0) ) {
1900 return WINED3D_OK;
1903 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1904 if (ret != DISP_CHANGE_SUCCESSFUL) {
1905 if(devmode.dmDisplayFrequency != 0) {
1906 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1907 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1908 devmode.dmDisplayFrequency = 0;
1909 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1911 if(ret != DISP_CHANGE_SUCCESSFUL) {
1912 return DDERR_INVALIDMODE;
1916 /* Store the new values */
1917 This->ddraw_width = pMode->Width;
1918 This->ddraw_height = pMode->Height;
1919 This->ddraw_format = pMode->Format;
1921 /* Only do this with a window of course */
1922 if(This->ddraw_window)
1923 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1925 /* And finally clip mouse to our screen */
1926 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1927 ClipCursor(&clip_rc);
1929 return WINED3D_OK;
1932 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1934 *ppD3D= This->wineD3D;
1935 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1936 IWineD3D_AddRef(*ppD3D);
1937 return WINED3D_OK;
1940 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1941 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1942 * into the video ram as possible and seeing how many fit
1943 * you can also get the correct initial value from nvidia and ATI's driver via X
1944 * texture memory is video memory + AGP memory
1945 *******************/
1946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1947 static BOOL showfixmes = TRUE;
1948 if (showfixmes) {
1949 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1950 (wined3d_settings.emulated_textureram/(1024*1024)),
1951 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1952 showfixmes = FALSE;
1954 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1955 (wined3d_settings.emulated_textureram/(1024*1024)),
1956 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1957 /* return simulated texture memory left */
1958 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1963 /*****
1964 * Get / Set FVF
1965 *****/
1966 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1969 /* Update the current state block */
1970 This->updateStateBlock->changed.fvf = TRUE;
1971 This->updateStateBlock->set.fvf = TRUE;
1973 if(This->updateStateBlock->fvf == fvf) {
1974 TRACE("Application is setting the old fvf over, nothing to do\n");
1975 return WINED3D_OK;
1978 This->updateStateBlock->fvf = fvf;
1979 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1980 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1981 return WINED3D_OK;
1985 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1987 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1988 *pfvf = This->stateBlock->fvf;
1989 return WINED3D_OK;
1992 /*****
1993 * Get / Set Stream Source
1994 *****/
1995 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1997 IWineD3DVertexBuffer *oldSrc;
1999 if (StreamNumber >= MAX_STREAMS) {
2000 WARN("Stream out of range %d\n", StreamNumber);
2001 return WINED3DERR_INVALIDCALL;
2004 oldSrc = This->stateBlock->streamSource[StreamNumber];
2005 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
2007 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2008 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2010 if(oldSrc == pStreamData &&
2011 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2012 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2013 TRACE("Application is setting the old values over, nothing to do\n");
2014 return WINED3D_OK;
2017 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2018 if (pStreamData) {
2019 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2020 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2023 /* Handle recording of state blocks */
2024 if (This->isRecordingState) {
2025 TRACE("Recording... not performing anything\n");
2026 return WINED3D_OK;
2029 /* Need to do a getParent and pass the reffs up */
2030 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2031 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2032 so for now, just count internally */
2033 if (pStreamData != NULL) {
2034 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2035 InterlockedIncrement(&vbImpl->bindCount);
2037 if (oldSrc != NULL) {
2038 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2043 return WINED3D_OK;
2046 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2049 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2050 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2052 if (StreamNumber >= MAX_STREAMS) {
2053 WARN("Stream out of range %d\n", StreamNumber);
2054 return WINED3DERR_INVALIDCALL;
2056 *pStream = This->stateBlock->streamSource[StreamNumber];
2057 *pStride = This->stateBlock->streamStride[StreamNumber];
2058 if (pOffset) {
2059 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2062 if (*pStream != NULL) {
2063 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2065 return WINED3D_OK;
2068 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2070 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2071 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2073 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2074 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2076 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2077 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2078 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2080 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2081 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2085 return WINED3D_OK;
2088 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2091 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2092 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2094 TRACE("(%p) : returning %d\n", This, *Divider);
2096 return WINED3D_OK;
2099 /*****
2100 * Get / Set & Multiply Transform
2101 *****/
2102 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2105 /* Most of this routine, comments included copied from ddraw tree initially: */
2106 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2108 /* Handle recording of state blocks */
2109 if (This->isRecordingState) {
2110 TRACE("Recording... not performing anything\n");
2111 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2112 This->updateStateBlock->set.transform[d3dts] = TRUE;
2113 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2114 return WINED3D_OK;
2118 * If the new matrix is the same as the current one,
2119 * we cut off any further processing. this seems to be a reasonable
2120 * optimization because as was noticed, some apps (warcraft3 for example)
2121 * tend towards setting the same matrix repeatedly for some reason.
2123 * From here on we assume that the new matrix is different, wherever it matters.
2125 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2126 TRACE("The app is setting the same matrix over again\n");
2127 return WINED3D_OK;
2128 } else {
2129 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2133 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2134 where ViewMat = Camera space, WorldMat = world space.
2136 In OpenGL, camera and world space is combined into GL_MODELVIEW
2137 matrix. The Projection matrix stay projection matrix.
2140 /* Capture the times we can just ignore the change for now */
2141 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2142 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2143 /* Handled by the state manager */
2146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2147 return WINED3D_OK;
2150 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2152 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2153 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2154 return WINED3D_OK;
2157 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2158 WINED3DMATRIX *mat = NULL;
2159 WINED3DMATRIX temp;
2161 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2162 * below means it will be recorded in a state block change, but it
2163 * works regardless where it is recorded.
2164 * If this is found to be wrong, change to StateBlock.
2166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2167 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2169 if (State < HIGHEST_TRANSFORMSTATE)
2171 mat = &This->updateStateBlock->transforms[State];
2172 } else {
2173 FIXME("Unhandled transform state!!\n");
2176 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2178 /* Apply change via set transform - will reapply to eg. lights this way */
2179 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2182 /*****
2183 * Get / Set Light
2184 *****/
2185 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2186 you can reference any indexes you want as long as that number max are enabled at any
2187 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2188 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2189 but when recording, just build a chain pretty much of commands to be replayed. */
2191 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2192 float rho;
2193 PLIGHTINFOEL *object = NULL;
2194 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2195 struct list *e;
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2198 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2200 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2201 * the gl driver.
2203 if(!pLight) {
2204 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2205 return WINED3DERR_INVALIDCALL;
2208 switch(pLight->Type) {
2209 case WINED3DLIGHT_POINT:
2210 case WINED3DLIGHT_SPOT:
2211 case WINED3DLIGHT_PARALLELPOINT:
2212 case WINED3DLIGHT_GLSPOT:
2213 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2214 * most wanted
2216 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2217 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2218 return WINED3DERR_INVALIDCALL;
2220 break;
2222 case WINED3DLIGHT_DIRECTIONAL:
2223 /* Ignores attenuation */
2224 break;
2226 default:
2227 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2228 return WINED3DERR_INVALIDCALL;
2231 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2232 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2233 if(object->OriginalIndex == Index) break;
2234 object = NULL;
2237 if(!object) {
2238 TRACE("Adding new light\n");
2239 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2240 if(!object) {
2241 ERR("Out of memory error when allocating a light\n");
2242 return E_OUTOFMEMORY;
2244 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2245 object->glIndex = -1;
2246 object->OriginalIndex = Index;
2247 object->changed = TRUE;
2250 /* Initialize the object */
2251 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,
2252 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2253 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2254 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2255 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2256 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2257 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2259 /* Save away the information */
2260 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2262 switch (pLight->Type) {
2263 case WINED3DLIGHT_POINT:
2264 /* Position */
2265 object->lightPosn[0] = pLight->Position.x;
2266 object->lightPosn[1] = pLight->Position.y;
2267 object->lightPosn[2] = pLight->Position.z;
2268 object->lightPosn[3] = 1.0f;
2269 object->cutoff = 180.0f;
2270 /* FIXME: Range */
2271 break;
2273 case WINED3DLIGHT_DIRECTIONAL:
2274 /* Direction */
2275 object->lightPosn[0] = -pLight->Direction.x;
2276 object->lightPosn[1] = -pLight->Direction.y;
2277 object->lightPosn[2] = -pLight->Direction.z;
2278 object->lightPosn[3] = 0.0;
2279 object->exponent = 0.0f;
2280 object->cutoff = 180.0f;
2281 break;
2283 case WINED3DLIGHT_SPOT:
2284 /* Position */
2285 object->lightPosn[0] = pLight->Position.x;
2286 object->lightPosn[1] = pLight->Position.y;
2287 object->lightPosn[2] = pLight->Position.z;
2288 object->lightPosn[3] = 1.0;
2290 /* Direction */
2291 object->lightDirn[0] = pLight->Direction.x;
2292 object->lightDirn[1] = pLight->Direction.y;
2293 object->lightDirn[2] = pLight->Direction.z;
2294 object->lightDirn[3] = 1.0;
2297 * opengl-ish and d3d-ish spot lights use too different models for the
2298 * light "intensity" as a function of the angle towards the main light direction,
2299 * so we only can approximate very roughly.
2300 * however spot lights are rather rarely used in games (if ever used at all).
2301 * furthermore if still used, probably nobody pays attention to such details.
2303 if (pLight->Falloff == 0) {
2304 rho = 6.28f;
2305 } else {
2306 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2308 if (rho < 0.0001) rho = 0.0001f;
2309 object->exponent = -0.3/log(cos(rho/2));
2310 if (object->exponent > 128.0) {
2311 object->exponent = 128.0;
2313 object->cutoff = pLight->Phi*90/M_PI;
2315 /* FIXME: Range */
2316 break;
2318 default:
2319 FIXME("Unrecognized light type %d\n", pLight->Type);
2322 /* Update the live definitions if the light is currently assigned a glIndex */
2323 if (object->glIndex != -1 && !This->isRecordingState) {
2324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2326 return WINED3D_OK;
2329 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2330 PLIGHTINFOEL *lightInfo = NULL;
2331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2332 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2333 struct list *e;
2334 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2336 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2337 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2338 if(lightInfo->OriginalIndex == Index) break;
2339 lightInfo = NULL;
2342 if (lightInfo == NULL) {
2343 TRACE("Light information requested but light not defined\n");
2344 return WINED3DERR_INVALIDCALL;
2347 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2348 return WINED3D_OK;
2351 /*****
2352 * Get / Set Light Enable
2353 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2354 *****/
2355 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2356 PLIGHTINFOEL *lightInfo = NULL;
2357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2358 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2359 struct list *e;
2360 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2362 /* Tests show true = 128...not clear why */
2363 Enable = Enable? 128: 0;
2365 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2366 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2367 if(lightInfo->OriginalIndex == Index) break;
2368 lightInfo = NULL;
2370 TRACE("Found light: %p\n", lightInfo);
2372 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2373 if (lightInfo == NULL) {
2375 TRACE("Light enabled requested but light not defined, so defining one!\n");
2376 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2378 /* Search for it again! Should be fairly quick as near head of list */
2379 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2380 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2381 if(lightInfo->OriginalIndex == Index) break;
2382 lightInfo = NULL;
2384 if (lightInfo == NULL) {
2385 FIXME("Adding default lights has failed dismally\n");
2386 return WINED3DERR_INVALIDCALL;
2390 lightInfo->enabledChanged = TRUE;
2391 if(!Enable) {
2392 if(lightInfo->glIndex != -1) {
2393 if(!This->isRecordingState) {
2394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2397 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2398 lightInfo->glIndex = -1;
2399 } else {
2400 TRACE("Light already disabled, nothing to do\n");
2402 } else {
2403 if (lightInfo->glIndex != -1) {
2404 /* nop */
2405 TRACE("Nothing to do as light was enabled\n");
2406 } else {
2407 int i;
2408 /* Find a free gl light */
2409 for(i = 0; i < This->maxConcurrentLights; i++) {
2410 if(This->stateBlock->activeLights[i] == NULL) {
2411 This->stateBlock->activeLights[i] = lightInfo;
2412 lightInfo->glIndex = i;
2413 break;
2416 if(lightInfo->glIndex == -1) {
2417 ERR("Too many concurrently active lights\n");
2418 return WINED3DERR_INVALIDCALL;
2421 /* i == lightInfo->glIndex */
2422 if(!This->isRecordingState) {
2423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2428 return WINED3D_OK;
2431 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2433 PLIGHTINFOEL *lightInfo = NULL;
2434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2435 struct list *e;
2436 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2437 TRACE("(%p) : for idx(%d)\n", This, Index);
2439 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2440 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2441 if(lightInfo->OriginalIndex == Index) break;
2442 lightInfo = NULL;
2445 if (lightInfo == NULL) {
2446 TRACE("Light enabled state requested but light not defined\n");
2447 return WINED3DERR_INVALIDCALL;
2449 /* true is 128 according to SetLightEnable */
2450 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2451 return WINED3D_OK;
2454 /*****
2455 * Get / Set Clip Planes
2456 *****/
2457 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2459 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2461 /* Validate Index */
2462 if (Index >= GL_LIMITS(clipplanes)) {
2463 TRACE("Application has requested clipplane this device doesn't support\n");
2464 return WINED3DERR_INVALIDCALL;
2467 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2468 This->updateStateBlock->set.clipplane[Index] = TRUE;
2470 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2471 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2472 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2473 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2474 TRACE("Application is setting old values over, nothing to do\n");
2475 return WINED3D_OK;
2478 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2479 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2480 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2481 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2483 /* Handle recording of state blocks */
2484 if (This->isRecordingState) {
2485 TRACE("Recording... not performing anything\n");
2486 return WINED3D_OK;
2489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2491 return WINED3D_OK;
2494 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2496 TRACE("(%p) : for idx %d\n", This, Index);
2498 /* Validate Index */
2499 if (Index >= GL_LIMITS(clipplanes)) {
2500 TRACE("Application has requested clipplane this device doesn't support\n");
2501 return WINED3DERR_INVALIDCALL;
2504 pPlane[0] = This->stateBlock->clipplane[Index][0];
2505 pPlane[1] = This->stateBlock->clipplane[Index][1];
2506 pPlane[2] = This->stateBlock->clipplane[Index][2];
2507 pPlane[3] = This->stateBlock->clipplane[Index][3];
2508 return WINED3D_OK;
2511 /*****
2512 * Get / Set Clip Plane Status
2513 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2514 *****/
2515 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 FIXME("(%p) : stub\n", This);
2518 if (NULL == pClipStatus) {
2519 return WINED3DERR_INVALIDCALL;
2521 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2522 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2523 return WINED3D_OK;
2526 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2528 FIXME("(%p) : stub\n", This);
2529 if (NULL == pClipStatus) {
2530 return WINED3DERR_INVALIDCALL;
2532 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2533 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2534 return WINED3D_OK;
2537 /*****
2538 * Get / Set Material
2539 *****/
2540 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2543 This->updateStateBlock->changed.material = TRUE;
2544 This->updateStateBlock->set.material = TRUE;
2545 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2547 /* Handle recording of state blocks */
2548 if (This->isRecordingState) {
2549 TRACE("Recording... not performing anything\n");
2550 return WINED3D_OK;
2553 ENTER_GL();
2554 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2555 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2556 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2557 pMaterial->Ambient.b, pMaterial->Ambient.a);
2558 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2559 pMaterial->Specular.b, pMaterial->Specular.a);
2560 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2561 pMaterial->Emissive.b, pMaterial->Emissive.a);
2562 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2564 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2565 checkGLcall("glMaterialfv(GL_AMBIENT)");
2566 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2567 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2569 /* Only change material color if specular is enabled, otherwise it is set to black */
2570 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2571 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2572 checkGLcall("glMaterialfv(GL_SPECULAR");
2573 } else {
2574 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2575 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2576 checkGLcall("glMaterialfv(GL_SPECULAR");
2578 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2579 checkGLcall("glMaterialfv(GL_EMISSION)");
2580 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2581 checkGLcall("glMaterialf(GL_SHININESS");
2583 LEAVE_GL();
2584 return WINED3D_OK;
2587 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2589 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2590 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2591 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2592 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2593 pMaterial->Ambient.b, pMaterial->Ambient.a);
2594 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2595 pMaterial->Specular.b, pMaterial->Specular.a);
2596 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2597 pMaterial->Emissive.b, pMaterial->Emissive.a);
2598 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2600 return WINED3D_OK;
2603 /*****
2604 * Get / Set Indices
2605 *****/
2606 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2607 UINT BaseVertexIndex) {
2608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2609 IWineD3DIndexBuffer *oldIdxs;
2610 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2612 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2613 oldIdxs = This->updateStateBlock->pIndexData;
2615 This->updateStateBlock->changed.indices = TRUE;
2616 This->updateStateBlock->set.indices = TRUE;
2617 This->updateStateBlock->pIndexData = pIndexData;
2618 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2620 /* Handle recording of state blocks */
2621 if (This->isRecordingState) {
2622 TRACE("Recording... not performing anything\n");
2623 return WINED3D_OK;
2626 /* The base vertex index affects the stream sources, while
2627 * The index buffer is a seperate index buffer state
2629 if(BaseVertexIndex != oldBaseIndex) {
2630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2632 if(oldIdxs != pIndexData) {
2633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2635 return WINED3D_OK;
2638 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 *ppIndexData = This->stateBlock->pIndexData;
2643 /* up ref count on ppindexdata */
2644 if (*ppIndexData) {
2645 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2646 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2647 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2648 }else{
2649 TRACE("(%p) No index data set\n", This);
2651 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2653 return WINED3D_OK;
2656 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2657 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 TRACE("(%p)->(%d)\n", This, BaseIndex);
2661 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2662 TRACE("Application is setting the old value over, nothing to do\n");
2663 return WINED3D_OK;
2666 This->updateStateBlock->baseVertexIndex = BaseIndex;
2668 if (This->isRecordingState) {
2669 TRACE("Recording... not performing anything\n");
2670 return WINED3D_OK;
2672 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2673 return WINED3D_OK;
2676 /*****
2677 * Get / Set Viewports
2678 *****/
2679 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2682 TRACE("(%p)\n", This);
2683 This->updateStateBlock->changed.viewport = TRUE;
2684 This->updateStateBlock->set.viewport = TRUE;
2685 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2687 /* Handle recording of state blocks */
2688 if (This->isRecordingState) {
2689 TRACE("Recording... not performing anything\n");
2690 return WINED3D_OK;
2693 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2694 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2697 return WINED3D_OK;
2701 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2703 TRACE("(%p)\n", This);
2704 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2705 return WINED3D_OK;
2708 /*****
2709 * Get / Set Render States
2710 * TODO: Verify against dx9 definitions
2711 *****/
2712 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2715 DWORD oldValue = This->stateBlock->renderState[State];
2717 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2719 This->updateStateBlock->changed.renderState[State] = TRUE;
2720 This->updateStateBlock->set.renderState[State] = TRUE;
2721 This->updateStateBlock->renderState[State] = Value;
2723 /* Handle recording of state blocks */
2724 if (This->isRecordingState) {
2725 TRACE("Recording... not performing anything\n");
2726 return WINED3D_OK;
2729 /* Compared here and not before the assignment to allow proper stateblock recording */
2730 if(Value == oldValue) {
2731 TRACE("Application is setting the old value over, nothing to do\n");
2732 } else {
2733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2736 return WINED3D_OK;
2739 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2741 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2742 *pValue = This->stateBlock->renderState[State];
2743 return WINED3D_OK;
2746 /*****
2747 * Get / Set Sampler States
2748 * TODO: Verify against dx9 definitions
2749 *****/
2751 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2753 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2756 * SetSampler is designed to allow for more than the standard up to 8 textures
2757 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2758 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2760 * http://developer.nvidia.com/object/General_FAQ.html#t6
2762 * There are two new settings for GForce
2763 * the sampler one:
2764 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2765 * and the texture one:
2766 * GL_MAX_TEXTURE_COORDS_ARB.
2767 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2768 ******************/
2770 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2771 debug_d3dsamplerstate(Type), Type, Value);
2772 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2773 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2774 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2776 /* Handle recording of state blocks */
2777 if (This->isRecordingState) {
2778 TRACE("Recording... not performing anything\n");
2779 return WINED3D_OK;
2782 if(oldValue == Value) {
2783 TRACE("Application is setting the old value over, nothing to do\n");
2784 return WINED3D_OK;
2787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2789 return WINED3D_OK;
2792 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2794 *Value = This->stateBlock->samplerState[Sampler][Type];
2795 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2797 return WINED3D_OK;
2800 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2803 This->updateStateBlock->set.scissorRect = TRUE;
2804 This->updateStateBlock->changed.scissorRect = TRUE;
2805 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2806 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2807 return WINED3D_OK;
2809 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2811 if(This->isRecordingState) {
2812 TRACE("Recording... not performing anything\n");
2813 return WINED3D_OK;
2816 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2818 return WINED3D_OK;
2821 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2824 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2825 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2826 return WINED3D_OK;
2829 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2831 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2833 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2835 This->updateStateBlock->vertexDecl = pDecl;
2836 This->updateStateBlock->changed.vertexDecl = TRUE;
2837 This->updateStateBlock->set.vertexDecl = TRUE;
2839 if (This->isRecordingState) {
2840 TRACE("Recording... not performing anything\n");
2841 return WINED3D_OK;
2842 } else if(pDecl == oldDecl) {
2843 /* Checked after the assignment to allow proper stateblock recording */
2844 TRACE("Application is setting the old declaration over, nothing to do\n");
2845 return WINED3D_OK;
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2849 return WINED3D_OK;
2852 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2855 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2857 *ppDecl = This->stateBlock->vertexDecl;
2858 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2859 return WINED3D_OK;
2862 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2866 This->updateStateBlock->vertexShader = pShader;
2867 This->updateStateBlock->changed.vertexShader = TRUE;
2868 This->updateStateBlock->set.vertexShader = TRUE;
2870 if (This->isRecordingState) {
2871 TRACE("Recording... not performing anything\n");
2872 return WINED3D_OK;
2873 } else if(oldShader == pShader) {
2874 /* Checked here to allow proper stateblock recording */
2875 TRACE("App is setting the old shader over, nothing to do\n");
2876 return WINED3D_OK;
2879 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2883 return WINED3D_OK;
2886 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 if (NULL == ppShader) {
2890 return WINED3DERR_INVALIDCALL;
2892 *ppShader = This->stateBlock->vertexShader;
2893 if( NULL != *ppShader)
2894 IWineD3DVertexShader_AddRef(*ppShader);
2896 TRACE("(%p) : returning %p\n", This, *ppShader);
2897 return WINED3D_OK;
2900 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2901 IWineD3DDevice *iface,
2902 UINT start,
2903 CONST BOOL *srcData,
2904 UINT count) {
2906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2907 int i, cnt = min(count, MAX_CONST_B - start);
2909 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2910 iface, srcData, start, count);
2912 if (srcData == NULL || cnt < 0)
2913 return WINED3DERR_INVALIDCALL;
2915 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2916 for (i = 0; i < cnt; i++)
2917 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2919 for (i = start; i < cnt + start; ++i) {
2920 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2921 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2926 return WINED3D_OK;
2929 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2930 IWineD3DDevice *iface,
2931 UINT start,
2932 BOOL *dstData,
2933 UINT count) {
2935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2936 int cnt = min(count, MAX_CONST_B - start);
2938 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2939 iface, dstData, start, count);
2941 if (dstData == NULL || cnt < 0)
2942 return WINED3DERR_INVALIDCALL;
2944 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2945 return WINED3D_OK;
2948 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2949 IWineD3DDevice *iface,
2950 UINT start,
2951 CONST int *srcData,
2952 UINT count) {
2954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2955 int i, cnt = min(count, MAX_CONST_I - start);
2957 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2958 iface, srcData, start, count);
2960 if (srcData == NULL || cnt < 0)
2961 return WINED3DERR_INVALIDCALL;
2963 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2964 for (i = 0; i < cnt; i++)
2965 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2966 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2968 for (i = start; i < cnt + start; ++i) {
2969 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2970 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2979 IWineD3DDevice *iface,
2980 UINT start,
2981 int *dstData,
2982 UINT count) {
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 int cnt = min(count, MAX_CONST_I - start);
2987 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2988 iface, dstData, start, count);
2990 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2991 return WINED3DERR_INVALIDCALL;
2993 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2994 return WINED3D_OK;
2997 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2998 IWineD3DDevice *iface,
2999 UINT start,
3000 CONST float *srcData,
3001 UINT count) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 int i;
3006 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3007 iface, srcData, start, count);
3009 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3010 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3011 return WINED3DERR_INVALIDCALL;
3013 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3014 if(TRACE_ON(d3d)) {
3015 for (i = 0; i < count; i++)
3016 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3017 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3020 for (i = start; i < count + start; ++i) {
3021 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3022 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3023 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3024 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3025 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3027 ptr->idx[ptr->count++] = i;
3028 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3030 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3033 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3035 return WINED3D_OK;
3038 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3039 IWineD3DDevice *iface,
3040 UINT start,
3041 float *dstData,
3042 UINT count) {
3044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3045 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3047 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3048 iface, dstData, start, count);
3050 if (dstData == NULL || cnt < 0)
3051 return WINED3DERR_INVALIDCALL;
3053 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3054 return WINED3D_OK;
3057 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3058 DWORD i;
3059 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3064 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3065 DWORD i, tex;
3066 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3067 * it is never called.
3069 * Rules are:
3070 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3071 * that would be really messy and require shader recompilation
3072 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3073 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3074 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3075 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3077 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3078 if(This->oneToOneTexUnitMap) {
3079 TRACE("Not touching 1:1 map\n");
3080 return;
3082 TRACE("Restoring 1:1 texture unit mapping\n");
3083 /* Restore a 1:1 mapping */
3084 for(i = 0; i < MAX_SAMPLERS; i++) {
3085 if(This->texUnitMap[i] != i) {
3086 This->texUnitMap[i] = i;
3087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3088 markTextureStagesDirty(This, i);
3091 This->oneToOneTexUnitMap = TRUE;
3092 return;
3093 } else {
3094 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3095 * First, see if we can succeed at all
3097 tex = 0;
3098 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3099 if(This->stateBlock->textures[i] == NULL) tex++;
3102 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3103 FIXME("Too many bound textures to support the combiner settings\n");
3104 return;
3107 /* Now work out the mapping */
3108 tex = 0;
3109 This->oneToOneTexUnitMap = FALSE;
3110 WARN("Non 1:1 mapping UNTESTED!\n");
3111 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3112 /* Skip NULL textures */
3113 if (!This->stateBlock->textures[i]) {
3114 /* Map to -1, so the check below doesn't fail if a non-NULL
3115 * texture is set on this stage */
3116 TRACE("Mapping texture stage %d to -1\n", i);
3117 This->texUnitMap[i] = -1;
3119 continue;
3122 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3123 if(This->texUnitMap[i] != tex) {
3124 This->texUnitMap[i] = tex;
3125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3126 markTextureStagesDirty(This, i);
3129 ++tex;
3134 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3137 This->updateStateBlock->pixelShader = pShader;
3138 This->updateStateBlock->changed.pixelShader = TRUE;
3139 This->updateStateBlock->set.pixelShader = TRUE;
3141 /* Handle recording of state blocks */
3142 if (This->isRecordingState) {
3143 TRACE("Recording... not performing anything\n");
3146 if (This->isRecordingState) {
3147 TRACE("Recording... not performing anything\n");
3148 return WINED3D_OK;
3151 if(pShader == oldShader) {
3152 TRACE("App is setting the old pixel shader over, nothing to do\n");
3153 return WINED3D_OK;
3156 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3159 /* Rebuild the texture unit mapping if nvrc's are supported */
3160 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3161 IWineD3DDeviceImpl_FindTexUnitMap(This);
3164 return WINED3D_OK;
3167 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 if (NULL == ppShader) {
3171 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3172 return WINED3DERR_INVALIDCALL;
3175 *ppShader = This->stateBlock->pixelShader;
3176 if (NULL != *ppShader) {
3177 IWineD3DPixelShader_AddRef(*ppShader);
3179 TRACE("(%p) : returning %p\n", This, *ppShader);
3180 return WINED3D_OK;
3183 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3184 IWineD3DDevice *iface,
3185 UINT start,
3186 CONST BOOL *srcData,
3187 UINT count) {
3189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3190 int i, cnt = min(count, MAX_CONST_B - start);
3192 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3193 iface, srcData, start, count);
3195 if (srcData == NULL || cnt < 0)
3196 return WINED3DERR_INVALIDCALL;
3198 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3199 for (i = 0; i < cnt; i++)
3200 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3202 for (i = start; i < cnt + start; ++i) {
3203 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3204 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3209 return WINED3D_OK;
3212 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3213 IWineD3DDevice *iface,
3214 UINT start,
3215 BOOL *dstData,
3216 UINT count) {
3218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3219 int cnt = min(count, MAX_CONST_B - start);
3221 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3222 iface, dstData, start, count);
3224 if (dstData == NULL || cnt < 0)
3225 return WINED3DERR_INVALIDCALL;
3227 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3228 return WINED3D_OK;
3231 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3232 IWineD3DDevice *iface,
3233 UINT start,
3234 CONST int *srcData,
3235 UINT count) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 int i, cnt = min(count, MAX_CONST_I - start);
3240 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3241 iface, srcData, start, count);
3243 if (srcData == NULL || cnt < 0)
3244 return WINED3DERR_INVALIDCALL;
3246 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3247 for (i = 0; i < cnt; i++)
3248 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3249 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3251 for (i = start; i < cnt + start; ++i) {
3252 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3253 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3258 return WINED3D_OK;
3261 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3262 IWineD3DDevice *iface,
3263 UINT start,
3264 int *dstData,
3265 UINT count) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 int cnt = min(count, MAX_CONST_I - start);
3270 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3271 iface, dstData, start, count);
3273 if (dstData == NULL || cnt < 0)
3274 return WINED3DERR_INVALIDCALL;
3276 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3277 return WINED3D_OK;
3280 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3281 IWineD3DDevice *iface,
3282 UINT start,
3283 CONST float *srcData,
3284 UINT count) {
3286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3287 int i;
3289 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3290 iface, srcData, start, count);
3292 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3293 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3294 return WINED3DERR_INVALIDCALL;
3296 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3297 if(TRACE_ON(d3d)) {
3298 for (i = 0; i < count; i++)
3299 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3300 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3303 for (i = start; i < count + start; ++i) {
3304 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3305 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3306 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3307 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3308 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3310 ptr->idx[ptr->count++] = i;
3311 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3313 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3318 return WINED3D_OK;
3321 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3322 IWineD3DDevice *iface,
3323 UINT start,
3324 float *dstData,
3325 UINT count) {
3327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3328 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3330 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3331 iface, dstData, start, count);
3333 if (dstData == NULL || cnt < 0)
3334 return WINED3DERR_INVALIDCALL;
3336 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3337 return WINED3D_OK;
3340 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3341 static HRESULT
3342 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3343 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3344 unsigned int i;
3345 DWORD DestFVF = dest->fvf;
3346 WINED3DVIEWPORT vp;
3347 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3348 BOOL doClip;
3349 int numTextures;
3351 if (SrcFVF & WINED3DFVF_NORMAL) {
3352 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3355 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3356 ERR("Source has no position mask\n");
3357 return WINED3DERR_INVALIDCALL;
3360 /* We might access VBOs from this code, so hold the lock */
3361 ENTER_GL();
3363 if (dest->resource.allocatedMemory == NULL) {
3364 /* This may happen if we do direct locking into a vbo. Unlikely,
3365 * but theoretically possible(ddraw processvertices test)
3367 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3368 if(!dest->resource.allocatedMemory) {
3369 LEAVE_GL();
3370 ERR("Out of memory\n");
3371 return E_OUTOFMEMORY;
3373 if(dest->vbo) {
3374 void *src;
3375 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3376 checkGLcall("glBindBufferARB");
3377 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3378 if(src) {
3379 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3381 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3382 checkGLcall("glUnmapBufferARB");
3386 /* Get a pointer into the destination vbo(create one if none exists) and
3387 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3389 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && wined3d_settings.vbo_mode != VBO_NONE) {
3390 CreateVBO(dest);
3393 if(dest->vbo) {
3394 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3395 if(!dest_conv_addr) {
3396 ERR("Out of memory\n");
3397 /* Continue without storing converted vertices */
3399 dest_conv = dest_conv_addr;
3402 /* Should I clip?
3403 * a) WINED3DRS_CLIPPING is enabled
3404 * b) WINED3DVOP_CLIP is passed
3406 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3407 static BOOL warned = FALSE;
3409 * The clipping code is not quite correct. Some things need
3410 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3411 * so disable clipping for now.
3412 * (The graphics in Half-Life are broken, and my processvertices
3413 * test crashes with IDirect3DDevice3)
3414 doClip = TRUE;
3416 doClip = FALSE;
3417 if(!warned) {
3418 warned = TRUE;
3419 FIXME("Clipping is broken and disabled for now\n");
3421 } else doClip = FALSE;
3422 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3424 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3425 WINED3DTS_VIEW,
3426 &view_mat);
3427 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3428 WINED3DTS_PROJECTION,
3429 &proj_mat);
3430 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3431 WINED3DTS_WORLDMATRIX(0),
3432 &world_mat);
3434 TRACE("View mat:\n");
3435 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);
3436 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);
3437 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);
3438 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);
3440 TRACE("Proj mat:\n");
3441 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);
3442 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);
3443 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);
3444 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);
3446 TRACE("World mat:\n");
3447 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);
3448 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);
3449 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);
3450 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);
3452 /* Get the viewport */
3453 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3454 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3455 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3457 multiply_matrix(&mat,&view_mat,&world_mat);
3458 multiply_matrix(&mat,&proj_mat,&mat);
3460 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3462 for (i = 0; i < dwCount; i+= 1) {
3463 unsigned int tex_index;
3465 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3466 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3467 /* The position first */
3468 float *p =
3469 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3470 float x, y, z, rhw;
3471 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3473 /* Multiplication with world, view and projection matrix */
3474 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);
3475 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);
3476 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);
3477 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);
3479 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3481 /* WARNING: The following things are taken from d3d7 and were not yet checked
3482 * against d3d8 or d3d9!
3485 /* Clipping conditions: From
3486 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3488 * A vertex is clipped if it does not match the following requirements
3489 * -rhw < x <= rhw
3490 * -rhw < y <= rhw
3491 * 0 < z <= rhw
3492 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3494 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3495 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3499 if( !doClip ||
3500 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3501 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3502 ( rhw > eps ) ) ) {
3504 /* "Normal" viewport transformation (not clipped)
3505 * 1) The values are divided by rhw
3506 * 2) The y axis is negative, so multiply it with -1
3507 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3508 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3509 * 4) Multiply x with Width/2 and add Width/2
3510 * 5) The same for the height
3511 * 6) Add the viewpoint X and Y to the 2D coordinates and
3512 * The minimum Z value to z
3513 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3515 * Well, basically it's simply a linear transformation into viewport
3516 * coordinates
3519 x /= rhw;
3520 y /= rhw;
3521 z /= rhw;
3523 y *= -1;
3525 x *= vp.Width / 2;
3526 y *= vp.Height / 2;
3527 z *= vp.MaxZ - vp.MinZ;
3529 x += vp.Width / 2 + vp.X;
3530 y += vp.Height / 2 + vp.Y;
3531 z += vp.MinZ;
3533 /* Half-Life draws vertices in front of the near clipping plane,
3534 * and opengl clips them. Apparently I am expected to clip the vertices here,
3535 * mark them clipped(see below), and modify the primitives in drawprim when
3536 * a clipped vertex is hit. This quite a lot of work for the hardly used hl1 d3d mode
3538 * The hack is to draw the verts directly on the near clipping plane, so the weapons will
3539 * look a bit disorted instead of having completely missing near parts... Looks better IHMO
3541 if(hl1hack) {
3542 if(z < vp.MinZ) z = vp.MinZ + eps;
3544 rhw = 1 / rhw;
3545 } else {
3546 /* That vertex got clipped
3547 * Contrary to OpenGL it is not dropped completely, it just
3548 * undergoes a different calculation.
3550 TRACE("Vertex got clipped\n");
3551 x += rhw;
3552 y += rhw;
3554 x /= 2;
3555 y /= 2;
3557 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3558 * outside of the main vertex buffer memory. That needs some more
3559 * investigation...
3563 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3566 ( (float *) dest_ptr)[0] = x;
3567 ( (float *) dest_ptr)[1] = y;
3568 ( (float *) dest_ptr)[2] = z;
3569 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3571 dest_ptr += 3 * sizeof(float);
3573 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3574 dest_ptr += sizeof(float);
3577 if(dest_conv) {
3578 float w = 1 / rhw;
3579 ( (float *) dest_conv)[0] = x * w;
3580 ( (float *) dest_conv)[1] = y * w;
3581 ( (float *) dest_conv)[2] = z * w;
3582 ( (float *) dest_conv)[3] = w;
3584 dest_conv += 3 * sizeof(float);
3586 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3587 dest_conv += sizeof(float);
3591 if (DestFVF & WINED3DFVF_PSIZE) {
3592 dest_ptr += sizeof(DWORD);
3593 if(dest_conv) dest_conv += sizeof(DWORD);
3595 if (DestFVF & WINED3DFVF_NORMAL) {
3596 float *normal =
3597 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3598 /* AFAIK this should go into the lighting information */
3599 FIXME("Didn't expect the destination to have a normal\n");
3600 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3601 if(dest_conv) {
3602 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3606 if (DestFVF & WINED3DFVF_DIFFUSE) {
3607 DWORD *color_d =
3608 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3609 if(!color_d) {
3610 static BOOL warned = FALSE;
3612 if(!warned) {
3613 ERR("No diffuse color in source, but destination has one\n");
3614 warned = TRUE;
3617 *( (DWORD *) dest_ptr) = 0xffffffff;
3618 dest_ptr += sizeof(DWORD);
3620 if(dest_conv) {
3621 *( (DWORD *) dest_conv) = 0xffffffff;
3622 dest_conv += sizeof(DWORD);
3625 else {
3626 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3627 if(dest_conv) {
3628 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3629 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3630 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3631 dest_conv += sizeof(DWORD);
3636 if (DestFVF & WINED3DFVF_SPECULAR) {
3637 /* What's the color value in the feedback buffer? */
3638 DWORD *color_s =
3639 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3640 if(!color_s) {
3641 static BOOL warned = FALSE;
3643 if(!warned) {
3644 ERR("No specular color in source, but destination has one\n");
3645 warned = TRUE;
3648 *( (DWORD *) dest_ptr) = 0xFF000000;
3649 dest_ptr += sizeof(DWORD);
3651 if(dest_conv) {
3652 *( (DWORD *) dest_conv) = 0xFF000000;
3653 dest_conv += sizeof(DWORD);
3656 else {
3657 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3658 if(dest_conv) {
3659 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3660 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3661 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3662 dest_conv += sizeof(DWORD);
3667 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3668 float *tex_coord =
3669 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3670 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3671 if(!tex_coord) {
3672 ERR("No source texture, but destination requests one\n");
3673 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3674 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3676 else {
3677 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3678 if(dest_conv) {
3679 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3685 if(dest_conv) {
3686 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3687 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3688 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3689 dwCount * get_flexible_vertex_size(DestFVF),
3690 dest_conv_addr));
3691 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3692 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3695 LEAVE_GL();
3697 return WINED3D_OK;
3699 #undef copy_and_next
3701 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3703 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3704 WineDirect3DVertexStridedData strided;
3705 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3707 if (!SrcImpl) {
3708 WARN("NULL source vertex buffer\n");
3709 return WINED3DERR_INVALIDCALL;
3712 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3713 * and this call is quite performance critical, so don't call needlessly
3715 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3716 ENTER_GL();
3717 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3718 LEAVE_GL();
3721 /* We don't need the source vbo because this buffer is only used as
3722 * a source for ProcessVertices. Avoid wasting resources by converting the
3723 * buffer and loading the VBO
3725 if(SrcImpl->vbo) {
3726 TRACE("Releasing the source vbo, it won't be needed\n");
3728 if(!SrcImpl->resource.allocatedMemory) {
3729 /* Rescue the data from the buffer */
3730 void *src;
3731 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3732 if(!SrcImpl->resource.allocatedMemory) {
3733 ERR("Out of memory\n");
3734 return E_OUTOFMEMORY;
3737 ENTER_GL();
3738 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3739 checkGLcall("glBindBufferARB");
3741 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3742 if(src) {
3743 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3746 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3747 checkGLcall("glUnmapBufferARB");
3748 } else {
3749 ENTER_GL();
3752 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3753 checkGLcall("glBindBufferARB");
3754 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3755 checkGLcall("glDeleteBuffersARB");
3756 LEAVE_GL();
3758 SrcImpl->vbo = 0;
3761 memset(&strided, 0, sizeof(strided));
3762 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3764 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3767 /*****
3768 * Get / Set Texture Stage States
3769 * TODO: Verify against dx9 definitions
3770 *****/
3771 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3773 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3775 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3777 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3779 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3780 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3781 This->updateStateBlock->textureState[Stage][Type] = Value;
3783 if (This->isRecordingState) {
3784 TRACE("Recording... not performing anything\n");
3785 return WINED3D_OK;
3788 /* Checked after the assignments to allow proper stateblock recording */
3789 if(oldValue == Value) {
3790 TRACE("App is setting the old value over, nothing to do\n");
3791 return WINED3D_OK;
3794 if(Stage > This->stateBlock->lowest_disabled_stage &&
3795 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3796 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3797 * Changes in other states are important on disabled stages too
3799 return WINED3D_OK;
3802 if(Type == WINED3DTSS_COLOROP) {
3803 int i;
3805 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3806 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3807 * they have to be disabled
3809 * The current stage is dirtified below.
3811 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3812 TRACE("Additionally dirtifying stage %d\n", i);
3813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3815 This->stateBlock->lowest_disabled_stage = Stage;
3816 TRACE("New lowest disabled: %d\n", Stage);
3817 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3818 /* Previously disabled stage enabled. Stages above it may need enabling
3819 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3820 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3822 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3825 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3826 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3827 break;
3829 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3830 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3832 This->stateBlock->lowest_disabled_stage = i;
3833 TRACE("New lowest disabled: %d\n", i);
3835 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3836 /* TODO: Built a stage -> texture unit mapping for register combiners */
3840 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3842 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3843 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3844 * will call FindTexUnitMap too.
3846 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3847 IWineD3DDeviceImpl_FindTexUnitMap(This);
3849 return WINED3D_OK;
3852 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3855 *pValue = This->updateStateBlock->textureState[Stage][Type];
3856 return WINED3D_OK;
3859 /*****
3860 * Get / Set Texture
3861 *****/
3862 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3865 IWineD3DBaseTexture *oldTexture;
3867 oldTexture = This->updateStateBlock->textures[Stage];
3868 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3870 #if 0 /* TODO: check so vertex textures */
3871 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3872 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3873 return WINED3D_OK;
3875 #endif
3877 if(pTexture != NULL) {
3878 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3880 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3881 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3882 return WINED3DERR_INVALIDCALL;
3884 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3887 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3888 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3890 This->updateStateBlock->set.textures[Stage] = TRUE;
3891 This->updateStateBlock->changed.textures[Stage] = TRUE;
3892 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3893 This->updateStateBlock->textures[Stage] = pTexture;
3895 /* Handle recording of state blocks */
3896 if (This->isRecordingState) {
3897 TRACE("Recording... not performing anything\n");
3898 return WINED3D_OK;
3901 if(oldTexture == pTexture) {
3902 TRACE("App is setting the same texture again, nothing to do\n");
3903 return WINED3D_OK;
3906 /** NOTE: MSDN says that setTexture increases the reference count,
3907 * and the the application nust set the texture back to null (or have a leaky application),
3908 * This means we should pass the refcount up to the parent
3909 *******************************/
3910 if (NULL != This->updateStateBlock->textures[Stage]) {
3911 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3912 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3914 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3915 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3916 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3917 * so the COLOROP and ALPHAOP have to be dirtified.
3919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3922 if(bindCount == 1) {
3923 new->baseTexture.sampler = Stage;
3925 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3929 if (NULL != oldTexture) {
3930 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3931 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3933 IWineD3DBaseTexture_Release(oldTexture);
3934 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3939 if(bindCount && old->baseTexture.sampler == Stage) {
3940 int i;
3941 /* Have to do a search for the other sampler(s) where the texture is bound to
3942 * Shouldn't happen as long as apps bind a texture only to one stage
3944 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3945 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3946 if(This->updateStateBlock->textures[i] == oldTexture) {
3947 old->baseTexture.sampler = i;
3948 break;
3954 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3956 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3957 * pixel shader is used
3959 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3960 IWineD3DDeviceImpl_FindTexUnitMap(This);
3963 return WINED3D_OK;
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3968 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3970 *ppTexture=This->stateBlock->textures[Stage];
3971 if (*ppTexture)
3972 IWineD3DBaseTexture_AddRef(*ppTexture);
3974 return WINED3D_OK;
3977 /*****
3978 * Get Back Buffer
3979 *****/
3980 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3981 IWineD3DSurface **ppBackBuffer) {
3982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3983 IWineD3DSwapChain *swapChain;
3984 HRESULT hr;
3986 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3988 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3989 if (hr == WINED3D_OK) {
3990 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3991 IWineD3DSwapChain_Release(swapChain);
3992 } else {
3993 *ppBackBuffer = NULL;
3995 return hr;
3998 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4000 WARN("(%p) : stub, calling idirect3d for now\n", This);
4001 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4004 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4006 IWineD3DSwapChain *swapChain;
4007 HRESULT hr;
4009 if(iSwapChain > 0) {
4010 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4011 if (hr == WINED3D_OK) {
4012 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4013 IWineD3DSwapChain_Release(swapChain);
4014 } else {
4015 FIXME("(%p) Error getting display mode\n", This);
4017 } else {
4018 /* Don't read the real display mode,
4019 but return the stored mode instead. X11 can't change the color
4020 depth, and some apps are pretty angry if they SetDisplayMode from
4021 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4023 Also don't relay to the swapchain because with ddraw it's possible
4024 that there isn't a swapchain at all */
4025 pMode->Width = This->ddraw_width;
4026 pMode->Height = This->ddraw_height;
4027 pMode->Format = This->ddraw_format;
4028 pMode->RefreshRate = 0;
4029 hr = WINED3D_OK;
4032 return hr;
4035 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4037 TRACE("(%p)->(%p)\n", This, hWnd);
4039 if(This->ddraw_fullscreen) {
4040 if(This->ddraw_window && This->ddraw_window != hWnd) {
4041 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4043 if(hWnd && This->ddraw_window != hWnd) {
4044 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4048 This->ddraw_window = hWnd;
4049 return WINED3D_OK;
4052 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4054 TRACE("(%p)->(%p)\n", This, hWnd);
4056 *hWnd = This->ddraw_window;
4057 return WINED3D_OK;
4060 /*****
4061 * Stateblock related functions
4062 *****/
4064 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4066 IWineD3DStateBlockImpl *object;
4067 HRESULT temp_result;
4068 int i;
4070 TRACE("(%p)\n", This);
4072 if (This->isRecordingState) {
4073 return WINED3DERR_INVALIDCALL;
4076 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4077 if (NULL == object ) {
4078 FIXME("(%p)Error allocating memory for stateblock\n", This);
4079 return E_OUTOFMEMORY;
4081 TRACE("(%p) created object %p\n", This, object);
4082 object->wineD3DDevice= This;
4083 /** FIXME: object->parent = parent; **/
4084 object->parent = NULL;
4085 object->blockType = WINED3DSBT_ALL;
4086 object->ref = 1;
4087 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4089 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4090 list_init(&object->lightMap[i]);
4093 temp_result = allocate_shader_constants(object);
4094 if (WINED3D_OK != temp_result)
4095 return temp_result;
4097 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4098 This->updateStateBlock = object;
4099 This->isRecordingState = TRUE;
4101 TRACE("(%p) recording stateblock %p\n",This , object);
4102 return WINED3D_OK;
4105 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4108 if (!This->isRecordingState) {
4109 FIXME("(%p) not recording! returning error\n", This);
4110 *ppStateBlock = NULL;
4111 return WINED3DERR_INVALIDCALL;
4114 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4115 This->isRecordingState = FALSE;
4116 This->updateStateBlock = This->stateBlock;
4117 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4118 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4119 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4120 return WINED3D_OK;
4123 /*****
4124 * Scene related functions
4125 *****/
4126 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4127 /* At the moment we have no need for any functionality at the beginning
4128 of a scene */
4129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4130 TRACE("(%p)\n", This);
4132 if(This->inScene) {
4133 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4134 return WINED3DERR_INVALIDCALL;
4136 This->inScene = TRUE;
4137 return WINED3D_OK;
4140 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4142 TRACE("(%p)\n", This);
4144 if(!This->inScene) {
4145 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4146 return WINED3DERR_INVALIDCALL;
4149 ENTER_GL();
4150 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4151 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4153 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4154 glFlush();
4155 checkGLcall("glFlush");
4156 LEAVE_GL();
4158 This->inScene = FALSE;
4159 return WINED3D_OK;
4162 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4163 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4164 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4166 IWineD3DSwapChain *swapChain = NULL;
4167 int i;
4168 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4170 TRACE("(%p) Presenting the frame\n", This);
4172 for(i = 0 ; i < swapchains ; i ++) {
4174 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4175 TRACE("presentinng chain %d, %p\n", i, swapChain);
4176 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4177 IWineD3DSwapChain_Release(swapChain);
4180 return WINED3D_OK;
4183 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4184 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4186 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4188 GLbitfield glMask = 0;
4189 unsigned int i;
4190 CONST WINED3DRECT* curRect;
4192 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4193 Count, pRects, Flags, Z, Stencil);
4195 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4196 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4197 /* TODO: What about depth stencil buffers without stencil bits? */
4198 return WINED3DERR_INVALIDCALL;
4201 ENTER_GL();
4202 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4203 * and not the last active one.
4205 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4207 glEnable(GL_SCISSOR_TEST);
4208 checkGLcall("glEnable GL_SCISSOR_TEST");
4209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4212 if (Count > 0 && pRects) {
4213 curRect = pRects;
4214 } else {
4215 curRect = NULL;
4218 /* Only set the values up once, as they are not changing */
4219 if (Flags & WINED3DCLEAR_STENCIL) {
4220 glClearStencil(Stencil);
4221 checkGLcall("glClearStencil");
4222 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4223 glStencilMask(0xFFFFFFFF);
4226 if (Flags & WINED3DCLEAR_ZBUFFER) {
4227 glDepthMask(GL_TRUE);
4228 glClearDepth(Z);
4229 checkGLcall("glClearDepth");
4230 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4231 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4234 if (Flags & WINED3DCLEAR_TARGET) {
4235 TRACE("Clearing screen with glClear to color %x\n", Color);
4236 glClearColor(D3DCOLOR_R(Color),
4237 D3DCOLOR_G(Color),
4238 D3DCOLOR_B(Color),
4239 D3DCOLOR_A(Color));
4240 checkGLcall("glClearColor");
4242 /* Clear ALL colors! */
4243 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4244 glMask = glMask | GL_COLOR_BUFFER_BIT;
4247 if (!curRect) {
4248 /* In drawable flag is set below */
4250 glScissor(This->stateBlock->viewport.X,
4251 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4252 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4253 This->stateBlock->viewport.Width,
4254 This->stateBlock->viewport.Height);
4255 checkGLcall("glScissor");
4256 glClear(glMask);
4257 checkGLcall("glClear");
4258 } else {
4259 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4260 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4262 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4263 curRect[0].x2 < target->currentDesc.Width ||
4264 curRect[0].y2 < target->currentDesc.Height) {
4265 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4266 blt_to_drawable(This, target);
4270 /* Now process each rect in turn */
4271 for (i = 0; i < Count; i++) {
4272 /* Note gl uses lower left, width/height */
4273 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4274 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4275 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4276 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4278 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4279 * The rectangle is not cleared, no error is returned, but further rectanlges are
4280 * still cleared if they are valid
4282 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4283 TRACE("Rectangle with negative dimensions, ignoring\n");
4284 continue;
4287 if(This->render_offscreen) {
4288 glScissor(curRect[i].x1, curRect[i].y1,
4289 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4290 } else {
4291 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4292 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4294 checkGLcall("glScissor");
4296 glClear(glMask);
4297 checkGLcall("glClear");
4301 /* Restore the old values (why..?) */
4302 if (Flags & WINED3DCLEAR_STENCIL) {
4303 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4305 if (Flags & WINED3DCLEAR_TARGET) {
4306 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4307 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4308 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4309 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4310 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4313 LEAVE_GL();
4315 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4316 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4318 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4319 target->Flags |= SFLAG_INTEXTURE;
4320 target->Flags &= ~SFLAG_INSYSMEM;
4321 } else {
4322 target->Flags |= SFLAG_INDRAWABLE;
4323 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4325 return WINED3D_OK;
4328 /*****
4329 * Drawing functions
4330 *****/
4331 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4332 UINT PrimitiveCount) {
4334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4336 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4337 debug_d3dprimitivetype(PrimitiveType),
4338 StartVertex, PrimitiveCount);
4340 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4341 if(This->stateBlock->streamIsUP) {
4342 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4343 This->stateBlock->streamIsUP = FALSE;
4346 if(This->stateBlock->loadBaseVertexIndex != 0) {
4347 This->stateBlock->loadBaseVertexIndex = 0;
4348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4350 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4351 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4352 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4353 return WINED3D_OK;
4356 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4357 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4358 WINED3DPRIMITIVETYPE PrimitiveType,
4359 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4362 UINT idxStride = 2;
4363 IWineD3DIndexBuffer *pIB;
4364 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4365 GLuint vbo;
4367 if(This->stateBlock->streamIsUP) {
4368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4369 This->stateBlock->streamIsUP = FALSE;
4371 pIB = This->stateBlock->pIndexData;
4372 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4374 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4375 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4376 minIndex, NumVertices, startIndex, primCount);
4378 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4379 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4380 idxStride = 2;
4381 } else {
4382 idxStride = 4;
4385 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4386 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4390 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4391 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4393 return WINED3D_OK;
4396 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4397 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4398 UINT VertexStreamZeroStride) {
4399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4401 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4402 debug_d3dprimitivetype(PrimitiveType),
4403 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4405 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4406 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4407 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4408 This->stateBlock->streamIsUP = TRUE;
4409 This->stateBlock->loadBaseVertexIndex = 0;
4411 /* TODO: Only mark dirty if drawing from a different UP address */
4412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4414 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4415 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4417 /* MSDN specifies stream zero settings must be set to NULL */
4418 This->stateBlock->streamStride[0] = 0;
4419 This->stateBlock->streamSource[0] = NULL;
4421 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4422 * the new stream sources or use UP drawing again
4424 return WINED3D_OK;
4427 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4428 UINT MinVertexIndex, UINT NumVertices,
4429 UINT PrimitiveCount, CONST void* pIndexData,
4430 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4431 UINT VertexStreamZeroStride) {
4432 int idxStride;
4433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4435 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4436 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4437 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4438 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4440 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4441 idxStride = 2;
4442 } else {
4443 idxStride = 4;
4446 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4447 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4448 This->stateBlock->streamIsUP = TRUE;
4449 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4451 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4452 This->stateBlock->baseVertexIndex = 0;
4453 This->stateBlock->loadBaseVertexIndex = 0;
4454 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4458 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4460 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4461 This->stateBlock->streamSource[0] = NULL;
4462 This->stateBlock->streamStride[0] = 0;
4463 This->stateBlock->pIndexData = NULL;
4464 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4465 * SetStreamSource to specify a vertex buffer
4468 return WINED3D_OK;
4471 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4474 /* Mark the state dirty until we have nicer tracking
4475 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4476 * that value.
4478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4480 This->stateBlock->baseVertexIndex = 0;
4481 This->up_strided = DrawPrimStrideData;
4482 This->stateBlock->streamIsUP = TRUE;
4483 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4484 This->up_strided = NULL;
4485 return WINED3D_OK;
4487 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4488 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 HRESULT hr = WINED3D_OK;
4491 WINED3DRESOURCETYPE sourceType;
4492 WINED3DRESOURCETYPE destinationType;
4493 int i ,levels;
4495 /* TODO: think about moving the code into IWineD3DBaseTexture */
4497 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4499 /* verify that the source and destination textures aren't NULL */
4500 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4501 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4502 This, pSourceTexture, pDestinationTexture);
4503 hr = WINED3DERR_INVALIDCALL;
4506 if (pSourceTexture == pDestinationTexture) {
4507 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4508 This, pSourceTexture, pDestinationTexture);
4509 hr = WINED3DERR_INVALIDCALL;
4511 /* Verify that the source and destination textures are the same type */
4512 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4513 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4515 if (sourceType != destinationType) {
4516 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4517 This);
4518 hr = WINED3DERR_INVALIDCALL;
4521 /* check that both textures have the identical numbers of levels */
4522 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4523 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4524 hr = WINED3DERR_INVALIDCALL;
4527 if (WINED3D_OK == hr) {
4529 /* Make sure that the destination texture is loaded */
4530 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4532 /* Update every surface level of the texture */
4533 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4535 switch (sourceType) {
4536 case WINED3DRTYPE_TEXTURE:
4538 IWineD3DSurface *srcSurface;
4539 IWineD3DSurface *destSurface;
4541 for (i = 0 ; i < levels ; ++i) {
4542 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4543 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4544 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4545 IWineD3DSurface_Release(srcSurface);
4546 IWineD3DSurface_Release(destSurface);
4547 if (WINED3D_OK != hr) {
4548 WARN("(%p) : Call to update surface failed\n", This);
4549 return hr;
4553 break;
4554 case WINED3DRTYPE_CUBETEXTURE:
4556 IWineD3DSurface *srcSurface;
4557 IWineD3DSurface *destSurface;
4558 WINED3DCUBEMAP_FACES faceType;
4560 for (i = 0 ; i < levels ; ++i) {
4561 /* Update each cube face */
4562 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4563 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4564 if (WINED3D_OK != hr) {
4565 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4566 } else {
4567 TRACE("Got srcSurface %p\n", srcSurface);
4569 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4570 if (WINED3D_OK != hr) {
4571 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4572 } else {
4573 TRACE("Got desrSurface %p\n", destSurface);
4575 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4576 IWineD3DSurface_Release(srcSurface);
4577 IWineD3DSurface_Release(destSurface);
4578 if (WINED3D_OK != hr) {
4579 WARN("(%p) : Call to update surface failed\n", This);
4580 return hr;
4585 break;
4586 #if 0 /* TODO: Add support for volume textures */
4587 case WINED3DRTYPE_VOLUMETEXTURE:
4589 IWineD3DVolume srcVolume = NULL;
4590 IWineD3DSurface destVolume = NULL;
4592 for (i = 0 ; i < levels ; ++i) {
4593 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4594 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4595 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4596 IWineD3DVolume_Release(srcSurface);
4597 IWineD3DVolume_Release(destSurface);
4598 if (WINED3D_OK != hr) {
4599 WARN("(%p) : Call to update volume failed\n", This);
4600 return hr;
4604 break;
4605 #endif
4606 default:
4607 FIXME("(%p) : Unsupported source and destination type\n", This);
4608 hr = WINED3DERR_INVALIDCALL;
4612 return hr;
4615 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4616 IWineD3DSwapChain *swapChain;
4617 HRESULT hr;
4618 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4619 if(hr == WINED3D_OK) {
4620 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4621 IWineD3DSwapChain_Release(swapChain);
4623 return hr;
4626 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4628 /* return a sensible default */
4629 *pNumPasses = 1;
4630 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4631 FIXME("(%p) : stub\n", This);
4632 return WINED3D_OK;
4635 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4637 int j;
4638 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4639 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4640 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4641 return WINED3DERR_INVALIDCALL;
4643 for (j = 0; j < 256; ++j) {
4644 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4645 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4646 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4647 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4649 TRACE("(%p) : returning\n", This);
4650 return WINED3D_OK;
4653 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 int j;
4656 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4657 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4658 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4659 return WINED3DERR_INVALIDCALL;
4661 for (j = 0; j < 256; ++j) {
4662 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4663 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4664 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4665 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4667 TRACE("(%p) : returning\n", This);
4668 return WINED3D_OK;
4671 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4673 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4674 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4675 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4676 return WINED3DERR_INVALIDCALL;
4678 /*TODO: stateblocks */
4679 This->currentPalette = PaletteNumber;
4680 TRACE("(%p) : returning\n", This);
4681 return WINED3D_OK;
4684 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4686 if (PaletteNumber == NULL) {
4687 WARN("(%p) : returning Invalid Call\n", This);
4688 return WINED3DERR_INVALIDCALL;
4690 /*TODO: stateblocks */
4691 *PaletteNumber = This->currentPalette;
4692 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4693 return WINED3D_OK;
4696 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4698 static BOOL showFixmes = TRUE;
4699 if (showFixmes) {
4700 FIXME("(%p) : stub\n", This);
4701 showFixmes = FALSE;
4704 This->softwareVertexProcessing = bSoftware;
4705 return WINED3D_OK;
4709 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 static BOOL showFixmes = TRUE;
4712 if (showFixmes) {
4713 FIXME("(%p) : stub\n", This);
4714 showFixmes = FALSE;
4716 return This->softwareVertexProcessing;
4720 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4722 IWineD3DSwapChain *swapChain;
4723 HRESULT hr;
4725 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4727 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4728 if(hr == WINED3D_OK){
4729 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4730 IWineD3DSwapChain_Release(swapChain);
4731 }else{
4732 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4734 return hr;
4738 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 static BOOL showfixmes = TRUE;
4741 if(nSegments != 0.0f) {
4742 if( showfixmes) {
4743 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4744 showfixmes = FALSE;
4747 return WINED3D_OK;
4750 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4752 static BOOL showfixmes = TRUE;
4753 if( showfixmes) {
4754 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4755 showfixmes = FALSE;
4757 return 0.0f;
4760 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4762 /** TODO: remove casts to IWineD3DSurfaceImpl
4763 * NOTE: move code to surface to accomplish this
4764 ****************************************/
4765 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4766 int srcWidth, srcHeight;
4767 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4768 WINED3DFORMAT destFormat, srcFormat;
4769 UINT destSize;
4770 int srcLeft, destLeft, destTop;
4771 WINED3DPOOL srcPool, destPool;
4772 int offset = 0;
4773 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4774 glDescriptor *glDescription = NULL;
4776 WINED3DSURFACE_DESC winedesc;
4778 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4779 memset(&winedesc, 0, sizeof(winedesc));
4780 winedesc.Width = &srcSurfaceWidth;
4781 winedesc.Height = &srcSurfaceHeight;
4782 winedesc.Pool = &srcPool;
4783 winedesc.Format = &srcFormat;
4785 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4787 winedesc.Width = &destSurfaceWidth;
4788 winedesc.Height = &destSurfaceHeight;
4789 winedesc.Pool = &destPool;
4790 winedesc.Format = &destFormat;
4791 winedesc.Size = &destSize;
4793 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4795 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4796 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4797 return WINED3DERR_INVALIDCALL;
4800 if (destFormat == WINED3DFMT_UNKNOWN) {
4801 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4802 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4804 /* Get the update surface description */
4805 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4808 ENTER_GL();
4810 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4812 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4813 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4814 checkGLcall("glActiveTextureARB");
4817 /* Make sure the surface is loaded and up to date */
4818 IWineD3DSurface_PreLoad(pDestinationSurface);
4820 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4822 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4823 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4824 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4825 srcLeft = pSourceRect ? pSourceRect->left : 0;
4826 destLeft = pDestPoint ? pDestPoint->x : 0;
4827 destTop = pDestPoint ? pDestPoint->y : 0;
4830 /* This function doesn't support compressed textures
4831 the pitch is just bytesPerPixel * width */
4832 if(srcWidth != srcSurfaceWidth || srcLeft ){
4833 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4834 offset += srcLeft * pSrcSurface->bytesPerPixel;
4835 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4837 /* TODO DXT formats */
4839 if(pSourceRect != NULL && pSourceRect->top != 0){
4840 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4842 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4843 ,This
4844 ,glDescription->level
4845 ,destLeft
4846 ,destTop
4847 ,srcWidth
4848 ,srcHeight
4849 ,glDescription->glFormat
4850 ,glDescription->glType
4851 ,IWineD3DSurface_GetData(pSourceSurface)
4854 /* Sanity check */
4855 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4857 /* need to lock the surface to get the data */
4858 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4861 /* TODO: Cube and volume support */
4862 if(rowoffset != 0){
4863 /* not a whole row so we have to do it a line at a time */
4864 int j;
4866 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4867 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4869 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4871 glTexSubImage2D(glDescription->target
4872 ,glDescription->level
4873 ,destLeft
4875 ,srcWidth
4877 ,glDescription->glFormat
4878 ,glDescription->glType
4879 ,data /* could be quicker using */
4881 data += rowoffset;
4884 } else { /* Full width, so just write out the whole texture */
4886 if (WINED3DFMT_DXT1 == destFormat ||
4887 WINED3DFMT_DXT2 == destFormat ||
4888 WINED3DFMT_DXT3 == destFormat ||
4889 WINED3DFMT_DXT4 == destFormat ||
4890 WINED3DFMT_DXT5 == destFormat) {
4891 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4892 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4893 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4894 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4895 } if (destFormat != srcFormat) {
4896 FIXME("Updating mixed format compressed texture is not curretly support\n");
4897 } else {
4898 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4899 glDescription->level,
4900 glDescription->glFormatInternal,
4901 srcWidth,
4902 srcHeight,
4904 destSize,
4905 IWineD3DSurface_GetData(pSourceSurface));
4907 } else {
4908 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4912 } else {
4913 glTexSubImage2D(glDescription->target
4914 ,glDescription->level
4915 ,destLeft
4916 ,destTop
4917 ,srcWidth
4918 ,srcHeight
4919 ,glDescription->glFormat
4920 ,glDescription->glType
4921 ,IWineD3DSurface_GetData(pSourceSurface)
4925 checkGLcall("glTexSubImage2D");
4927 LEAVE_GL();
4929 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
4930 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
4931 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4933 return WINED3D_OK;
4936 /* Implementation details at http://developer.nvidia.com/attach/6494
4938 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4939 hmm.. no longer supported use
4940 OpenGL evaluators or tessellate surfaces within your application.
4943 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4944 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4946 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4947 FIXME("(%p) : Stub\n", This);
4948 return WINED3D_OK;
4952 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4953 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4955 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4956 FIXME("(%p) : Stub\n", This);
4957 return WINED3D_OK;
4960 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4962 TRACE("(%p) Handle(%d)\n", This, Handle);
4963 FIXME("(%p) : Stub\n", This);
4964 return WINED3D_OK;
4967 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4969 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4970 DDBLTFX BltFx;
4971 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4973 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4974 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4975 return WINED3DERR_INVALIDCALL;
4978 /* Just forward this to the DirectDraw blitting engine */
4979 memset(&BltFx, 0, sizeof(BltFx));
4980 BltFx.dwSize = sizeof(BltFx);
4981 BltFx.u5.dwFillColor = color;
4982 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4985 /* rendertarget and deptth stencil functions */
4986 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4989 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4990 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4991 return WINED3DERR_INVALIDCALL;
4994 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4995 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4996 /* Note inc ref on returned surface */
4997 if(*ppRenderTarget != NULL)
4998 IWineD3DSurface_AddRef(*ppRenderTarget);
4999 return WINED3D_OK;
5002 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5004 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5005 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5006 IWineD3DSwapChainImpl *Swapchain;
5007 HRESULT hr;
5009 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5011 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5012 if(hr != WINED3D_OK) {
5013 ERR("Can't get the swapchain\n");
5014 return hr;
5017 /* Make sure to release the swapchain */
5018 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5020 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5021 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5022 return WINED3DERR_INVALIDCALL;
5024 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5025 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5026 return WINED3DERR_INVALIDCALL;
5029 if(Swapchain->frontBuffer != Front) {
5030 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5032 if(Swapchain->frontBuffer)
5033 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5034 Swapchain->frontBuffer = Front;
5036 if(Swapchain->frontBuffer) {
5037 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5041 if(Back && !Swapchain->backBuffer) {
5042 /* We need memory for the back buffer array - only one back buffer this way */
5043 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5044 if(!Swapchain->backBuffer) {
5045 ERR("Out of memory\n");
5046 return E_OUTOFMEMORY;
5050 if(Swapchain->backBuffer[0] != Back) {
5051 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5053 /* What to do about the context here in the case of multithreading? Not sure.
5054 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5056 ENTER_GL();
5057 if(!Swapchain->backBuffer[0]) {
5058 /* GL was told to draw to the front buffer at creation,
5059 * undo that
5061 glDrawBuffer(GL_BACK);
5062 checkGLcall("glDrawBuffer(GL_BACK)");
5063 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5064 Swapchain->presentParms.BackBufferCount = 1;
5065 } else if (!Back) {
5066 /* That makes problems - disable for now */
5067 /* glDrawBuffer(GL_FRONT); */
5068 checkGLcall("glDrawBuffer(GL_FRONT)");
5069 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5070 Swapchain->presentParms.BackBufferCount = 0;
5072 LEAVE_GL();
5074 if(Swapchain->backBuffer[0])
5075 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5076 Swapchain->backBuffer[0] = Back;
5078 if(Swapchain->backBuffer[0]) {
5079 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5080 } else {
5081 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5086 return WINED3D_OK;
5089 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5091 *ppZStencilSurface = This->depthStencilBuffer;
5092 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5094 if(*ppZStencilSurface != NULL) {
5095 /* Note inc ref on returned surface */
5096 IWineD3DSurface_AddRef(*ppZStencilSurface);
5098 return WINED3D_OK;
5101 static void bind_fbo(IWineD3DDevice *iface) {
5102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5104 if (!This->fbo) {
5105 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5106 checkGLcall("glGenFramebuffersEXT()");
5108 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5109 checkGLcall("glBindFramebuffer()");
5112 /* TODO: Handle stencil attachments */
5113 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5115 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5117 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5119 bind_fbo(iface);
5121 if (depth_stencil_impl) {
5122 GLenum texttarget, target;
5123 GLint old_binding = 0;
5125 IWineD3DSurface_PreLoad(depth_stencil);
5126 texttarget = depth_stencil_impl->glDescription.target;
5127 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5129 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5130 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5131 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5132 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5133 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5134 glBindTexture(target, old_binding);
5136 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5137 checkGLcall("glFramebufferTexture2DEXT()");
5138 } else {
5139 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5140 checkGLcall("glFramebufferTexture2DEXT()");
5143 if (!This->render_offscreen) {
5144 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5145 checkGLcall("glBindFramebuffer()");
5149 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5153 if (idx >= GL_LIMITS(buffers)) {
5154 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5157 bind_fbo(iface);
5159 if (rtimpl) {
5160 GLenum texttarget, target;
5161 GLint old_binding = 0;
5163 IWineD3DSurface_PreLoad(render_target);
5164 texttarget = rtimpl->glDescription.target;
5165 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5167 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5168 glBindTexture(target, rtimpl->glDescription.textureName);
5169 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5170 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5171 glBindTexture(target, old_binding);
5173 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5174 checkGLcall("glFramebufferTexture2DEXT()");
5176 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5177 } else {
5178 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5179 checkGLcall("glFramebufferTexture2DEXT()");
5181 This->draw_buffers[idx] = GL_NONE;
5184 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5185 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5186 checkGLcall("glDrawBuffers()");
5189 if (!This->render_offscreen) {
5190 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5191 checkGLcall("glBindFramebuffer()");
5195 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5197 WINED3DVIEWPORT viewport;
5199 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5201 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5202 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5203 return WINED3DERR_INVALIDCALL;
5206 /* MSDN says that null disables the render target
5207 but a device must always be associated with a render target
5208 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5210 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5211 for more details
5213 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5214 FIXME("Trying to set render target 0 to NULL\n");
5215 return WINED3DERR_INVALIDCALL;
5217 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5218 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);
5219 return WINED3DERR_INVALIDCALL;
5222 /* If we are trying to set what we already have, don't bother */
5223 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5224 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5225 return WINED3D_OK;
5227 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5228 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5229 This->render_targets[RenderTargetIndex] = pRenderTarget;
5231 /* Render target 0 is special */
5232 if(RenderTargetIndex == 0) {
5233 /* Finally, reset the viewport as the MSDN states. */
5234 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5235 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5236 viewport.X = 0;
5237 viewport.Y = 0;
5238 viewport.MaxZ = 1.0f;
5239 viewport.MinZ = 0.0f;
5240 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5241 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5242 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5246 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5247 * ctx properly.
5248 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5249 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5251 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5252 } else {
5253 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5254 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5256 return WINED3D_OK;
5259 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5261 HRESULT hr = WINED3D_OK;
5262 IWineD3DSurface *tmp;
5264 TRACE("(%p) Swapping z-buffer\n",This);
5266 if (pNewZStencil == This->stencilBufferTarget) {
5267 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5268 } else {
5269 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5270 * depending on the renter target implementation being used.
5271 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5272 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5273 * stencil buffer and incure an extra memory overhead
5274 ******************************************************/
5276 tmp = This->stencilBufferTarget;
5277 This->stencilBufferTarget = pNewZStencil;
5278 /* should we be calling the parent or the wined3d surface? */
5279 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5280 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5281 hr = WINED3D_OK;
5283 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5284 set_depth_stencil_fbo(iface, pNewZStencil);
5287 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5288 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5295 return hr;
5298 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5299 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5301 /* TODO: the use of Impl is deprecated. */
5302 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5304 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5306 /* some basic validation checks */
5307 if(This->cursorTexture) {
5308 ENTER_GL();
5309 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5310 glDeleteTextures(1, &This->cursorTexture);
5311 LEAVE_GL();
5312 This->cursorTexture = 0;
5315 if(pCursorBitmap) {
5316 WINED3DLOCKED_RECT rect;
5318 /* MSDN: Cursor must be A8R8G8B8 */
5319 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5320 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5321 return WINED3DERR_INVALIDCALL;
5324 /* MSDN: Cursor must be smaller than the display mode */
5325 if(pSur->currentDesc.Width > This->ddraw_width ||
5326 pSur->currentDesc.Height > This->ddraw_height) {
5327 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);
5328 return WINED3DERR_INVALIDCALL;
5331 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5333 /* Do not store the surface's pointer because the application may release
5334 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5335 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5337 This->cursorWidth = pSur->currentDesc.Width;
5338 This->cursorHeight = pSur->currentDesc.Height;
5339 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5341 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5342 char *mem, *bits = (char *)rect.pBits;
5343 GLint intfmt = tableEntry->glInternal;
5344 GLint format = tableEntry->glFormat;
5345 GLint type = tableEntry->glType;
5346 INT height = This->cursorHeight;
5347 INT width = This->cursorWidth;
5348 INT bpp = tableEntry->bpp;
5349 INT i;
5351 /* Reformat the texture memory (pitch and width can be different) */
5352 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5353 for(i = 0; i < height; i++)
5354 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5355 IWineD3DSurface_UnlockRect(pCursorBitmap);
5356 ENTER_GL();
5358 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5359 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5360 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5363 /* Make sure that a proper texture unit is selected */
5364 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5365 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5366 checkGLcall("glActiveTextureARB");
5368 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5369 /* Create a new cursor texture */
5370 glGenTextures(1, &This->cursorTexture);
5371 checkGLcall("glGenTextures");
5372 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5373 checkGLcall("glBindTexture");
5374 /* Copy the bitmap memory into the cursor texture */
5375 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5376 HeapFree(GetProcessHeap(), 0, mem);
5377 checkGLcall("glTexImage2D");
5379 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5380 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5381 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5384 LEAVE_GL();
5386 else
5388 FIXME("A cursor texture was not returned.\n");
5389 This->cursorTexture = 0;
5394 This->xHotSpot = XHotSpot;
5395 This->yHotSpot = YHotSpot;
5397 /* On windows the cursor is not visible any more after this call, although IsCursorVisible still returns that the cursor should be there
5398 * For now just disable it using the user code instead of using some ExtEscape calls
5400 ShowCursor(FALSE);
5402 return WINED3D_OK;
5405 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5407 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5409 This->xScreenSpace = XScreenSpace;
5410 This->yScreenSpace = YScreenSpace;
5412 return;
5416 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5418 BOOL oldVisible = This->bCursorVisible;
5419 POINT pt;
5421 TRACE("(%p) : visible(%d)\n", This, bShow);
5423 This->bCursorVisible = bShow;
5424 if(cursorhack && !bShow)
5425 ShowCursor(FALSE);
5427 * When ShowCursor is first called it should make the cursor appear at the OS's last
5428 * known cursor position. Because of this, some applications just repetitively call
5429 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5431 GetCursorPos(&pt);
5432 This->xScreenSpace = pt.x;
5433 This->yScreenSpace = pt.y;
5435 return oldVisible;
5438 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5440 TRACE("(%p) : state (%u)\n", This, This->state);
5441 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5442 switch (This->state) {
5443 case WINED3D_OK:
5444 return WINED3D_OK;
5445 case WINED3DERR_DEVICELOST:
5447 ResourceList *resourceList = This->resources;
5448 while (NULL != resourceList) {
5449 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5450 return WINED3DERR_DEVICENOTRESET;
5451 resourceList = resourceList->next;
5453 return WINED3DERR_DEVICELOST;
5455 case WINED3DERR_DRIVERINTERNALERROR:
5456 return WINED3DERR_DRIVERINTERNALERROR;
5459 /* Unknown state */
5460 return WINED3DERR_DRIVERINTERNALERROR;
5464 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5466 /** FIXME: Resource tracking needs to be done,
5467 * The closes we can do to this is set the priorities of all managed textures low
5468 * and then reset them.
5469 ***********************************************************/
5470 FIXME("(%p) : stub\n", This);
5471 return WINED3D_OK;
5474 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5475 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5477 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5478 if(surface->Flags & SFLAG_DIBSECTION) {
5479 /* Release the DC */
5480 SelectObject(surface->hDC, surface->dib.holdbitmap);
5481 DeleteDC(surface->hDC);
5482 /* Release the DIB section */
5483 DeleteObject(surface->dib.DIBsection);
5484 surface->dib.bitmap_data = NULL;
5485 surface->resource.allocatedMemory = NULL;
5486 surface->Flags &= ~SFLAG_DIBSECTION;
5488 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5489 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5490 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5491 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5492 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5493 } else {
5494 surface->pow2Width = surface->pow2Height = 1;
5495 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5496 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5498 if(surface->glDescription.textureName) {
5499 ENTER_GL();
5500 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5501 glDeleteTextures(1, &surface->glDescription.textureName);
5502 LEAVE_GL();
5503 surface->glDescription.textureName = 0;
5504 surface->Flags &= ~SFLAG_CLIENT;
5506 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5507 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5508 surface->Flags |= SFLAG_NONPOW2;
5509 } else {
5510 surface->Flags &= ~SFLAG_NONPOW2;
5512 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5513 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5516 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5518 IWineD3DSwapChainImpl *swapchain;
5519 HRESULT hr;
5520 BOOL DisplayModeChanged = FALSE;
5521 WINED3DDISPLAYMODE mode;
5522 TRACE("(%p)\n", This);
5524 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5525 if(FAILED(hr)) {
5526 ERR("Failed to get the first implicit swapchain\n");
5527 return hr;
5530 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5531 * on an existing gl context, so there's no real need for recreation.
5533 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5535 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5537 TRACE("New params:\n");
5538 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5539 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5540 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5541 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5542 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5543 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5544 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5545 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5546 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5547 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5548 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5549 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5550 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5552 /* No special treatment of these parameters. Just store them */
5553 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5554 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5555 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5556 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5558 /* What to do about these? */
5559 if(pPresentationParameters->BackBufferCount != 0 &&
5560 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5561 ERR("Cannot change the back buffer count yet\n");
5563 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5564 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5565 ERR("Cannot change the back buffer format yet\n");
5567 if(pPresentationParameters->hDeviceWindow != NULL &&
5568 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5569 ERR("Cannot change the device window yet\n");
5571 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5572 ERR("What do do about a changed auto depth stencil parameter?\n");
5575 if(pPresentationParameters->Windowed) {
5576 mode.Width = swapchain->orig_width;
5577 mode.Height = swapchain->orig_height;
5578 mode.RefreshRate = 0;
5579 mode.Format = swapchain->presentParms.BackBufferFormat;
5580 } else {
5581 mode.Width = pPresentationParameters->BackBufferWidth;
5582 mode.Height = pPresentationParameters->BackBufferHeight;
5583 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5584 mode.Format = swapchain->presentParms.BackBufferFormat;
5587 /* Should Width == 800 && Height == 0 set 800x600? */
5588 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5589 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5590 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5592 WINED3DVIEWPORT vp;
5593 int i;
5595 vp.X = 0;
5596 vp.Y = 0;
5597 vp.Width = pPresentationParameters->BackBufferWidth;
5598 vp.Height = pPresentationParameters->BackBufferHeight;
5599 vp.MinZ = 0;
5600 vp.MaxZ = 1;
5602 if(!pPresentationParameters->Windowed) {
5603 DisplayModeChanged = TRUE;
5605 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5606 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5608 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5609 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5610 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5613 /* Now set the new viewport */
5614 IWineD3DDevice_SetViewport(iface, &vp);
5617 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5618 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5619 DisplayModeChanged) {
5621 if(!pPresentationParameters->Windowed) {
5622 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5623 IWineD3DDevice_SetFullscreen(iface, TRUE);
5624 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5625 } else {
5626 /* Switching out of fullscreen mode? First set the original res, then change the window */
5627 ChangeDisplaySettingsExW(NULL, NULL, NULL, 0, NULL);
5628 IWineD3DDevice_SetFullscreen(iface, FALSE);
5630 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5633 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5634 return WINED3D_OK;
5637 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5639 /** FIXME: always true at the moment **/
5640 if(!bEnableDialogs) {
5641 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5643 return WINED3D_OK;
5647 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5649 TRACE("(%p) : pParameters %p\n", This, pParameters);
5651 *pParameters = This->createParms;
5652 return WINED3D_OK;
5655 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5656 IWineD3DSwapChain *swapchain;
5657 HRESULT hrc = WINED3D_OK;
5659 TRACE("Relaying to swapchain\n");
5661 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5662 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5663 IWineD3DSwapChain_Release(swapchain);
5665 return;
5668 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5669 IWineD3DSwapChain *swapchain;
5670 HRESULT hrc = WINED3D_OK;
5672 TRACE("Relaying to swapchain\n");
5674 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5675 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5676 IWineD3DSwapChain_Release(swapchain);
5678 return;
5682 /** ********************************************************
5683 * Notification functions
5684 ** ********************************************************/
5685 /** This function must be called in the release of a resource when ref == 0,
5686 * the contents of resource must still be correct,
5687 * any handels to other resource held by the caller must be closed
5688 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5689 *****************************************************/
5690 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5692 ResourceList* resourceList;
5694 TRACE("(%p) : resource %p\n", This, resource);
5695 #if 0
5696 EnterCriticalSection(&resourceStoreCriticalSection);
5697 #endif
5698 /* add a new texture to the frot of the linked list */
5699 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5700 resourceList->resource = resource;
5702 /* Get the old head */
5703 resourceList->next = This->resources;
5705 This->resources = resourceList;
5706 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5708 #if 0
5709 LeaveCriticalSection(&resourceStoreCriticalSection);
5710 #endif
5711 return;
5714 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5716 ResourceList* resourceList = NULL;
5717 ResourceList* previousResourceList = NULL;
5719 TRACE("(%p) : resource %p\n", This, resource);
5721 #if 0
5722 EnterCriticalSection(&resourceStoreCriticalSection);
5723 #endif
5724 resourceList = This->resources;
5726 while (resourceList != NULL) {
5727 if(resourceList->resource == resource) break;
5728 previousResourceList = resourceList;
5729 resourceList = resourceList->next;
5732 if (resourceList == NULL) {
5733 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5734 #if 0
5735 LeaveCriticalSection(&resourceStoreCriticalSection);
5736 #endif
5737 return;
5738 } else {
5739 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5741 /* make sure we don't leave a hole in the list */
5742 if (previousResourceList != NULL) {
5743 previousResourceList->next = resourceList->next;
5744 } else {
5745 This->resources = resourceList->next;
5748 #if 0
5749 LeaveCriticalSection(&resourceStoreCriticalSection);
5750 #endif
5751 return;
5755 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5757 int counter;
5759 TRACE("(%p) : resource %p\n", This, resource);
5760 switch(IWineD3DResource_GetType(resource)){
5761 case WINED3DRTYPE_SURFACE:
5762 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5763 break;
5764 case WINED3DRTYPE_TEXTURE:
5765 case WINED3DRTYPE_CUBETEXTURE:
5766 case WINED3DRTYPE_VOLUMETEXTURE:
5767 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5768 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5769 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5770 This->stateBlock->textures[counter] = NULL;
5772 if (This->updateStateBlock != This->stateBlock ){
5773 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5774 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5775 This->updateStateBlock->textures[counter] = NULL;
5779 break;
5780 case WINED3DRTYPE_VOLUME:
5781 /* TODO: nothing really? */
5782 break;
5783 case WINED3DRTYPE_VERTEXBUFFER:
5784 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5786 int streamNumber;
5787 TRACE("Cleaning up stream pointers\n");
5789 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5790 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5791 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5793 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5794 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5795 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5796 This->updateStateBlock->streamSource[streamNumber] = 0;
5797 /* Set changed flag? */
5800 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) */
5801 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5802 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5803 This->stateBlock->streamSource[streamNumber] = 0;
5806 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5807 else { /* This shouldn't happen */
5808 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5810 #endif
5814 break;
5815 case WINED3DRTYPE_INDEXBUFFER:
5816 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5817 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5818 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5819 This->updateStateBlock->pIndexData = NULL;
5822 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5823 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5824 This->stateBlock->pIndexData = NULL;
5828 break;
5829 default:
5830 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5831 break;
5835 /* Remove the resoruce from the resourceStore */
5836 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5838 TRACE("Resource released\n");
5842 /**********************************************************
5843 * IWineD3DDevice VTbl follows
5844 **********************************************************/
5846 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5848 /*** IUnknown methods ***/
5849 IWineD3DDeviceImpl_QueryInterface,
5850 IWineD3DDeviceImpl_AddRef,
5851 IWineD3DDeviceImpl_Release,
5852 /*** IWineD3DDevice methods ***/
5853 IWineD3DDeviceImpl_GetParent,
5854 /*** Creation methods**/
5855 IWineD3DDeviceImpl_CreateVertexBuffer,
5856 IWineD3DDeviceImpl_CreateIndexBuffer,
5857 IWineD3DDeviceImpl_CreateStateBlock,
5858 IWineD3DDeviceImpl_CreateSurface,
5859 IWineD3DDeviceImpl_CreateTexture,
5860 IWineD3DDeviceImpl_CreateVolumeTexture,
5861 IWineD3DDeviceImpl_CreateVolume,
5862 IWineD3DDeviceImpl_CreateCubeTexture,
5863 IWineD3DDeviceImpl_CreateQuery,
5864 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5865 IWineD3DDeviceImpl_CreateVertexDeclaration,
5866 IWineD3DDeviceImpl_CreateVertexShader,
5867 IWineD3DDeviceImpl_CreatePixelShader,
5868 IWineD3DDeviceImpl_CreatePalette,
5869 /*** Odd functions **/
5870 IWineD3DDeviceImpl_Init3D,
5871 IWineD3DDeviceImpl_Uninit3D,
5872 IWineD3DDeviceImpl_SetFullscreen,
5873 IWineD3DDeviceImpl_SetMultithreaded,
5874 IWineD3DDeviceImpl_EvictManagedResources,
5875 IWineD3DDeviceImpl_GetAvailableTextureMem,
5876 IWineD3DDeviceImpl_GetBackBuffer,
5877 IWineD3DDeviceImpl_GetCreationParameters,
5878 IWineD3DDeviceImpl_GetDeviceCaps,
5879 IWineD3DDeviceImpl_GetDirect3D,
5880 IWineD3DDeviceImpl_GetDisplayMode,
5881 IWineD3DDeviceImpl_SetDisplayMode,
5882 IWineD3DDeviceImpl_GetHWND,
5883 IWineD3DDeviceImpl_SetHWND,
5884 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5885 IWineD3DDeviceImpl_GetRasterStatus,
5886 IWineD3DDeviceImpl_GetSwapChain,
5887 IWineD3DDeviceImpl_Reset,
5888 IWineD3DDeviceImpl_SetDialogBoxMode,
5889 IWineD3DDeviceImpl_SetCursorProperties,
5890 IWineD3DDeviceImpl_SetCursorPosition,
5891 IWineD3DDeviceImpl_ShowCursor,
5892 IWineD3DDeviceImpl_TestCooperativeLevel,
5893 /*** Getters and setters **/
5894 IWineD3DDeviceImpl_SetClipPlane,
5895 IWineD3DDeviceImpl_GetClipPlane,
5896 IWineD3DDeviceImpl_SetClipStatus,
5897 IWineD3DDeviceImpl_GetClipStatus,
5898 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5899 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5900 IWineD3DDeviceImpl_SetDepthStencilSurface,
5901 IWineD3DDeviceImpl_GetDepthStencilSurface,
5902 IWineD3DDeviceImpl_SetFVF,
5903 IWineD3DDeviceImpl_GetFVF,
5904 IWineD3DDeviceImpl_SetGammaRamp,
5905 IWineD3DDeviceImpl_GetGammaRamp,
5906 IWineD3DDeviceImpl_SetIndices,
5907 IWineD3DDeviceImpl_GetIndices,
5908 IWineD3DDeviceImpl_SetBasevertexIndex,
5909 IWineD3DDeviceImpl_SetLight,
5910 IWineD3DDeviceImpl_GetLight,
5911 IWineD3DDeviceImpl_SetLightEnable,
5912 IWineD3DDeviceImpl_GetLightEnable,
5913 IWineD3DDeviceImpl_SetMaterial,
5914 IWineD3DDeviceImpl_GetMaterial,
5915 IWineD3DDeviceImpl_SetNPatchMode,
5916 IWineD3DDeviceImpl_GetNPatchMode,
5917 IWineD3DDeviceImpl_SetPaletteEntries,
5918 IWineD3DDeviceImpl_GetPaletteEntries,
5919 IWineD3DDeviceImpl_SetPixelShader,
5920 IWineD3DDeviceImpl_GetPixelShader,
5921 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5922 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5923 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5924 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5925 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5926 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5927 IWineD3DDeviceImpl_SetRenderState,
5928 IWineD3DDeviceImpl_GetRenderState,
5929 IWineD3DDeviceImpl_SetRenderTarget,
5930 IWineD3DDeviceImpl_GetRenderTarget,
5931 IWineD3DDeviceImpl_SetFrontBackBuffers,
5932 IWineD3DDeviceImpl_SetSamplerState,
5933 IWineD3DDeviceImpl_GetSamplerState,
5934 IWineD3DDeviceImpl_SetScissorRect,
5935 IWineD3DDeviceImpl_GetScissorRect,
5936 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5937 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5938 IWineD3DDeviceImpl_SetStreamSource,
5939 IWineD3DDeviceImpl_GetStreamSource,
5940 IWineD3DDeviceImpl_SetStreamSourceFreq,
5941 IWineD3DDeviceImpl_GetStreamSourceFreq,
5942 IWineD3DDeviceImpl_SetTexture,
5943 IWineD3DDeviceImpl_GetTexture,
5944 IWineD3DDeviceImpl_SetTextureStageState,
5945 IWineD3DDeviceImpl_GetTextureStageState,
5946 IWineD3DDeviceImpl_SetTransform,
5947 IWineD3DDeviceImpl_GetTransform,
5948 IWineD3DDeviceImpl_SetVertexDeclaration,
5949 IWineD3DDeviceImpl_GetVertexDeclaration,
5950 IWineD3DDeviceImpl_SetVertexShader,
5951 IWineD3DDeviceImpl_GetVertexShader,
5952 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5953 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5954 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5955 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5956 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5957 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5958 IWineD3DDeviceImpl_SetViewport,
5959 IWineD3DDeviceImpl_GetViewport,
5960 IWineD3DDeviceImpl_MultiplyTransform,
5961 IWineD3DDeviceImpl_ValidateDevice,
5962 IWineD3DDeviceImpl_ProcessVertices,
5963 /*** State block ***/
5964 IWineD3DDeviceImpl_BeginStateBlock,
5965 IWineD3DDeviceImpl_EndStateBlock,
5966 /*** Scene management ***/
5967 IWineD3DDeviceImpl_BeginScene,
5968 IWineD3DDeviceImpl_EndScene,
5969 IWineD3DDeviceImpl_Present,
5970 IWineD3DDeviceImpl_Clear,
5971 /*** Drawing ***/
5972 IWineD3DDeviceImpl_DrawPrimitive,
5973 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5974 IWineD3DDeviceImpl_DrawPrimitiveUP,
5975 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5976 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5977 IWineD3DDeviceImpl_DrawRectPatch,
5978 IWineD3DDeviceImpl_DrawTriPatch,
5979 IWineD3DDeviceImpl_DeletePatch,
5980 IWineD3DDeviceImpl_ColorFill,
5981 IWineD3DDeviceImpl_UpdateTexture,
5982 IWineD3DDeviceImpl_UpdateSurface,
5983 IWineD3DDeviceImpl_GetFrontBufferData,
5984 /*** object tracking ***/
5985 IWineD3DDeviceImpl_ResourceReleased
5989 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5990 WINED3DRS_ALPHABLENDENABLE ,
5991 WINED3DRS_ALPHAFUNC ,
5992 WINED3DRS_ALPHAREF ,
5993 WINED3DRS_ALPHATESTENABLE ,
5994 WINED3DRS_BLENDOP ,
5995 WINED3DRS_COLORWRITEENABLE ,
5996 WINED3DRS_DESTBLEND ,
5997 WINED3DRS_DITHERENABLE ,
5998 WINED3DRS_FILLMODE ,
5999 WINED3DRS_FOGDENSITY ,
6000 WINED3DRS_FOGEND ,
6001 WINED3DRS_FOGSTART ,
6002 WINED3DRS_LASTPIXEL ,
6003 WINED3DRS_SHADEMODE ,
6004 WINED3DRS_SRCBLEND ,
6005 WINED3DRS_STENCILENABLE ,
6006 WINED3DRS_STENCILFAIL ,
6007 WINED3DRS_STENCILFUNC ,
6008 WINED3DRS_STENCILMASK ,
6009 WINED3DRS_STENCILPASS ,
6010 WINED3DRS_STENCILREF ,
6011 WINED3DRS_STENCILWRITEMASK ,
6012 WINED3DRS_STENCILZFAIL ,
6013 WINED3DRS_TEXTUREFACTOR ,
6014 WINED3DRS_WRAP0 ,
6015 WINED3DRS_WRAP1 ,
6016 WINED3DRS_WRAP2 ,
6017 WINED3DRS_WRAP3 ,
6018 WINED3DRS_WRAP4 ,
6019 WINED3DRS_WRAP5 ,
6020 WINED3DRS_WRAP6 ,
6021 WINED3DRS_WRAP7 ,
6022 WINED3DRS_ZENABLE ,
6023 WINED3DRS_ZFUNC ,
6024 WINED3DRS_ZWRITEENABLE
6027 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6028 WINED3DTSS_ADDRESSW ,
6029 WINED3DTSS_ALPHAARG0 ,
6030 WINED3DTSS_ALPHAARG1 ,
6031 WINED3DTSS_ALPHAARG2 ,
6032 WINED3DTSS_ALPHAOP ,
6033 WINED3DTSS_BUMPENVLOFFSET ,
6034 WINED3DTSS_BUMPENVLSCALE ,
6035 WINED3DTSS_BUMPENVMAT00 ,
6036 WINED3DTSS_BUMPENVMAT01 ,
6037 WINED3DTSS_BUMPENVMAT10 ,
6038 WINED3DTSS_BUMPENVMAT11 ,
6039 WINED3DTSS_COLORARG0 ,
6040 WINED3DTSS_COLORARG1 ,
6041 WINED3DTSS_COLORARG2 ,
6042 WINED3DTSS_COLOROP ,
6043 WINED3DTSS_RESULTARG ,
6044 WINED3DTSS_TEXCOORDINDEX ,
6045 WINED3DTSS_TEXTURETRANSFORMFLAGS
6048 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6049 WINED3DSAMP_ADDRESSU ,
6050 WINED3DSAMP_ADDRESSV ,
6051 WINED3DSAMP_ADDRESSW ,
6052 WINED3DSAMP_BORDERCOLOR ,
6053 WINED3DSAMP_MAGFILTER ,
6054 WINED3DSAMP_MINFILTER ,
6055 WINED3DSAMP_MIPFILTER ,
6056 WINED3DSAMP_MIPMAPLODBIAS ,
6057 WINED3DSAMP_MAXMIPLEVEL ,
6058 WINED3DSAMP_MAXANISOTROPY ,
6059 WINED3DSAMP_SRGBTEXTURE ,
6060 WINED3DSAMP_ELEMENTINDEX
6063 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6064 WINED3DRS_AMBIENT ,
6065 WINED3DRS_AMBIENTMATERIALSOURCE ,
6066 WINED3DRS_CLIPPING ,
6067 WINED3DRS_CLIPPLANEENABLE ,
6068 WINED3DRS_COLORVERTEX ,
6069 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6070 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6071 WINED3DRS_FOGDENSITY ,
6072 WINED3DRS_FOGEND ,
6073 WINED3DRS_FOGSTART ,
6074 WINED3DRS_FOGTABLEMODE ,
6075 WINED3DRS_FOGVERTEXMODE ,
6076 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6077 WINED3DRS_LIGHTING ,
6078 WINED3DRS_LOCALVIEWER ,
6079 WINED3DRS_MULTISAMPLEANTIALIAS ,
6080 WINED3DRS_MULTISAMPLEMASK ,
6081 WINED3DRS_NORMALIZENORMALS ,
6082 WINED3DRS_PATCHEDGESTYLE ,
6083 WINED3DRS_POINTSCALE_A ,
6084 WINED3DRS_POINTSCALE_B ,
6085 WINED3DRS_POINTSCALE_C ,
6086 WINED3DRS_POINTSCALEENABLE ,
6087 WINED3DRS_POINTSIZE ,
6088 WINED3DRS_POINTSIZE_MAX ,
6089 WINED3DRS_POINTSIZE_MIN ,
6090 WINED3DRS_POINTSPRITEENABLE ,
6091 WINED3DRS_RANGEFOGENABLE ,
6092 WINED3DRS_SPECULARMATERIALSOURCE ,
6093 WINED3DRS_TWEENFACTOR ,
6094 WINED3DRS_VERTEXBLEND
6097 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6098 WINED3DTSS_TEXCOORDINDEX ,
6099 WINED3DTSS_TEXTURETRANSFORMFLAGS
6102 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6103 WINED3DSAMP_DMAPOFFSET
6106 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6107 DWORD rep = StateTable[state].representative;
6108 DWORD idx;
6109 BYTE shift;
6110 UINT i;
6111 WineD3DContext *context;
6113 if(!rep) return;
6114 for(i = 0; i < This->numContexts; i++) {
6115 context = This->contexts[i];
6116 if(isStateDirty(context, rep)) continue;
6118 context->dirtyArray[context->numDirtyEntries++] = rep;
6119 idx = rep >> 5;
6120 shift = rep & 0x1f;
6121 context->isStateDirty[idx] |= (1 << shift);