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
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 */
48 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
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 inline static Display *get_display( HDC hdc )
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;
73 /* allocate one pbuffer per surface */
74 BOOL pbuffer_per_surface = FALSE;
76 /* static function declarations */
77 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
79 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
82 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
84 #define D3DCREATEOBJECTINSTANCE(object, type) { \
85 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
86 D3DMEMCHECK(object, pp##type); \
87 object->lpVtbl = &IWineD3D##type##_Vtbl; \
88 object->wineD3DDevice = This; \
89 object->parent = parent; \
91 *pp##type = (IWineD3D##type *) object; \
94 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
95 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
96 D3DMEMCHECK(object, pp##type); \
97 object->lpVtbl = &IWineD3D##type##_Vtbl; \
98 object->parent = parent; \
100 object->baseShader.device = (IWineD3DDevice*) This; \
101 list_init(&object->baseShader.linked_programs); \
102 *pp##type = (IWineD3D##type *) object; \
105 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
106 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
107 D3DMEMCHECK(object, pp##type); \
108 object->lpVtbl = &IWineD3D##type##_Vtbl; \
109 object->resource.wineD3DDevice = This; \
110 object->resource.parent = parent; \
111 object->resource.resourceType = d3dtype; \
112 object->resource.ref = 1; \
113 object->resource.pool = Pool; \
114 object->resource.format = Format; \
115 object->resource.usage = Usage; \
116 object->resource.size = _size; \
117 /* Check that we have enough video ram left */ \
118 if (Pool == WINED3DPOOL_DEFAULT) { \
119 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
120 WARN("Out of 'bogus' video memory\n"); \
121 HeapFree(GetProcessHeap(), 0, object); \
123 return WINED3DERR_OUTOFVIDEOMEMORY; \
125 globalChangeGlRam(_size); \
127 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
128 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
129 FIXME("Out of memory!\n"); \
130 HeapFree(GetProcessHeap(), 0, object); \
132 return WINED3DERR_OUTOFVIDEOMEMORY; \
134 *pp##type = (IWineD3D##type *) object; \
135 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
136 TRACE("(%p) : Created resource %p\n", This, object); \
139 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
140 _basetexture.levels = Levels; \
141 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
142 _basetexture.LOD = 0; \
143 _basetexture.dirty = TRUE; \
146 /**********************************************************
147 * Global variable / Constants follow
148 **********************************************************/
149 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
151 /**********************************************************
152 * IUnknown parts follows
153 **********************************************************/
155 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
159 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
160 if (IsEqualGUID(riid, &IID_IUnknown)
161 || IsEqualGUID(riid, &IID_IWineD3DBase)
162 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
163 IUnknown_AddRef(iface);
168 return E_NOINTERFACE;
171 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
173 ULONG refCount = InterlockedIncrement(&This->ref);
175 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
179 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
181 ULONG refCount = InterlockedDecrement(&This->ref);
183 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
187 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
190 HeapFree(GetProcessHeap(), 0, This->render_targets);
192 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
194 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
196 /* TODO: Clean up all the surfaces and textures! */
197 /* NOTE: You must release the parent if the object was created via a callback
198 ** ***************************/
200 /* Release the update stateblock */
201 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
202 if(This->updateStateBlock != This->stateBlock)
203 FIXME("(%p) Something's still holding the Update stateblock\n",This);
205 This->updateStateBlock = NULL;
206 { /* because were not doing proper internal refcounts releasing the primary state block
207 causes recursion with the extra checks in ResourceReleased, to avoid this we have
208 to set this->stateBlock = NULL; first */
209 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
210 This->stateBlock = NULL;
212 /* Release the stateblock */
213 if(IWineD3DStateBlock_Release(stateBlock) > 0){
214 FIXME("(%p) Something's still holding the Update stateblock\n",This);
218 if (This->resources != NULL ) {
219 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
220 dumpResources(This->resources);
223 if(This->contexts) ERR("Context array not freed!\n");
225 IWineD3D_Release(This->wineD3D);
226 This->wineD3D = NULL;
227 HeapFree(GetProcessHeap(), 0, This);
228 TRACE("Freed device %p\n", This);
234 /**********************************************************
235 * IWineD3DDevice implementation follows
236 **********************************************************/
237 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
239 *pParent = This->parent;
240 IUnknown_AddRef(This->parent);
244 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
245 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
246 GLenum error, glUsage;
247 DWORD vboUsage = object->resource.usage;
248 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
249 WARN("Creating a vbo failed once, not trying again\n");
253 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
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);
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);
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;
294 case WINED3DUSAGE_WRITEONLY:
296 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
297 glUsage = GL_DYNAMIC_DRAW_ARB;
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);
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));
320 object->Flags |= VBFLAG_VBOCREATEFAIL;
325 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
326 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
329 IWineD3DVertexBufferImpl *object;
330 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
331 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
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);
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
362 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
363 * more. In this call we can convert dx7 buffers too.
365 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
366 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
367 (dxVersion > 7 || !conv) ) {
373 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
374 GLenum error, glUsage;
375 TRACE("Creating VBO for Index Buffer %p\n", object);
377 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
378 * restored on the next draw
380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
385 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
386 error = glGetError();
387 if(error != GL_NO_ERROR || object->vbo == 0) {
388 ERR("Creating a vbo failed, continueing without vbo for this buffer\n");
392 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
393 error = glGetError();
394 if(error != GL_NO_ERROR) {
395 ERR("Failed to bind index buffer, continueing without vbo for this buffer\n");
399 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
400 * copy no readback will be needed
402 glUsage = GL_STATIC_DRAW_ARB;
403 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
404 error = glGetError();
405 if(error != GL_NO_ERROR) {
406 ERR("Failed to initialize the index buffer\n");
410 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
414 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
415 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
420 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
421 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
422 HANDLE *sharedHandle, IUnknown *parent) {
423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
424 IWineD3DIndexBufferImpl *object;
425 TRACE("(%p) Creating index buffer\n", This);
427 /* Allocate the storage for the device */
428 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
430 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
431 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
434 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
435 CreateIndexBufferVBO(This, object);
438 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
439 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
440 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
445 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
448 IWineD3DStateBlockImpl *object;
452 D3DCREATEOBJECTINSTANCE(object, StateBlock)
453 object->blockType = Type;
455 for(i = 0; i < LIGHTMAP_SIZE; i++) {
456 list_init(&object->lightMap[i]);
459 /* Special case - Used during initialization to produce a placeholder stateblock
460 so other functions called can update a state block */
461 if (Type == WINED3DSBT_INIT) {
462 /* Don't bother increasing the reference count otherwise a device will never
463 be freed due to circular dependencies */
467 temp_result = allocate_shader_constants(object);
468 if (WINED3D_OK != temp_result)
471 /* Otherwise, might as well set the whole state block to the appropriate values */
472 if (This->stateBlock != NULL)
473 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
475 memset(object->streamFreq, 1, sizeof(object->streamFreq));
477 /* Reset the ref and type after kludging it */
478 object->wineD3DDevice = This;
480 object->blockType = Type;
482 TRACE("Updating changed flags appropriate for type %d\n", Type);
484 if (Type == WINED3DSBT_ALL) {
486 TRACE("ALL => Pretend everything has changed\n");
487 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
489 /* Lights are not part of the changed / set structure */
490 for(j = 0; j < LIGHTMAP_SIZE; j++) {
492 LIST_FOR_EACH(e, &object->lightMap[j]) {
493 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
494 light->changed = TRUE;
495 light->enabledChanged = TRUE;
498 } else if (Type == WINED3DSBT_PIXELSTATE) {
500 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
501 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
503 object->changed.pixelShader = TRUE;
505 /* Pixel Shader Constants */
506 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
507 object->changed.pixelShaderConstantsF[i] = TRUE;
508 for (i = 0; i < MAX_CONST_B; ++i)
509 object->changed.pixelShaderConstantsB[i] = TRUE;
510 for (i = 0; i < MAX_CONST_I; ++i)
511 object->changed.pixelShaderConstantsI[i] = TRUE;
513 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
514 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
516 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
517 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
518 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
521 for (j = 0 ; j < 16; j++) {
522 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
524 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
528 } else if (Type == WINED3DSBT_VERTEXSTATE) {
530 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
531 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
533 object->changed.vertexShader = TRUE;
535 /* Vertex Shader Constants */
536 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
537 object->changed.vertexShaderConstantsF[i] = TRUE;
538 for (i = 0; i < MAX_CONST_B; ++i)
539 object->changed.vertexShaderConstantsB[i] = TRUE;
540 for (i = 0; i < MAX_CONST_I; ++i)
541 object->changed.vertexShaderConstantsI[i] = TRUE;
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
544 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
546 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
547 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
548 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
551 for (j = 0 ; j < 16; j++){
552 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
553 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 FIXME("Unrecognized state block type %d\n", Type);
569 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
574 /* ************************************
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 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.
583 ******************************** */
585 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) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int pow2Width, pow2Height;
589 unsigned int Size = 1;
590 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
591 TRACE("(%p) Create surface\n",This);
593 /** FIXME: Check ranges on the inputs are valid
596 * [in] Quality level. The valid range is between zero and one less than the level
597 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
598 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
599 * values of paired render targets, depth stencil surfaces, and the MultiSample type
601 *******************************/
606 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
608 * If this flag is set, the contents of the depth stencil buffer will be
609 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
610 * with a different depth surface.
612 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
613 ***************************/
615 if(MultisampleQuality < 0) {
616 FIXME("Invalid multisample level %d\n", MultisampleQuality);
617 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
620 if(MultisampleQuality > 0) {
621 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
622 MultisampleQuality=0;
625 /** FIXME: Check that the format is supported
627 *******************************/
629 /* Non-power2 support */
630 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
634 /* Find the nearest pow2 match */
635 pow2Width = pow2Height = 1;
636 while (pow2Width < Width) pow2Width <<= 1;
637 while (pow2Height < Height) pow2Height <<= 1;
640 if (pow2Width > Width || pow2Height > Height) {
641 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
642 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
643 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
644 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
645 This, Width, Height);
646 return WINED3DERR_NOTAVAILABLE;
650 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
651 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
653 *********************************/
654 if (WINED3DFMT_UNKNOWN == Format) {
656 } else if (Format == WINED3DFMT_DXT1) {
657 /* DXT1 is half byte per pixel */
658 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
660 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
661 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
662 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
664 /* The pitch is a multiple of 4 bytes */
665 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
669 /** Create and initialise the surface resource **/
670 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
671 /* "Standalone" surface */
672 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
674 object->currentDesc.Width = Width;
675 object->currentDesc.Height = Height;
676 object->currentDesc.MultiSampleType = MultiSample;
677 object->currentDesc.MultiSampleQuality = MultisampleQuality;
679 /* Setup some glformat defaults */
680 object->glDescription.glFormat = tableEntry->glFormat;
681 object->glDescription.glFormatInternal = tableEntry->glInternal;
682 object->glDescription.glType = tableEntry->glType;
684 object->glDescription.textureName = 0;
685 object->glDescription.level = Level;
686 object->glDescription.target = GL_TEXTURE_2D;
689 object->pow2Width = pow2Width;
690 object->pow2Height = pow2Height;
693 object->Flags = 0; /* We start without flags set */
694 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
695 object->Flags |= Discard ? SFLAG_DISCARD : 0;
696 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
697 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
700 if (WINED3DFMT_UNKNOWN != Format) {
701 object->bytesPerPixel = tableEntry->bpp;
703 object->bytesPerPixel = 0;
706 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
708 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
710 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
711 * this function is too deep to need to care about things like this.
712 * Levels need to be checked too, and possibly Type since they all affect what can be done.
713 * ****************************************/
715 case WINED3DPOOL_SCRATCH:
717 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
718 "which are mutually exclusive, setting lockable to TRUE\n");
721 case WINED3DPOOL_SYSTEMMEM:
722 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
723 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
724 case WINED3DPOOL_MANAGED:
725 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
726 "Usage of DYNAMIC which are mutually exclusive, not doing "
727 "anything just telling you.\n");
729 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
730 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
731 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
732 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
735 FIXME("(%p) Unknown pool %d\n", This, Pool);
739 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
740 FIXME("Trying to create a render target that isn't in the default pool\n");
743 /* mark the texture as dirty so that it gets loaded first time around*/
744 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
745 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
746 This, Width, Height, Format, debug_d3dformat(Format),
747 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
749 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
750 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
751 This->ddraw_primary = (IWineD3DSurface *) object;
753 /* Look at the implementation and set the correct Vtable */
756 /* Nothing to do, it's set already */
760 object->lpVtbl = &IWineGDISurface_Vtbl;
764 /* To be sure to catch this */
765 ERR("Unknown requested surface implementation %d!\n", Impl);
766 IWineD3DSurface_Release((IWineD3DSurface *) object);
767 return WINED3DERR_INVALIDCALL;
770 /* Call the private setup routine */
771 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
775 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
776 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
777 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
778 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
781 IWineD3DTextureImpl *object;
786 unsigned int pow2Width;
787 unsigned int pow2Height;
790 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
791 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
792 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
794 /* TODO: It should only be possible to create textures for formats
795 that are reported as supported */
796 if (WINED3DFMT_UNKNOWN >= Format) {
797 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
798 return WINED3DERR_INVALIDCALL;
801 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
802 D3DINITIALIZEBASETEXTURE(object->baseTexture);
803 object->width = Width;
804 object->height = Height;
806 /** Non-power2 support **/
807 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
811 /* Find the nearest pow2 match */
812 pow2Width = pow2Height = 1;
813 while (pow2Width < Width) pow2Width <<= 1;
814 while (pow2Height < Height) pow2Height <<= 1;
817 /** FIXME: add support for real non-power-two if it's provided by the video card **/
818 /* Precalculated scaling for 'faked' non power of two texture coords */
819 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
820 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
821 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
823 /* Calculate levels for mip mapping */
825 TRACE("calculating levels %d\n", object->baseTexture.levels);
826 object->baseTexture.levels++;
829 while (tmpW > 1 || tmpH > 1) {
830 tmpW = max(1, tmpW >> 1);
831 tmpH = max(1, tmpH >> 1);
832 object->baseTexture.levels++;
834 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
837 /* Generate all the surfaces */
840 for (i = 0; i < object->baseTexture.levels; i++)
842 /* use the callback to create the texture surface */
843 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
844 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
845 FIXME("Failed to create surface %p\n", object);
847 object->surfaces[i] = NULL;
848 IWineD3DTexture_Release((IWineD3DTexture *)object);
854 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
855 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
856 /* calculate the next mipmap level */
857 tmpW = max(1, tmpW >> 1);
858 tmpH = max(1, tmpH >> 1);
861 TRACE("(%p) : Created texture %p\n", This, object);
865 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
866 UINT Width, UINT Height, UINT Depth,
867 UINT Levels, DWORD Usage,
868 WINED3DFORMAT Format, WINED3DPOOL Pool,
869 IWineD3DVolumeTexture **ppVolumeTexture,
870 HANDLE *pSharedHandle, IUnknown *parent,
871 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
874 IWineD3DVolumeTextureImpl *object;
880 /* TODO: It should only be possible to create textures for formats
881 that are reported as supported */
882 if (WINED3DFMT_UNKNOWN >= Format) {
883 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
884 return WINED3DERR_INVALIDCALL;
887 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
888 D3DINITIALIZEBASETEXTURE(object->baseTexture);
890 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
891 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
893 object->width = Width;
894 object->height = Height;
895 object->depth = Depth;
897 /* Calculate levels for mip mapping */
899 object->baseTexture.levels++;
903 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
904 tmpW = max(1, tmpW >> 1);
905 tmpH = max(1, tmpH >> 1);
906 tmpD = max(1, tmpD >> 1);
907 object->baseTexture.levels++;
909 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
912 /* Generate all the surfaces */
917 for (i = 0; i < object->baseTexture.levels; i++)
920 /* Create the volume */
921 hr = D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
922 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
925 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
926 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
927 *ppVolumeTexture = NULL;
931 /* Set its container to this object */
932 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
934 /* calcualte the next mipmap level */
935 tmpW = max(1, tmpW >> 1);
936 tmpH = max(1, tmpH >> 1);
937 tmpD = max(1, tmpD >> 1);
940 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
941 TRACE("(%p) : Created volume texture %p\n", This, object);
945 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
946 UINT Width, UINT Height, UINT Depth,
948 WINED3DFORMAT Format, WINED3DPOOL Pool,
949 IWineD3DVolume** ppVolume,
950 HANDLE* pSharedHandle, IUnknown *parent) {
952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
953 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
954 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
956 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
958 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
959 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
961 object->currentDesc.Width = Width;
962 object->currentDesc.Height = Height;
963 object->currentDesc.Depth = Depth;
964 object->bytesPerPixel = formatDesc->bpp;
966 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
967 object->lockable = TRUE;
968 object->locked = FALSE;
969 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
970 object->dirty = TRUE;
972 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
975 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
976 UINT Levels, DWORD Usage,
977 WINED3DFORMAT Format, WINED3DPOOL Pool,
978 IWineD3DCubeTexture **ppCubeTexture,
979 HANDLE *pSharedHandle, IUnknown *parent,
980 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
983 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
987 unsigned int pow2EdgeLength = EdgeLength;
989 /* TODO: It should only be possible to create textures for formats
990 that are reported as supported */
991 if (WINED3DFMT_UNKNOWN >= Format) {
992 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
993 return WINED3DERR_INVALIDCALL;
996 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
997 D3DINITIALIZEBASETEXTURE(object->baseTexture);
999 TRACE("(%p) Create Cube Texture\n", This);
1001 /** Non-power2 support **/
1003 /* Find the nearest pow2 match */
1005 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1007 object->edgeLength = EdgeLength;
1008 /* TODO: support for native non-power 2 */
1009 /* Precalculated scaling for 'faked' non power of two texture coords */
1010 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1012 /* Calculate levels for mip mapping */
1014 object->baseTexture.levels++;
1017 tmpW = max(1, tmpW >> 1);
1018 object->baseTexture.levels++;
1020 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1023 /* Generate all the surfaces */
1025 for (i = 0; i < object->baseTexture.levels; i++) {
1027 /* Create the 6 faces */
1028 for (j = 0; j < 6; j++) {
1030 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1031 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1033 if(hr!= WINED3D_OK) {
1037 for (l = 0; l < j; l++) {
1038 IWineD3DSurface_Release(object->surfaces[j][i]);
1040 for (k = 0; k < i; k++) {
1041 for (l = 0; l < 6; l++) {
1042 IWineD3DSurface_Release(object->surfaces[l][j]);
1046 FIXME("(%p) Failed to create surface\n",object);
1047 HeapFree(GetProcessHeap(),0,object);
1048 *ppCubeTexture = NULL;
1051 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1052 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1054 tmpW = max(1, tmpW >> 1);
1057 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1058 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1062 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1064 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1065 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1067 /* Just a check to see if we support this type of query */
1069 case WINED3DQUERYTYPE_OCCLUSION:
1070 TRACE("(%p) occlusion query\n", This);
1071 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1074 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1077 case WINED3DQUERYTYPE_EVENT:
1078 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1079 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1080 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1082 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1087 case WINED3DQUERYTYPE_VCACHE:
1088 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1089 case WINED3DQUERYTYPE_VERTEXSTATS:
1090 case WINED3DQUERYTYPE_TIMESTAMP:
1091 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1092 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1093 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1094 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1095 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1096 case WINED3DQUERYTYPE_PIXELTIMINGS:
1097 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1098 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1100 FIXME("(%p) Unhandled query type %d\n", This, Type);
1102 if(NULL == ppQuery || hr != WINED3D_OK) {
1106 D3DCREATEOBJECTINSTANCE(object, Query)
1107 object->type = Type;
1108 /* allocated the 'extended' data based on the type of query requested */
1110 case WINED3DQUERYTYPE_OCCLUSION:
1111 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1112 TRACE("(%p) Allocating data for an occlusion query\n", This);
1113 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1114 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1117 case WINED3DQUERYTYPE_EVENT:
1118 /* TODO: GL_APPLE_fence */
1119 if(GL_SUPPORT(APPLE_FENCE)) {
1120 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1121 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1122 checkGLcall("glGenFencesAPPLE");
1123 } else if(GL_SUPPORT(NV_FENCE)) {
1124 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1125 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1126 checkGLcall("glGenFencesNV");
1130 case WINED3DQUERYTYPE_VCACHE:
1131 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1132 case WINED3DQUERYTYPE_VERTEXSTATS:
1133 case WINED3DQUERYTYPE_TIMESTAMP:
1134 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1135 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1136 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1137 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1138 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1139 case WINED3DQUERYTYPE_PIXELTIMINGS:
1140 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1141 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1143 object->extendedData = 0;
1144 FIXME("(%p) Unhandled query type %d\n",This , Type);
1146 TRACE("(%p) : Created Query %p\n", This, object);
1150 /*****************************************************************************
1151 * IWineD3DDeviceImpl_SetupFullscreenWindow
1153 * Helper function that modifies a HWND's Style and ExStyle for proper
1157 * iface: Pointer to the IWineD3DDevice interface
1158 * window: Window to setup
1160 *****************************************************************************/
1161 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1164 LONG style, exStyle;
1165 /* Don't do anything if an original style is stored.
1166 * That shouldn't happen
1168 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1169 if (This->style || This->exStyle) {
1170 ERR("(%p): Want to change the window parameters of HWND %p, but "
1171 "another style is stored for restoration afterwards\n", This, window);
1174 /* Get the parameters and save them */
1175 style = GetWindowLongW(window, GWL_STYLE);
1176 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1177 This->style = style;
1178 This->exStyle = exStyle;
1180 /* Filter out window decorations */
1181 style &= ~WS_CAPTION;
1182 style &= ~WS_THICKFRAME;
1183 exStyle &= ~WS_EX_WINDOWEDGE;
1184 exStyle &= ~WS_EX_CLIENTEDGE;
1186 /* Make sure the window is managed, otherwise we won't get keyboard input */
1187 style |= WS_POPUP | WS_SYSMENU;
1189 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1190 This->style, This->exStyle, style, exStyle);
1192 SetWindowLongW(window, GWL_STYLE, style);
1193 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1195 /* Inform the window about the update. */
1196 SetWindowPos(window, HWND_TOP, 0, 0,
1197 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1198 ShowWindow(window, SW_NORMAL);
1201 /*****************************************************************************
1202 * IWineD3DDeviceImpl_RestoreWindow
1204 * Helper function that restores a windows' properties when taking it out
1205 * of fullscreen mode
1208 * iface: Pointer to the IWineD3DDevice interface
1209 * window: Window to setup
1211 *****************************************************************************/
1212 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1215 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1216 * switch, do nothing
1218 if (!This->style && !This->exStyle) return;
1220 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1221 This, window, This->style, This->exStyle);
1223 SetWindowLongW(window, GWL_STYLE, This->style);
1224 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1226 /* Delete the old values */
1230 /* Inform the window about the update */
1231 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1232 0, 0, 0, 0, /* Pos, Size, ignored */
1233 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1236 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1237 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1239 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1240 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1244 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1245 HRESULT hr = WINED3D_OK;
1246 IUnknown *bufferParent;
1249 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1251 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1252 * does a device hold a reference to a swap chain giving them a lifetime of the device
1253 * or does the swap chain notify the device of its destruction.
1254 *******************************/
1256 /* Check the params */
1257 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1258 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1259 return WINED3DERR_INVALIDCALL;
1260 } else if (pPresentationParameters->BackBufferCount > 1) {
1261 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");
1264 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1266 /*********************
1267 * Lookup the window Handle and the relating X window handle
1268 ********************/
1270 /* Setup hwnd we are using, plus which display this equates to */
1271 object->win_handle = pPresentationParameters->hDeviceWindow;
1272 if (!object->win_handle) {
1273 object->win_handle = This->createParms.hFocusWindow;
1276 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1277 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1278 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1279 return WINED3DERR_NOTAVAILABLE;
1281 hDc = GetDC(object->win_handle);
1282 display = get_display(hDc);
1283 ReleaseDC(object->win_handle, hDc);
1284 TRACE("Using a display of %p %p\n", display, hDc);
1286 if (NULL == display || NULL == hDc) {
1287 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1288 return WINED3DERR_NOTAVAILABLE;
1291 if (object->win == 0) {
1292 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1293 return WINED3DERR_NOTAVAILABLE;
1296 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1297 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1298 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1300 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1301 * then the corresponding dimension of the client area of the hDeviceWindow
1302 * (or the focus window, if hDeviceWindow is NULL) is taken.
1303 **********************/
1305 if (pPresentationParameters->Windowed &&
1306 ((pPresentationParameters->BackBufferWidth == 0) ||
1307 (pPresentationParameters->BackBufferHeight == 0))) {
1310 GetClientRect(object->win_handle, &Rect);
1312 if (pPresentationParameters->BackBufferWidth == 0) {
1313 pPresentationParameters->BackBufferWidth = Rect.right;
1314 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1316 if (pPresentationParameters->BackBufferHeight == 0) {
1317 pPresentationParameters->BackBufferHeight = Rect.bottom;
1318 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1322 /* Put the correct figures in the presentation parameters */
1323 TRACE("Copying across presentation parameters\n");
1324 object->presentParms = *pPresentationParameters;
1326 TRACE("calling rendertarget CB\n");
1327 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1329 object->presentParms.BackBufferWidth,
1330 object->presentParms.BackBufferHeight,
1331 object->presentParms.BackBufferFormat,
1332 object->presentParms.MultiSampleType,
1333 object->presentParms.MultiSampleQuality,
1334 TRUE /* Lockable */,
1335 &object->frontBuffer,
1336 NULL /* pShared (always null)*/);
1337 if (object->frontBuffer != NULL) {
1338 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1340 ERR("Failed to create the front buffer\n");
1345 * Create an opengl context for the display visual
1346 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1347 * use different properties after that point in time. FIXME: How to handle when requested format
1348 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1349 * it chooses is identical to the one already being used!
1350 **********************************/
1352 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1354 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1357 if (!object->context) {
1358 ERR("Failed to create a new context\n");
1359 hr = WINED3DERR_NOTAVAILABLE;
1362 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1363 object->win_handle, object->context->glCtx, object->win);
1366 /*********************
1367 * Windowed / Fullscreen
1368 *******************/
1371 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1372 * so we should really check to see if there is a fullscreen swapchain already
1373 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1374 **************************************/
1376 if (!pPresentationParameters->Windowed) {
1383 /* Get info on the current display setup */
1385 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1388 /* Change the display settings */
1389 memset(&devmode, 0, sizeof(DEVMODEW));
1390 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1391 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1392 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1393 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1394 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1395 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1397 /* For GetDisplayMode */
1398 This->ddraw_width = devmode.dmPelsWidth;
1399 This->ddraw_height = devmode.dmPelsHeight;
1400 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1402 IWineD3DDevice_SetFullscreen(iface, TRUE);
1404 /* And finally clip mouse to our screen */
1405 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1406 ClipCursor(&clip_rc);
1409 /*********************
1410 * Create the back, front and stencil buffers
1411 *******************/
1412 if(object->presentParms.BackBufferCount > 0) {
1415 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1416 if(!object->backBuffer) {
1417 ERR("Out of memory\n");
1422 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1423 TRACE("calling rendertarget CB\n");
1424 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1426 object->presentParms.BackBufferWidth,
1427 object->presentParms.BackBufferHeight,
1428 object->presentParms.BackBufferFormat,
1429 object->presentParms.MultiSampleType,
1430 object->presentParms.MultiSampleQuality,
1431 TRUE /* Lockable */,
1432 &object->backBuffer[i],
1433 NULL /* pShared (always null)*/);
1434 if(hr == WINED3D_OK && object->backBuffer[i]) {
1435 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1437 ERR("Cannot create new back buffer\n");
1441 glDrawBuffer(GL_BACK);
1442 checkGLcall("glDrawBuffer(GL_BACK)");
1446 object->backBuffer = NULL;
1448 /* Single buffering - draw to front buffer */
1450 glDrawBuffer(GL_FRONT);
1451 checkGLcall("glDrawBuffer(GL_FRONT)");
1455 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1456 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1457 TRACE("Creating depth stencil buffer\n");
1458 if (This->depthStencilBuffer == NULL ) {
1459 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1461 object->presentParms.BackBufferWidth,
1462 object->presentParms.BackBufferHeight,
1463 object->presentParms.AutoDepthStencilFormat,
1464 object->presentParms.MultiSampleType,
1465 object->presentParms.MultiSampleQuality,
1466 FALSE /* FIXME: Discard */,
1467 &This->depthStencilBuffer,
1468 NULL /* pShared (always null)*/ );
1469 if (This->depthStencilBuffer != NULL)
1470 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1473 /** TODO: A check on width, height and multisample types
1474 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1475 ****************************/
1476 object->wantsDepthStencilBuffer = TRUE;
1478 object->wantsDepthStencilBuffer = FALSE;
1481 TRACE("Created swapchain %p\n", object);
1482 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1486 if (object->backBuffer) {
1488 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1489 if(object->backBuffer[i]) {
1490 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1491 IUnknown_Release(bufferParent); /* once for the get parent */
1492 if (IUnknown_Release(bufferParent) > 0) {
1493 FIXME("(%p) Something's still holding the back buffer\n",This);
1497 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1498 object->backBuffer = NULL;
1500 if(object->context) {
1501 DestroyContext(This, object->context);
1503 if(object->frontBuffer) {
1504 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1505 IUnknown_Release(bufferParent); /* once for the get parent */
1506 if (IUnknown_Release(bufferParent) > 0) {
1507 FIXME("(%p) Something's still holding the front buffer\n",This);
1510 HeapFree(GetProcessHeap(), 0, object);
1514 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1515 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1517 TRACE("(%p)\n", This);
1519 return This->NumberOfSwapChains;
1522 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1524 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1526 if(iSwapChain < This->NumberOfSwapChains) {
1527 *pSwapChain = This->swapchains[iSwapChain];
1528 IWineD3DSwapChain_AddRef(*pSwapChain);
1529 TRACE("(%p) returning %p\n", This, *pSwapChain);
1532 TRACE("Swapchain out of range\n");
1534 return WINED3DERR_INVALIDCALL;
1539 * Vertex Declaration
1541 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1542 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 IWineD3DVertexDeclarationImpl *object = NULL;
1545 HRESULT hr = WINED3D_OK;
1547 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1548 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1550 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1553 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1558 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1559 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1561 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1562 HRESULT hr = WINED3D_OK;
1563 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1564 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1566 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1568 if (vertex_declaration) {
1569 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1572 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1574 if (WINED3D_OK != hr) {
1575 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1576 IWineD3DVertexShader_Release(*ppVertexShader);
1577 return WINED3DERR_INVALIDCALL;
1583 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1585 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1586 HRESULT hr = WINED3D_OK;
1588 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1589 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1590 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1591 if (WINED3D_OK == hr) {
1592 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1594 WARN("(%p) : Failed to create pixel shader\n", This);
1600 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1602 IWineD3DPaletteImpl *object;
1604 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1606 /* Create the new object */
1607 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1609 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1610 return E_OUTOFMEMORY;
1613 object->lpVtbl = &IWineD3DPalette_Vtbl;
1615 object->Flags = Flags;
1616 object->parent = Parent;
1617 object->wineD3DDevice = This;
1618 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1620 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1623 HeapFree( GetProcessHeap(), 0, object);
1624 return E_OUTOFMEMORY;
1627 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1629 IWineD3DPalette_Release((IWineD3DPalette *) object);
1633 *Palette = (IWineD3DPalette *) object;
1638 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1640 IWineD3DSwapChainImpl *swapchain;
1643 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1644 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1646 /* TODO: Test if OpenGL is compiled in and loaded */
1648 /* Initialize the texture unit mapping to a 1:1 mapping */
1649 for(state = 0; state < MAX_SAMPLERS; state++) {
1650 This->texUnitMap[state] = state;
1652 This->oneToOneTexUnitMap = TRUE;
1654 /* Setup the implicit swapchain */
1655 TRACE("Creating implicit swapchain\n");
1656 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1657 WARN("Failed to create implicit swapchain\n");
1658 return WINED3DERR_INVALIDCALL;
1661 This->NumberOfSwapChains = 1;
1662 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1663 if(!This->swapchains) {
1664 ERR("Out of memory!\n");
1665 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1666 return E_OUTOFMEMORY;
1668 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1670 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1672 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1673 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1674 This->render_targets[0] = swapchain->backBuffer[0];
1675 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1678 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1679 This->render_targets[0] = swapchain->frontBuffer;
1680 This->lastActiveRenderTarget = swapchain->frontBuffer;
1682 IWineD3DSurface_AddRef(This->render_targets[0]);
1683 This->activeContext = swapchain->context;
1685 /* Depth Stencil support */
1686 This->stencilBufferTarget = This->depthStencilBuffer;
1687 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1688 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1690 if (NULL != This->stencilBufferTarget) {
1691 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1694 /* Set up some starting GL setup */
1697 * Initialize openGL extension related variables
1698 * with Default values
1701 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1702 /* Setup all the devices defaults */
1703 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1705 IWineD3DImpl_CheckGraphicsMemory();
1708 { /* Set a default viewport */
1712 vp.Width = pPresentationParameters->BackBufferWidth;
1713 vp.Height = pPresentationParameters->BackBufferHeight;
1716 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1719 /* Initialize the current view state */
1720 This->view_ident = 1;
1721 This->contexts[0]->last_was_rhw = 0;
1722 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1723 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1725 switch(wined3d_settings.offscreen_rendering_mode) {
1728 This->offscreenBuffer = GL_BACK;
1731 case ORM_BACKBUFFER:
1733 if(GL_LIMITS(aux_buffers) > 0) {
1734 TRACE("Using auxilliary buffer for offscreen rendering\n");
1735 This->offscreenBuffer = GL_AUX0;
1737 TRACE("Using back buffer for offscreen rendering\n");
1738 This->offscreenBuffer = GL_BACK;
1743 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1746 /* Clear the screen */
1747 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1748 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1751 This->d3d_initialized = TRUE;
1755 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1759 TRACE("(%p)\n", This);
1761 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1763 /* Delete the pbuffer context if there is any */
1764 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1766 /* Delete the mouse cursor texture */
1767 if(This->cursorTexture) {
1769 glDeleteTextures(1, &This->cursorTexture);
1771 This->cursorTexture = 0;
1774 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1775 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1778 /* Release the buffers (with sanity checks)*/
1779 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1780 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1781 if(This->depthStencilBuffer != This->stencilBufferTarget)
1782 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1784 This->stencilBufferTarget = NULL;
1786 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1787 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1788 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1790 TRACE("Setting rendertarget to NULL\n");
1791 This->render_targets[0] = NULL;
1793 if (This->depthStencilBuffer) {
1794 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1795 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1797 This->depthStencilBuffer = NULL;
1800 for(i=0; i < This->NumberOfSwapChains; i++) {
1801 TRACE("Releasing the implicit swapchain %d\n", i);
1802 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1803 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1807 HeapFree(GetProcessHeap(), 0, This->swapchains);
1808 This->swapchains = NULL;
1809 This->NumberOfSwapChains = 0;
1811 This->d3d_initialized = FALSE;
1815 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1817 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1819 /* Setup the window for fullscreen mode */
1820 if(fullscreen && !This->ddraw_fullscreen) {
1821 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1822 } else if(!fullscreen && This->ddraw_fullscreen) {
1823 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1826 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1827 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1828 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1831 This->ddraw_fullscreen = fullscreen;
1834 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1836 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1838 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1841 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1843 /* Resize the screen even without a window:
1844 * The app could have unset it with SetCooperativeLevel, but not called
1845 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1846 * but we don't have any hwnd
1849 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1850 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1851 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1852 devmode.dmPelsWidth = pMode->Width;
1853 devmode.dmPelsHeight = pMode->Height;
1855 devmode.dmDisplayFrequency = pMode->RefreshRate;
1856 if (pMode->RefreshRate != 0) {
1857 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1860 /* Only change the mode if necessary */
1861 if( (This->ddraw_width == pMode->Width) &&
1862 (This->ddraw_height == pMode->Height) &&
1863 (This->ddraw_format == pMode->Format) &&
1864 (pMode->RefreshRate == 0) ) {
1868 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1869 if (ret != DISP_CHANGE_SUCCESSFUL) {
1870 if(devmode.dmDisplayFrequency != 0) {
1871 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1872 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1873 devmode.dmDisplayFrequency = 0;
1874 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1876 if(ret != DISP_CHANGE_SUCCESSFUL) {
1877 return DDERR_INVALIDMODE;
1881 /* Store the new values */
1882 This->ddraw_width = pMode->Width;
1883 This->ddraw_height = pMode->Height;
1884 This->ddraw_format = pMode->Format;
1886 /* Only do this with a window of course */
1887 if(This->ddraw_window)
1888 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1890 /* And finally clip mouse to our screen */
1891 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1892 ClipCursor(&clip_rc);
1897 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1899 *ppD3D= This->wineD3D;
1900 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1901 IWineD3D_AddRef(*ppD3D);
1905 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1906 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1907 * into the video ram as possible and seeing how many fit
1908 * you can also get the correct initial value from nvidia and ATI's driver via X
1909 * texture memory is video memory + AGP memory
1910 *******************/
1911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1912 static BOOL showfixmes = TRUE;
1914 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1915 (wined3d_settings.emulated_textureram/(1024*1024)),
1916 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1919 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1920 (wined3d_settings.emulated_textureram/(1024*1024)),
1921 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1922 /* return simulated texture memory left */
1923 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1931 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1934 /* Update the current state block */
1935 This->updateStateBlock->changed.fvf = TRUE;
1936 This->updateStateBlock->set.fvf = TRUE;
1938 if(This->updateStateBlock->fvf == fvf) {
1939 TRACE("Application is setting the old fvf over, nothing to do\n");
1943 This->updateStateBlock->fvf = fvf;
1944 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1950 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1952 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1953 *pfvf = This->stateBlock->fvf;
1958 * Get / Set Stream Source
1960 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1962 IWineD3DVertexBuffer *oldSrc;
1964 if (StreamNumber >= MAX_STREAMS) {
1965 WARN("Stream out of range %d\n", StreamNumber);
1966 return WINED3DERR_INVALIDCALL;
1969 oldSrc = This->stateBlock->streamSource[StreamNumber];
1970 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1972 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1973 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1975 if(oldSrc == pStreamData &&
1976 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1977 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1978 TRACE("Application is setting the old values over, nothing to do\n");
1982 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1984 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1985 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1988 /* Handle recording of state blocks */
1989 if (This->isRecordingState) {
1990 TRACE("Recording... not performing anything\n");
1994 /* Need to do a getParent and pass the reffs up */
1995 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
1996 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
1997 so for now, just count internally */
1998 if (pStreamData != NULL) {
1999 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2000 InterlockedIncrement(&vbImpl->bindCount);
2002 if (oldSrc != NULL) {
2003 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2011 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2014 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2015 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2017 if (StreamNumber >= MAX_STREAMS) {
2018 WARN("Stream out of range %d\n", StreamNumber);
2019 return WINED3DERR_INVALIDCALL;
2021 *pStream = This->stateBlock->streamSource[StreamNumber];
2022 *pStride = This->stateBlock->streamStride[StreamNumber];
2024 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2027 if (*pStream != NULL) {
2028 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2033 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2035 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2036 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2038 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2039 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2041 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2042 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2043 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2045 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2046 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2047 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2053 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2056 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2057 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2059 TRACE("(%p) : returning %d\n", This, *Divider);
2065 * Get / Set & Multiply Transform
2067 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2070 /* Most of this routine, comments included copied from ddraw tree initially: */
2071 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2073 /* Handle recording of state blocks */
2074 if (This->isRecordingState) {
2075 TRACE("Recording... not performing anything\n");
2076 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2077 This->updateStateBlock->set.transform[d3dts] = TRUE;
2078 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2083 * If the new matrix is the same as the current one,
2084 * we cut off any further processing. this seems to be a reasonable
2085 * optimization because as was noticed, some apps (warcraft3 for example)
2086 * tend towards setting the same matrix repeatedly for some reason.
2088 * From here on we assume that the new matrix is different, wherever it matters.
2090 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2091 TRACE("The app is setting the same matrix over again\n");
2094 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2098 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2099 where ViewMat = Camera space, WorldMat = world space.
2101 In OpenGL, camera and world space is combined into GL_MODELVIEW
2102 matrix. The Projection matrix stay projection matrix.
2105 /* Capture the times we can just ignore the change for now */
2106 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2107 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2108 /* Handled by the state manager */
2111 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2115 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2117 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2118 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2122 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2123 WINED3DMATRIX *mat = NULL;
2126 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2127 * below means it will be recorded in a state block change, but it
2128 * works regardless where it is recorded.
2129 * If this is found to be wrong, change to StateBlock.
2131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2132 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2134 if (State < HIGHEST_TRANSFORMSTATE)
2136 mat = &This->updateStateBlock->transforms[State];
2138 FIXME("Unhandled transform state!!\n");
2141 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2143 /* Apply change via set transform - will reapply to eg. lights this way */
2144 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2150 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2151 you can reference any indexes you want as long as that number max are enabled at any
2152 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2153 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2154 but when recording, just build a chain pretty much of commands to be replayed. */
2156 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2158 PLIGHTINFOEL *object = NULL;
2159 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2163 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2165 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2169 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2170 return WINED3DERR_INVALIDCALL;
2173 switch(pLight->Type) {
2174 case WINED3DLIGHT_POINT:
2175 case WINED3DLIGHT_SPOT:
2176 case WINED3DLIGHT_PARALLELPOINT:
2177 case WINED3DLIGHT_GLSPOT:
2178 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2181 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2182 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2183 return WINED3DERR_INVALIDCALL;
2187 case WINED3DLIGHT_DIRECTIONAL:
2188 /* Ignores attenuation */
2192 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2193 return WINED3DERR_INVALIDCALL;
2196 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2197 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2198 if(object->OriginalIndex == Index) break;
2203 TRACE("Adding new light\n");
2204 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2206 ERR("Out of memory error when allocating a light\n");
2207 return E_OUTOFMEMORY;
2209 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2210 object->glIndex = -1;
2211 object->OriginalIndex = Index;
2212 object->changed = TRUE;
2215 /* Initialize the object */
2216 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,
2217 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2218 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2219 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2220 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2221 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2222 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2224 /* Save away the information */
2225 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2227 switch (pLight->Type) {
2228 case WINED3DLIGHT_POINT:
2230 object->lightPosn[0] = pLight->Position.x;
2231 object->lightPosn[1] = pLight->Position.y;
2232 object->lightPosn[2] = pLight->Position.z;
2233 object->lightPosn[3] = 1.0f;
2234 object->cutoff = 180.0f;
2238 case WINED3DLIGHT_DIRECTIONAL:
2240 object->lightPosn[0] = -pLight->Direction.x;
2241 object->lightPosn[1] = -pLight->Direction.y;
2242 object->lightPosn[2] = -pLight->Direction.z;
2243 object->lightPosn[3] = 0.0;
2244 object->exponent = 0.0f;
2245 object->cutoff = 180.0f;
2248 case WINED3DLIGHT_SPOT:
2250 object->lightPosn[0] = pLight->Position.x;
2251 object->lightPosn[1] = pLight->Position.y;
2252 object->lightPosn[2] = pLight->Position.z;
2253 object->lightPosn[3] = 1.0;
2256 object->lightDirn[0] = pLight->Direction.x;
2257 object->lightDirn[1] = pLight->Direction.y;
2258 object->lightDirn[2] = pLight->Direction.z;
2259 object->lightDirn[3] = 1.0;
2262 * opengl-ish and d3d-ish spot lights use too different models for the
2263 * light "intensity" as a function of the angle towards the main light direction,
2264 * so we only can approximate very roughly.
2265 * however spot lights are rather rarely used in games (if ever used at all).
2266 * furthermore if still used, probably nobody pays attention to such details.
2268 if (pLight->Falloff == 0) {
2271 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2273 if (rho < 0.0001) rho = 0.0001f;
2274 object->exponent = -0.3/log(cos(rho/2));
2275 if (object->exponent > 128.0) {
2276 object->exponent = 128.0;
2278 object->cutoff = pLight->Phi*90/M_PI;
2284 FIXME("Unrecognized light type %d\n", pLight->Type);
2287 /* Update the live definitions if the light is currently assigned a glIndex */
2288 if (object->glIndex != -1 && !This->isRecordingState) {
2289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2294 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2295 PLIGHTINFOEL *lightInfo = NULL;
2296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2297 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2299 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2301 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2302 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2303 if(lightInfo->OriginalIndex == Index) break;
2307 if (lightInfo == NULL) {
2308 TRACE("Light information requested but light not defined\n");
2309 return WINED3DERR_INVALIDCALL;
2312 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2317 * Get / Set Light Enable
2318 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2320 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2321 PLIGHTINFOEL *lightInfo = NULL;
2322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2323 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2325 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2327 /* Tests show true = 128...not clear why */
2328 Enable = Enable? 128: 0;
2330 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2331 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2332 if(lightInfo->OriginalIndex == Index) break;
2335 TRACE("Found light: %p\n", lightInfo);
2337 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2338 if (lightInfo == NULL) {
2340 TRACE("Light enabled requested but light not defined, so defining one!\n");
2341 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2343 /* Search for it again! Should be fairly quick as near head of list */
2344 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2345 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2346 if(lightInfo->OriginalIndex == Index) break;
2349 if (lightInfo == NULL) {
2350 FIXME("Adding default lights has failed dismally\n");
2351 return WINED3DERR_INVALIDCALL;
2355 lightInfo->enabledChanged = TRUE;
2357 if(lightInfo->glIndex != -1) {
2358 if(!This->isRecordingState) {
2359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2362 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2363 lightInfo->glIndex = -1;
2365 TRACE("Light already disabled, nothing to do\n");
2368 if (lightInfo->glIndex != -1) {
2370 TRACE("Nothing to do as light was enabled\n");
2373 /* Find a free gl light */
2374 for(i = 0; i < This->maxConcurrentLights; i++) {
2375 if(This->stateBlock->activeLights[i] == NULL) {
2376 This->stateBlock->activeLights[i] = lightInfo;
2377 lightInfo->glIndex = i;
2381 if(lightInfo->glIndex == -1) {
2382 ERR("Too many concurrently active lights\n");
2383 return WINED3DERR_INVALIDCALL;
2386 /* i == lightInfo->glIndex */
2387 if(!This->isRecordingState) {
2388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2396 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2398 PLIGHTINFOEL *lightInfo = NULL;
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2401 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2402 TRACE("(%p) : for idx(%d)\n", This, Index);
2404 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2405 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2406 if(lightInfo->OriginalIndex == Index) break;
2410 if (lightInfo == NULL) {
2411 TRACE("Light enabled state requested but light not defined\n");
2412 return WINED3DERR_INVALIDCALL;
2414 /* true is 128 according to SetLightEnable */
2415 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2420 * Get / Set Clip Planes
2422 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2424 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2426 /* Validate Index */
2427 if (Index >= GL_LIMITS(clipplanes)) {
2428 TRACE("Application has requested clipplane this device doesn't support\n");
2429 return WINED3DERR_INVALIDCALL;
2432 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2433 This->updateStateBlock->set.clipplane[Index] = TRUE;
2435 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2436 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2437 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2438 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2439 TRACE("Application is setting old values over, nothing to do\n");
2443 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2444 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2445 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2446 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2448 /* Handle recording of state blocks */
2449 if (This->isRecordingState) {
2450 TRACE("Recording... not performing anything\n");
2454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2459 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 TRACE("(%p) : for idx %d\n", This, Index);
2463 /* Validate Index */
2464 if (Index >= GL_LIMITS(clipplanes)) {
2465 TRACE("Application has requested clipplane this device doesn't support\n");
2466 return WINED3DERR_INVALIDCALL;
2469 pPlane[0] = This->stateBlock->clipplane[Index][0];
2470 pPlane[1] = This->stateBlock->clipplane[Index][1];
2471 pPlane[2] = This->stateBlock->clipplane[Index][2];
2472 pPlane[3] = This->stateBlock->clipplane[Index][3];
2477 * Get / Set Clip Plane Status
2478 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2480 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 FIXME("(%p) : stub\n", This);
2483 if (NULL == pClipStatus) {
2484 return WINED3DERR_INVALIDCALL;
2486 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2487 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2491 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2493 FIXME("(%p) : stub\n", This);
2494 if (NULL == pClipStatus) {
2495 return WINED3DERR_INVALIDCALL;
2497 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2498 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2503 * Get / Set Material
2505 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2508 This->updateStateBlock->changed.material = TRUE;
2509 This->updateStateBlock->set.material = TRUE;
2510 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2512 /* Handle recording of state blocks */
2513 if (This->isRecordingState) {
2514 TRACE("Recording... not performing anything\n");
2519 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2520 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2521 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2522 pMaterial->Ambient.b, pMaterial->Ambient.a);
2523 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2524 pMaterial->Specular.b, pMaterial->Specular.a);
2525 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2526 pMaterial->Emissive.b, pMaterial->Emissive.a);
2527 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2529 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2530 checkGLcall("glMaterialfv(GL_AMBIENT)");
2531 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2532 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2534 /* Only change material color if specular is enabled, otherwise it is set to black */
2535 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2536 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2537 checkGLcall("glMaterialfv(GL_SPECULAR");
2539 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2540 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2541 checkGLcall("glMaterialfv(GL_SPECULAR");
2543 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2544 checkGLcall("glMaterialfv(GL_EMISSION)");
2545 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2546 checkGLcall("glMaterialf(GL_SHININESS");
2552 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2555 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2556 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2557 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2558 pMaterial->Ambient.b, pMaterial->Ambient.a);
2559 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2560 pMaterial->Specular.b, pMaterial->Specular.a);
2561 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2562 pMaterial->Emissive.b, pMaterial->Emissive.a);
2563 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2571 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2572 UINT BaseVertexIndex) {
2573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2574 IWineD3DIndexBuffer *oldIdxs;
2575 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2577 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2578 oldIdxs = This->updateStateBlock->pIndexData;
2580 This->updateStateBlock->changed.indices = TRUE;
2581 This->updateStateBlock->set.indices = TRUE;
2582 This->updateStateBlock->pIndexData = pIndexData;
2583 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2585 /* Handle recording of state blocks */
2586 if (This->isRecordingState) {
2587 TRACE("Recording... not performing anything\n");
2591 /* The base vertex index affects the stream sources, while
2592 * The index buffer is a seperate index buffer state
2594 if(BaseVertexIndex != oldBaseIndex) {
2595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2597 if(oldIdxs != pIndexData) {
2598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2603 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2606 *ppIndexData = This->stateBlock->pIndexData;
2608 /* up ref count on ppindexdata */
2610 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2611 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2612 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2614 TRACE("(%p) No index data set\n", This);
2616 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2621 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2622 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2624 TRACE("(%p)->(%d)\n", This, BaseIndex);
2626 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2627 TRACE("Application is setting the old value over, nothing to do\n");
2631 This->updateStateBlock->baseVertexIndex = BaseIndex;
2633 if (This->isRecordingState) {
2634 TRACE("Recording... not performing anything\n");
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2642 * Get / Set Viewports
2644 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2647 TRACE("(%p)\n", This);
2648 This->updateStateBlock->changed.viewport = TRUE;
2649 This->updateStateBlock->set.viewport = TRUE;
2650 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2652 /* Handle recording of state blocks */
2653 if (This->isRecordingState) {
2654 TRACE("Recording... not performing anything\n");
2658 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2659 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2666 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2668 TRACE("(%p)\n", This);
2669 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2674 * Get / Set Render States
2675 * TODO: Verify against dx9 definitions
2677 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2680 DWORD oldValue = This->stateBlock->renderState[State];
2682 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2684 This->updateStateBlock->changed.renderState[State] = TRUE;
2685 This->updateStateBlock->set.renderState[State] = TRUE;
2686 This->updateStateBlock->renderState[State] = Value;
2688 /* Handle recording of state blocks */
2689 if (This->isRecordingState) {
2690 TRACE("Recording... not performing anything\n");
2694 /* Compared here and not before the assignment to allow proper stateblock recording */
2695 if(Value == oldValue) {
2696 TRACE("Application is setting the old value over, nothing to do\n");
2698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2704 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2706 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2707 *pValue = This->stateBlock->renderState[State];
2712 * Get / Set Sampler States
2713 * TODO: Verify against dx9 definitions
2716 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2718 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2721 * SetSampler is designed to allow for more than the standard up to 8 textures
2722 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2723 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2725 * http://developer.nvidia.com/object/General_FAQ.html#t6
2727 * There are two new settings for GForce
2729 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2730 * and the texture one:
2731 * GL_MAX_TEXTURE_COORDS_ARB.
2732 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2735 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2736 debug_d3dsamplerstate(Type), Type, Value);
2737 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2738 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2739 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2741 /* Handle recording of state blocks */
2742 if (This->isRecordingState) {
2743 TRACE("Recording... not performing anything\n");
2747 if(oldValue == Value) {
2748 TRACE("Application is setting the old value over, nothing to do\n");
2752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2757 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2759 *Value = This->stateBlock->samplerState[Sampler][Type];
2760 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2765 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 This->updateStateBlock->set.scissorRect = TRUE;
2769 This->updateStateBlock->changed.scissorRect = TRUE;
2770 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2771 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2774 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2776 if(This->isRecordingState) {
2777 TRACE("Recording... not performing anything\n");
2781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2786 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2790 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2796 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2798 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2800 This->updateStateBlock->vertexDecl = pDecl;
2801 This->updateStateBlock->changed.vertexDecl = TRUE;
2802 This->updateStateBlock->set.vertexDecl = TRUE;
2804 if (This->isRecordingState) {
2805 TRACE("Recording... not performing anything\n");
2807 } else if(pDecl == oldDecl) {
2808 /* Checked after the assignment to allow proper stateblock recording */
2809 TRACE("Application is setting the old declaration over, nothing to do\n");
2813 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2817 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2820 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2822 *ppDecl = This->stateBlock->vertexDecl;
2823 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2827 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2829 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2831 This->updateStateBlock->vertexShader = pShader;
2832 This->updateStateBlock->changed.vertexShader = TRUE;
2833 This->updateStateBlock->set.vertexShader = TRUE;
2835 if (This->isRecordingState) {
2836 TRACE("Recording... not performing anything\n");
2838 } else if(oldShader == pShader) {
2839 /* Checked here to allow proper stateblock recording */
2840 TRACE("App is setting the old shader over, nothing to do\n");
2844 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2851 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2854 if (NULL == ppShader) {
2855 return WINED3DERR_INVALIDCALL;
2857 *ppShader = This->stateBlock->vertexShader;
2858 if( NULL != *ppShader)
2859 IWineD3DVertexShader_AddRef(*ppShader);
2861 TRACE("(%p) : returning %p\n", This, *ppShader);
2865 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2866 IWineD3DDevice *iface,
2868 CONST BOOL *srcData,
2871 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2872 int i, cnt = min(count, MAX_CONST_B - start);
2874 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2875 iface, srcData, start, count);
2877 if (srcData == NULL || cnt < 0)
2878 return WINED3DERR_INVALIDCALL;
2880 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2881 for (i = 0; i < cnt; i++)
2882 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2884 for (i = start; i < cnt + start; ++i) {
2885 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2886 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2889 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2894 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2895 IWineD3DDevice *iface,
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 int cnt = min(count, MAX_CONST_B - start);
2903 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2904 iface, dstData, start, count);
2906 if (dstData == NULL || cnt < 0)
2907 return WINED3DERR_INVALIDCALL;
2909 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2913 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2914 IWineD3DDevice *iface,
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 int i, cnt = min(count, MAX_CONST_I - start);
2922 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2923 iface, srcData, start, count);
2925 if (srcData == NULL || cnt < 0)
2926 return WINED3DERR_INVALIDCALL;
2928 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2929 for (i = 0; i < cnt; i++)
2930 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2931 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2933 for (i = start; i < cnt + start; ++i) {
2934 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2935 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2938 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2943 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2944 IWineD3DDevice *iface,
2949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2950 int cnt = min(count, MAX_CONST_I - start);
2952 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2953 iface, dstData, start, count);
2955 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2956 return WINED3DERR_INVALIDCALL;
2958 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2962 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2963 IWineD3DDevice *iface,
2965 CONST float *srcData,
2968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2971 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2972 iface, srcData, start, count);
2974 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
2975 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
2976 return WINED3DERR_INVALIDCALL;
2978 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
2980 for (i = 0; i < count; i++)
2981 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
2982 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2985 for (i = start; i < count + start; ++i) {
2986 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
2987 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
2988 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
2989 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
2990 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
2992 ptr->idx[ptr->count++] = i;
2993 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
2995 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
2998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3003 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3004 IWineD3DDevice *iface,
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3012 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3013 iface, dstData, start, count);
3015 if (dstData == NULL || cnt < 0)
3016 return WINED3DERR_INVALIDCALL;
3018 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3022 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3024 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3029 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3031 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3032 * it is never called.
3035 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3036 * that would be really messy and require shader recompilation
3037 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3038 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3039 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3040 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3042 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3043 if(This->oneToOneTexUnitMap) {
3044 TRACE("Not touching 1:1 map\n");
3047 TRACE("Restoring 1:1 texture unit mapping\n");
3048 /* Restore a 1:1 mapping */
3049 for(i = 0; i < MAX_SAMPLERS; i++) {
3050 if(This->texUnitMap[i] != i) {
3051 This->texUnitMap[i] = i;
3052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3053 markTextureStagesDirty(This, i);
3056 This->oneToOneTexUnitMap = TRUE;
3059 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3060 * First, see if we can succeed at all
3063 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3064 if(This->stateBlock->textures[i] == NULL) tex++;
3067 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3068 FIXME("Too many bound textures to support the combiner settings\n");
3072 /* Now work out the mapping */
3074 This->oneToOneTexUnitMap = FALSE;
3075 WARN("Non 1:1 mapping UNTESTED!\n");
3076 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3077 /* Skip NULL textures */
3078 if (!This->stateBlock->textures[i]) {
3079 /* Map to -1, so the check below doesn't fail if a non-NULL
3080 * texture is set on this stage */
3081 TRACE("Mapping texture stage %d to -1\n", i);
3082 This->texUnitMap[i] = -1;
3087 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3088 if(This->texUnitMap[i] != tex) {
3089 This->texUnitMap[i] = tex;
3090 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3091 markTextureStagesDirty(This, i);
3099 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3102 This->updateStateBlock->pixelShader = pShader;
3103 This->updateStateBlock->changed.pixelShader = TRUE;
3104 This->updateStateBlock->set.pixelShader = TRUE;
3106 /* Handle recording of state blocks */
3107 if (This->isRecordingState) {
3108 TRACE("Recording... not performing anything\n");
3111 if (This->isRecordingState) {
3112 TRACE("Recording... not performing anything\n");
3116 if(pShader == oldShader) {
3117 TRACE("App is setting the old pixel shader over, nothing to do\n");
3121 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3124 /* Rebuild the texture unit mapping if nvrc's are supported */
3125 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3126 IWineD3DDeviceImpl_FindTexUnitMap(This);
3132 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 if (NULL == ppShader) {
3136 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3137 return WINED3DERR_INVALIDCALL;
3140 *ppShader = This->stateBlock->pixelShader;
3141 if (NULL != *ppShader) {
3142 IWineD3DPixelShader_AddRef(*ppShader);
3144 TRACE("(%p) : returning %p\n", This, *ppShader);
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3149 IWineD3DDevice *iface,
3151 CONST BOOL *srcData,
3154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3155 int i, cnt = min(count, MAX_CONST_B - start);
3157 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3158 iface, srcData, start, count);
3160 if (srcData == NULL || cnt < 0)
3161 return WINED3DERR_INVALIDCALL;
3163 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3164 for (i = 0; i < cnt; i++)
3165 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3167 for (i = start; i < cnt + start; ++i) {
3168 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3169 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3177 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3178 IWineD3DDevice *iface,
3183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 int cnt = min(count, MAX_CONST_B - start);
3186 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3187 iface, dstData, start, count);
3189 if (dstData == NULL || cnt < 0)
3190 return WINED3DERR_INVALIDCALL;
3192 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3196 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3197 IWineD3DDevice *iface,
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3203 int i, cnt = min(count, MAX_CONST_I - start);
3205 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3206 iface, srcData, start, count);
3208 if (srcData == NULL || cnt < 0)
3209 return WINED3DERR_INVALIDCALL;
3211 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3212 for (i = 0; i < cnt; i++)
3213 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3214 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3216 for (i = start; i < cnt + start; ++i) {
3217 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3218 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3227 IWineD3DDevice *iface,
3232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 int cnt = min(count, MAX_CONST_I - start);
3235 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3236 iface, dstData, start, count);
3238 if (dstData == NULL || cnt < 0)
3239 return WINED3DERR_INVALIDCALL;
3241 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3246 IWineD3DDevice *iface,
3248 CONST float *srcData,
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3254 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3255 iface, srcData, start, count);
3257 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3258 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3259 return WINED3DERR_INVALIDCALL;
3261 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3263 for (i = 0; i < count; i++)
3264 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3265 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3268 for (i = start; i < count + start; ++i) {
3269 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3270 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3271 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3272 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3273 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3275 ptr->idx[ptr->count++] = i;
3276 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3278 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3286 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3287 IWineD3DDevice *iface,
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3295 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3296 iface, dstData, start, count);
3298 if (dstData == NULL || cnt < 0)
3299 return WINED3DERR_INVALIDCALL;
3301 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3305 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3307 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3308 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3310 DWORD DestFVF = dest->fvf;
3312 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3316 if (SrcFVF & WINED3DFVF_NORMAL) {
3317 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3320 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3321 ERR("Source has no position mask\n");
3322 return WINED3DERR_INVALIDCALL;
3325 /* We might access VBOs from this code, so hold the lock */
3328 if (dest->resource.allocatedMemory == NULL) {
3329 /* This may happen if we do direct locking into a vbo. Unlikely,
3330 * but theoretically possible(ddraw processvertices test)
3332 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3333 if(!dest->resource.allocatedMemory) {
3335 ERR("Out of memory\n");
3336 return E_OUTOFMEMORY;
3340 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3341 checkGLcall("glBindBufferARB");
3342 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3344 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3346 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3347 checkGLcall("glUnmapBufferARB");
3351 /* Get a pointer into the destination vbo(create one if none exists) and
3352 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3354 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3359 dest_conv_addr = HeapAlloc(GetProcessHeap(), 0, dwCount * get_flexible_vertex_size(DestFVF));
3360 if(!dest_conv_addr) {
3361 ERR("Out of memory\n");
3362 /* Continue without storing converted vertices */
3364 dest_conv = dest_conv_addr;
3368 * a) WINED3DRS_CLIPPING is enabled
3369 * b) WINED3DVOP_CLIP is passed
3371 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3372 static BOOL warned = FALSE;
3374 * The clipping code is not quite correct. Some things need
3375 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3376 * so disable clipping for now.
3377 * (The graphics in Half-Life are broken, and my processvertices
3378 * test crashes with IDirect3DDevice3)
3384 FIXME("Clipping is broken and disabled for now\n");
3386 } else doClip = FALSE;
3387 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3389 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3392 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3393 WINED3DTS_PROJECTION,
3395 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3396 WINED3DTS_WORLDMATRIX(0),
3399 TRACE("View mat:\n");
3400 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);
3401 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);
3402 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);
3403 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);
3405 TRACE("Proj mat:\n");
3406 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);
3407 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);
3408 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);
3409 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);
3411 TRACE("World mat:\n");
3412 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);
3413 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);
3414 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);
3415 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);
3417 /* Get the viewport */
3418 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3419 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3420 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3422 multiply_matrix(&mat,&view_mat,&world_mat);
3423 multiply_matrix(&mat,&proj_mat,&mat);
3425 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3427 for (i = 0; i < dwCount; i+= 1) {
3428 unsigned int tex_index;
3430 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3431 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3432 /* The position first */
3434 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3436 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3438 /* Multiplication with world, view and projection matrix */
3439 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);
3440 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);
3441 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);
3442 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);
3444 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3446 /* WARNING: The following things are taken from d3d7 and were not yet checked
3447 * against d3d8 or d3d9!
3450 /* Clipping conditions: From
3451 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3453 * A vertex is clipped if it does not match the following requirements
3457 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3459 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3460 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3465 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3466 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3469 /* "Normal" viewport transformation (not clipped)
3470 * 1) The values are divided by rhw
3471 * 2) The y axis is negative, so multiply it with -1
3472 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3473 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3474 * 4) Multiply x with Width/2 and add Width/2
3475 * 5) The same for the height
3476 * 6) Add the viewpoint X and Y to the 2D coordinates and
3477 * The minimum Z value to z
3478 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3480 * Well, basically it's simply a linear transformation into viewport
3492 z *= vp.MaxZ - vp.MinZ;
3494 x += vp.Width / 2 + vp.X;
3495 y += vp.Height / 2 + vp.Y;
3500 /* That vertex got clipped
3501 * Contrary to OpenGL it is not dropped completely, it just
3502 * undergoes a different calculation.
3504 TRACE("Vertex got clipped\n");
3511 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3512 * outside of the main vertex buffer memory. That needs some more
3517 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3520 ( (float *) dest_ptr)[0] = x;
3521 ( (float *) dest_ptr)[1] = y;
3522 ( (float *) dest_ptr)[2] = z;
3523 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3525 dest_ptr += 3 * sizeof(float);
3527 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3528 dest_ptr += sizeof(float);
3533 ( (float *) dest_conv)[0] = x * w;
3534 ( (float *) dest_conv)[1] = y * w;
3535 ( (float *) dest_conv)[2] = z * w;
3536 ( (float *) dest_conv)[3] = w;
3538 dest_conv += 3 * sizeof(float);
3540 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3541 dest_conv += sizeof(float);
3545 if (DestFVF & WINED3DFVF_PSIZE) {
3546 dest_ptr += sizeof(DWORD);
3547 if(dest_conv) dest_conv += sizeof(DWORD);
3549 if (DestFVF & WINED3DFVF_NORMAL) {
3551 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3552 /* AFAIK this should go into the lighting information */
3553 FIXME("Didn't expect the destination to have a normal\n");
3554 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3556 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3560 if (DestFVF & WINED3DFVF_DIFFUSE) {
3562 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3564 static BOOL warned = FALSE;
3567 ERR("No diffuse color in source, but destination has one\n");
3571 *( (DWORD *) dest_ptr) = 0xffffffff;
3572 dest_ptr += sizeof(DWORD);
3575 *( (DWORD *) dest_conv) = 0xffffffff;
3576 dest_conv += sizeof(DWORD);
3580 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3582 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3583 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3584 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3585 dest_conv += sizeof(DWORD);
3590 if (DestFVF & WINED3DFVF_SPECULAR) {
3591 /* What's the color value in the feedback buffer? */
3593 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3595 static BOOL warned = FALSE;
3598 ERR("No specular color in source, but destination has one\n");
3602 *( (DWORD *) dest_ptr) = 0xFF000000;
3603 dest_ptr += sizeof(DWORD);
3606 *( (DWORD *) dest_conv) = 0xFF000000;
3607 dest_conv += sizeof(DWORD);
3611 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3613 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3614 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3615 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3616 dest_conv += sizeof(DWORD);
3621 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3623 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3624 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3626 ERR("No source texture, but destination requests one\n");
3627 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3628 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3631 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3633 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3640 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3641 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3642 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3643 dwCount * get_flexible_vertex_size(DestFVF),
3645 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3646 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3653 #undef copy_and_next
3655 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3657 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3658 WineDirect3DVertexStridedData strided;
3659 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3662 WARN("NULL source vertex buffer\n");
3663 return WINED3DERR_INVALIDCALL;
3665 /* We don't need the source vbo because this buffer is only used as
3666 * a source for ProcessVertices. Avoid wasting resources by converting the
3667 * buffer and loading the VBO
3670 TRACE("Releasing the source vbo, it won't be needed\n");
3672 if(!SrcImpl->resource.allocatedMemory) {
3673 /* Rescue the data from the buffer */
3675 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3676 if(!SrcImpl->resource.allocatedMemory) {
3677 ERR("Out of memory\n");
3678 return E_OUTOFMEMORY;
3682 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3683 checkGLcall("glBindBufferARB");
3685 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3687 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3690 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3691 checkGLcall("glUnmapBufferARB");
3696 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3697 checkGLcall("glBindBufferARB");
3698 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3699 checkGLcall("glDeleteBuffersARB");
3705 memset(&strided, 0, sizeof(strided));
3706 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3708 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3712 * Get / Set Texture Stage States
3713 * TODO: Verify against dx9 definitions
3715 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3717 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3719 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3721 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3723 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3724 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3725 This->updateStateBlock->textureState[Stage][Type] = Value;
3727 if (This->isRecordingState) {
3728 TRACE("Recording... not performing anything\n");
3732 /* Checked after the assignments to allow proper stateblock recording */
3733 if(oldValue == Value) {
3734 TRACE("App is setting the old value over, nothing to do\n");
3738 if(Stage > This->stateBlock->lowest_disabled_stage &&
3739 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3740 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3741 * Changes in other states are important on disabled stages too
3746 if(Type == WINED3DTSS_COLOROP) {
3749 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3750 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3751 * they have to be disabled
3753 * The current stage is dirtified below.
3755 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3756 TRACE("Additionally dirtifying stage %d\n", i);
3757 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3759 This->stateBlock->lowest_disabled_stage = Stage;
3760 TRACE("New lowest disabled: %d\n", Stage);
3761 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3762 /* Previously disabled stage enabled. Stages above it may need enabling
3763 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3764 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3766 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3769 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3770 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3773 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3776 This->stateBlock->lowest_disabled_stage = i;
3777 TRACE("New lowest disabled: %d\n", i);
3779 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3780 /* TODO: Built a stage -> texture unit mapping for register combiners */
3784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3786 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3787 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3788 * will call FindTexUnitMap too.
3790 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3791 IWineD3DDeviceImpl_FindTexUnitMap(This);
3796 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3798 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3799 *pValue = This->updateStateBlock->textureState[Stage][Type];
3806 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3809 IWineD3DBaseTexture *oldTexture;
3811 oldTexture = This->updateStateBlock->textures[Stage];
3812 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3814 #if 0 /* TODO: check so vertex textures */
3815 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3816 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3821 if(pTexture != NULL) {
3822 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3824 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3825 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3826 return WINED3DERR_INVALIDCALL;
3828 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3831 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3832 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3834 This->updateStateBlock->set.textures[Stage] = TRUE;
3835 This->updateStateBlock->changed.textures[Stage] = TRUE;
3836 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3837 This->updateStateBlock->textures[Stage] = pTexture;
3839 /* Handle recording of state blocks */
3840 if (This->isRecordingState) {
3841 TRACE("Recording... not performing anything\n");
3845 if(oldTexture == pTexture) {
3846 TRACE("App is setting the same texture again, nothing to do\n");
3850 /** NOTE: MSDN says that setTexture increases the reference count,
3851 * and the the application nust set the texture back to null (or have a leaky application),
3852 * This means we should pass the refcount up to the parent
3853 *******************************/
3854 if (NULL != This->updateStateBlock->textures[Stage]) {
3855 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3856 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3858 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3859 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3860 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3861 * so the COLOROP and ALPHAOP have to be dirtified.
3863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3864 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3866 if(bindCount == 1) {
3867 new->baseTexture.sampler = Stage;
3869 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3873 if (NULL != oldTexture) {
3874 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3875 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3877 IWineD3DBaseTexture_Release(oldTexture);
3878 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3883 if(bindCount && old->baseTexture.sampler == Stage) {
3885 /* Have to do a search for the other sampler(s) where the texture is bound to
3886 * Shouldn't happen as long as apps bind a texture only to one stage
3888 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3889 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3890 if(This->updateStateBlock->textures[i] == oldTexture) {
3891 old->baseTexture.sampler = i;
3898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3900 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3901 * pixel shader is used
3903 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3904 IWineD3DDeviceImpl_FindTexUnitMap(This);
3910 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3912 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3914 *ppTexture=This->stateBlock->textures[Stage];
3916 IWineD3DBaseTexture_AddRef(*ppTexture);
3924 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3925 IWineD3DSurface **ppBackBuffer) {
3926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3927 IWineD3DSwapChain *swapChain;
3930 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3932 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3933 if (hr == WINED3D_OK) {
3934 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3935 IWineD3DSwapChain_Release(swapChain);
3937 *ppBackBuffer = NULL;
3942 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3944 WARN("(%p) : stub, calling idirect3d for now\n", This);
3945 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3948 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 IWineD3DSwapChain *swapChain;
3953 if(iSwapChain > 0) {
3954 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3955 if (hr == WINED3D_OK) {
3956 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3957 IWineD3DSwapChain_Release(swapChain);
3959 FIXME("(%p) Error getting display mode\n", This);
3962 /* Don't read the real display mode,
3963 but return the stored mode instead. X11 can't change the color
3964 depth, and some apps are pretty angry if they SetDisplayMode from
3965 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3967 Also don't relay to the swapchain because with ddraw it's possible
3968 that there isn't a swapchain at all */
3969 pMode->Width = This->ddraw_width;
3970 pMode->Height = This->ddraw_height;
3971 pMode->Format = This->ddraw_format;
3972 pMode->RefreshRate = 0;
3979 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
3980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3981 TRACE("(%p)->(%p)\n", This, hWnd);
3983 if(This->ddraw_fullscreen) {
3984 if(This->ddraw_window && This->ddraw_window != hWnd) {
3985 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
3987 if(hWnd && This->ddraw_window != hWnd) {
3988 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
3992 This->ddraw_window = hWnd;
3996 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
3997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3998 TRACE("(%p)->(%p)\n", This, hWnd);
4000 *hWnd = This->ddraw_window;
4005 * Stateblock related functions
4008 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 IWineD3DStateBlockImpl *object;
4011 HRESULT temp_result;
4014 TRACE("(%p)\n", This);
4016 if (This->isRecordingState) {
4017 return WINED3DERR_INVALIDCALL;
4020 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4021 if (NULL == object ) {
4022 FIXME("(%p)Error allocating memory for stateblock\n", This);
4023 return E_OUTOFMEMORY;
4025 TRACE("(%p) created object %p\n", This, object);
4026 object->wineD3DDevice= This;
4027 /** FIXME: object->parent = parent; **/
4028 object->parent = NULL;
4029 object->blockType = WINED3DSBT_ALL;
4031 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4033 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4034 list_init(&object->lightMap[i]);
4037 temp_result = allocate_shader_constants(object);
4038 if (WINED3D_OK != temp_result)
4041 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4042 This->updateStateBlock = object;
4043 This->isRecordingState = TRUE;
4045 TRACE("(%p) recording stateblock %p\n",This , object);
4049 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4052 if (!This->isRecordingState) {
4053 FIXME("(%p) not recording! returning error\n", This);
4054 *ppStateBlock = NULL;
4055 return WINED3DERR_INVALIDCALL;
4058 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4059 This->isRecordingState = FALSE;
4060 This->updateStateBlock = This->stateBlock;
4061 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4062 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4063 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4068 * Scene related functions
4070 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4071 /* At the moment we have no need for any functionality at the beginning
4073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4074 TRACE("(%p)\n", This);
4077 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4078 return WINED3DERR_INVALIDCALL;
4080 This->inScene = TRUE;
4084 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4086 TRACE("(%p)\n", This);
4088 if(!This->inScene) {
4089 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4090 return WINED3DERR_INVALIDCALL;
4094 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4096 checkGLcall("glFlush");
4099 This->inScene = FALSE;
4103 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4104 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4105 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4107 IWineD3DSwapChain *swapChain = NULL;
4109 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4111 TRACE("(%p) Presenting the frame\n", This);
4113 for(i = 0 ; i < swapchains ; i ++) {
4115 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4116 TRACE("presentinng chain %d, %p\n", i, swapChain);
4117 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4118 IWineD3DSwapChain_Release(swapChain);
4124 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4125 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4128 GLbitfield glMask = 0;
4130 CONST WINED3DRECT* curRect;
4132 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4133 Count, pRects, Flags, Z, Stencil);
4135 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4136 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4137 /* TODO: What about depth stencil buffers without stencil bits? */
4138 return WINED3DERR_INVALIDCALL;
4143 glEnable(GL_SCISSOR_TEST);
4144 checkGLcall("glEnable GL_SCISSOR_TEST");
4145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4148 if (Count > 0 && pRects) {
4154 /* Only set the values up once, as they are not changing */
4155 if (Flags & WINED3DCLEAR_STENCIL) {
4156 glClearStencil(Stencil);
4157 checkGLcall("glClearStencil");
4158 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4159 glStencilMask(0xFFFFFFFF);
4162 if (Flags & WINED3DCLEAR_ZBUFFER) {
4163 glDepthMask(GL_TRUE);
4165 checkGLcall("glClearDepth");
4166 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4170 if (Flags & WINED3DCLEAR_TARGET) {
4171 TRACE("Clearing screen with glClear to color %x\n", Color);
4172 glClearColor(D3DCOLOR_R(Color),
4176 checkGLcall("glClearColor");
4178 /* Clear ALL colors! */
4179 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4180 glMask = glMask | GL_COLOR_BUFFER_BIT;
4184 glScissor(This->stateBlock->viewport.X,
4185 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4186 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4187 This->stateBlock->viewport.Width,
4188 This->stateBlock->viewport.Height);
4189 checkGLcall("glScissor");
4191 checkGLcall("glClear");
4193 /* Now process each rect in turn */
4194 for (i = 0; i < Count; i++) {
4195 /* Note gl uses lower left, width/height */
4196 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4197 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4198 curRect[i].x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2),
4199 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4201 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4202 * The rectangle is not cleared, no error is returned, but further rectanlges are
4203 * still cleared if they are valid
4205 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4206 TRACE("Rectangle with negative dimensions, ignoring\n");
4210 glScissor(curRect[i].x1, ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect[i].y2,
4211 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4212 checkGLcall("glScissor");
4215 checkGLcall("glClear");
4219 /* Restore the old values (why..?) */
4220 if (Flags & WINED3DCLEAR_STENCIL) {
4221 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4223 if (Flags & WINED3DCLEAR_TARGET) {
4224 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4225 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4226 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4227 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4228 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4233 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4234 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4236 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4237 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INTEXTURE;
4238 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~SFLAG_INSYSMEM;
4240 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_INDRAWABLE;
4241 ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4249 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4250 UINT PrimitiveCount) {
4252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4253 This->stateBlock->streamIsUP = FALSE;
4255 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4256 debug_d3dprimitivetype(PrimitiveType),
4257 StartVertex, PrimitiveCount);
4259 if(This->stateBlock->loadBaseVertexIndex != 0) {
4260 This->stateBlock->loadBaseVertexIndex = 0;
4261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4263 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4264 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4265 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4269 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4270 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4271 WINED3DPRIMITIVETYPE PrimitiveType,
4272 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4276 IWineD3DIndexBuffer *pIB;
4277 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4280 pIB = This->stateBlock->pIndexData;
4281 This->stateBlock->streamIsUP = FALSE;
4282 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4284 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4285 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4286 minIndex, NumVertices, startIndex, primCount);
4288 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4289 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4295 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4296 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4300 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4301 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4306 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4307 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4308 UINT VertexStreamZeroStride) {
4309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4311 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4312 debug_d3dprimitivetype(PrimitiveType),
4313 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4315 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4316 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4317 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4318 This->stateBlock->streamIsUP = TRUE;
4319 This->stateBlock->loadBaseVertexIndex = 0;
4321 /* TODO: Only mark dirty if drawing from a different UP address */
4322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4324 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4325 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4327 /* MSDN specifies stream zero settings must be set to NULL */
4328 This->stateBlock->streamStride[0] = 0;
4329 This->stateBlock->streamSource[0] = NULL;
4331 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4332 * the new stream sources or use UP drawing again
4337 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4338 UINT MinVertexIndex, UINT NumVertices,
4339 UINT PrimitiveCount, CONST void* pIndexData,
4340 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4341 UINT VertexStreamZeroStride) {
4343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4345 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4346 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4347 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4348 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4350 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4356 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4357 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4358 This->stateBlock->streamIsUP = TRUE;
4359 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4361 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4362 This->stateBlock->baseVertexIndex = 0;
4363 This->stateBlock->loadBaseVertexIndex = 0;
4364 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4368 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4370 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4371 This->stateBlock->streamSource[0] = NULL;
4372 This->stateBlock->streamStride[0] = 0;
4373 This->stateBlock->pIndexData = NULL;
4374 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4375 * SetStreamSource to specify a vertex buffer
4381 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4384 /* Mark the state dirty until we have nicer tracking
4385 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4390 This->stateBlock->baseVertexIndex = 0;
4391 This->up_strided = DrawPrimStrideData;
4392 This->stateBlock->streamIsUP = TRUE;
4393 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4394 This->up_strided = NULL;
4397 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4398 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4400 HRESULT hr = WINED3D_OK;
4401 WINED3DRESOURCETYPE sourceType;
4402 WINED3DRESOURCETYPE destinationType;
4405 /* TODO: think about moving the code into IWineD3DBaseTexture */
4407 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4409 /* verify that the source and destination textures aren't NULL */
4410 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4411 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4412 This, pSourceTexture, pDestinationTexture);
4413 hr = WINED3DERR_INVALIDCALL;
4416 if (pSourceTexture == pDestinationTexture) {
4417 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4418 This, pSourceTexture, pDestinationTexture);
4419 hr = WINED3DERR_INVALIDCALL;
4421 /* Verify that the source and destination textures are the same type */
4422 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4423 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4425 if (sourceType != destinationType) {
4426 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4428 hr = WINED3DERR_INVALIDCALL;
4431 /* check that both textures have the identical numbers of levels */
4432 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4433 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4434 hr = WINED3DERR_INVALIDCALL;
4437 if (WINED3D_OK == hr) {
4439 /* Make sure that the destination texture is loaded */
4440 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4442 /* Update every surface level of the texture */
4443 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4445 switch (sourceType) {
4446 case WINED3DRTYPE_TEXTURE:
4448 IWineD3DSurface *srcSurface;
4449 IWineD3DSurface *destSurface;
4451 for (i = 0 ; i < levels ; ++i) {
4452 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4453 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4454 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4455 IWineD3DSurface_Release(srcSurface);
4456 IWineD3DSurface_Release(destSurface);
4457 if (WINED3D_OK != hr) {
4458 WARN("(%p) : Call to update surface failed\n", This);
4464 case WINED3DRTYPE_CUBETEXTURE:
4466 IWineD3DSurface *srcSurface;
4467 IWineD3DSurface *destSurface;
4468 WINED3DCUBEMAP_FACES faceType;
4470 for (i = 0 ; i < levels ; ++i) {
4471 /* Update each cube face */
4472 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4473 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4474 if (WINED3D_OK != hr) {
4475 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4477 TRACE("Got srcSurface %p\n", srcSurface);
4479 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4480 if (WINED3D_OK != hr) {
4481 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4483 TRACE("Got desrSurface %p\n", destSurface);
4485 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4486 IWineD3DSurface_Release(srcSurface);
4487 IWineD3DSurface_Release(destSurface);
4488 if (WINED3D_OK != hr) {
4489 WARN("(%p) : Call to update surface failed\n", This);
4496 #if 0 /* TODO: Add support for volume textures */
4497 case WINED3DRTYPE_VOLUMETEXTURE:
4499 IWineD3DVolume srcVolume = NULL;
4500 IWineD3DSurface destVolume = NULL;
4502 for (i = 0 ; i < levels ; ++i) {
4503 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4504 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4505 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4506 IWineD3DVolume_Release(srcSurface);
4507 IWineD3DVolume_Release(destSurface);
4508 if (WINED3D_OK != hr) {
4509 WARN("(%p) : Call to update volume failed\n", This);
4517 FIXME("(%p) : Unsupported source and destination type\n", This);
4518 hr = WINED3DERR_INVALIDCALL;
4525 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4526 IWineD3DSwapChain *swapChain;
4528 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4529 if(hr == WINED3D_OK) {
4530 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4531 IWineD3DSwapChain_Release(swapChain);
4536 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4538 /* return a sensible default */
4540 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4541 FIXME("(%p) : stub\n", This);
4545 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4548 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4549 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4550 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4551 return WINED3DERR_INVALIDCALL;
4553 for (j = 0; j < 256; ++j) {
4554 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4555 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4556 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4557 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4559 TRACE("(%p) : returning\n", This);
4563 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4567 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4568 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4569 return WINED3DERR_INVALIDCALL;
4571 for (j = 0; j < 256; ++j) {
4572 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4573 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4574 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4575 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4577 TRACE("(%p) : returning\n", This);
4581 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4584 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4585 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4586 return WINED3DERR_INVALIDCALL;
4588 /*TODO: stateblocks */
4589 This->currentPalette = PaletteNumber;
4590 TRACE("(%p) : returning\n", This);
4594 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4596 if (PaletteNumber == NULL) {
4597 WARN("(%p) : returning Invalid Call\n", This);
4598 return WINED3DERR_INVALIDCALL;
4600 /*TODO: stateblocks */
4601 *PaletteNumber = This->currentPalette;
4602 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4606 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4608 static BOOL showFixmes = TRUE;
4610 FIXME("(%p) : stub\n", This);
4614 This->softwareVertexProcessing = bSoftware;
4619 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4621 static BOOL showFixmes = TRUE;
4623 FIXME("(%p) : stub\n", This);
4626 return This->softwareVertexProcessing;
4630 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4632 IWineD3DSwapChain *swapChain;
4635 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4637 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4638 if(hr == WINED3D_OK){
4639 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4640 IWineD3DSwapChain_Release(swapChain);
4642 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4648 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4650 static BOOL showfixmes = TRUE;
4651 if(nSegments != 0.0f) {
4653 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4660 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4662 static BOOL showfixmes = TRUE;
4664 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4670 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4672 /** TODO: remove casts to IWineD3DSurfaceImpl
4673 * NOTE: move code to surface to accomplish this
4674 ****************************************/
4675 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4676 int srcWidth, srcHeight;
4677 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4678 WINED3DFORMAT destFormat, srcFormat;
4680 int srcLeft, destLeft, destTop;
4681 WINED3DPOOL srcPool, destPool;
4683 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4684 glDescriptor *glDescription = NULL;
4686 WINED3DSURFACE_DESC winedesc;
4688 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4689 memset(&winedesc, 0, sizeof(winedesc));
4690 winedesc.Width = &srcSurfaceWidth;
4691 winedesc.Height = &srcSurfaceHeight;
4692 winedesc.Pool = &srcPool;
4693 winedesc.Format = &srcFormat;
4695 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4697 winedesc.Width = &destSurfaceWidth;
4698 winedesc.Height = &destSurfaceHeight;
4699 winedesc.Pool = &destPool;
4700 winedesc.Format = &destFormat;
4701 winedesc.Size = &destSize;
4703 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4705 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4706 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4707 return WINED3DERR_INVALIDCALL;
4710 if (destFormat == WINED3DFMT_UNKNOWN) {
4711 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4712 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4714 /* Get the update surface description */
4715 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4719 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4720 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4721 checkGLcall("glActiveTextureARB");
4724 /* Make sure the surface is loaded and up to date */
4725 IWineD3DSurface_PreLoad(pDestinationSurface);
4727 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4729 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4730 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4731 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4732 srcLeft = pSourceRect ? pSourceRect->left : 0;
4733 destLeft = pDestPoint ? pDestPoint->x : 0;
4734 destTop = pDestPoint ? pDestPoint->y : 0;
4737 /* This function doesn't support compressed textures
4738 the pitch is just bytesPerPixel * width */
4739 if(srcWidth != srcSurfaceWidth || srcLeft ){
4740 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4741 offset += srcLeft * pSrcSurface->bytesPerPixel;
4742 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4744 /* TODO DXT formats */
4746 if(pSourceRect != NULL && pSourceRect->top != 0){
4747 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4749 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4751 ,glDescription->level
4756 ,glDescription->glFormat
4757 ,glDescription->glType
4758 ,IWineD3DSurface_GetData(pSourceSurface)
4762 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4764 /* need to lock the surface to get the data */
4765 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4768 /* TODO: Cube and volume support */
4770 /* not a whole row so we have to do it a line at a time */
4773 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4774 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4776 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4778 glTexSubImage2D(glDescription->target
4779 ,glDescription->level
4784 ,glDescription->glFormat
4785 ,glDescription->glType
4786 ,data /* could be quicker using */
4791 } else { /* Full width, so just write out the whole texture */
4793 if (WINED3DFMT_DXT1 == destFormat ||
4794 WINED3DFMT_DXT2 == destFormat ||
4795 WINED3DFMT_DXT3 == destFormat ||
4796 WINED3DFMT_DXT4 == destFormat ||
4797 WINED3DFMT_DXT5 == destFormat) {
4798 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4799 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4800 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4801 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4802 } if (destFormat != srcFormat) {
4803 FIXME("Updating mixed format compressed texture is not curretly support\n");
4805 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4806 glDescription->level,
4807 glDescription->glFormatInternal,
4812 IWineD3DSurface_GetData(pSourceSurface));
4815 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4820 glTexSubImage2D(glDescription->target
4821 ,glDescription->level
4826 ,glDescription->glFormat
4827 ,glDescription->glType
4828 ,IWineD3DSurface_GetData(pSourceSurface)
4832 checkGLcall("glTexSubImage2D");
4836 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
4837 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
4838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
4843 /* Implementation details at http://developer.nvidia.com/attach/6494
4845 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4846 hmm.. no longer supported use
4847 OpenGL evaluators or tessellate surfaces within your application.
4850 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4851 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4854 FIXME("(%p) : Stub\n", This);
4859 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4860 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4862 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4863 FIXME("(%p) : Stub\n", This);
4867 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4869 TRACE("(%p) Handle(%d)\n", This, Handle);
4870 FIXME("(%p) : Stub\n", This);
4874 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4876 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4878 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4880 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4881 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4882 return WINED3DERR_INVALIDCALL;
4885 /* Just forward this to the DirectDraw blitting engine */
4886 memset(&BltFx, 0, sizeof(BltFx));
4887 BltFx.dwSize = sizeof(BltFx);
4888 BltFx.u5.dwFillColor = color;
4889 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4892 /* rendertarget and deptth stencil functions */
4893 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4896 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4897 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4898 return WINED3DERR_INVALIDCALL;
4901 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4902 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4903 /* Note inc ref on returned surface */
4904 if(*ppRenderTarget != NULL)
4905 IWineD3DSurface_AddRef(*ppRenderTarget);
4909 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4911 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4912 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4913 IWineD3DSwapChainImpl *Swapchain;
4916 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4918 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4919 if(hr != WINED3D_OK) {
4920 ERR("Can't get the swapchain\n");
4924 /* Make sure to release the swapchain */
4925 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4927 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4928 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4929 return WINED3DERR_INVALIDCALL;
4931 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4932 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4933 return WINED3DERR_INVALIDCALL;
4936 if(Swapchain->frontBuffer != Front) {
4937 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4939 if(Swapchain->frontBuffer)
4940 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4941 Swapchain->frontBuffer = Front;
4943 if(Swapchain->frontBuffer) {
4944 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4948 if(Back && !Swapchain->backBuffer) {
4949 /* We need memory for the back buffer array - only one back buffer this way */
4950 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4951 if(!Swapchain->backBuffer) {
4952 ERR("Out of memory\n");
4953 return E_OUTOFMEMORY;
4957 if(Swapchain->backBuffer[0] != Back) {
4958 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4960 if(!Swapchain->backBuffer[0]) {
4961 /* GL was told to draw to the front buffer at creation,
4964 glDrawBuffer(GL_BACK);
4965 checkGLcall("glDrawBuffer(GL_BACK)");
4966 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4967 Swapchain->presentParms.BackBufferCount = 1;
4969 /* That makes problems - disable for now */
4970 /* glDrawBuffer(GL_FRONT); */
4971 checkGLcall("glDrawBuffer(GL_FRONT)");
4972 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4973 Swapchain->presentParms.BackBufferCount = 0;
4977 if(Swapchain->backBuffer[0])
4978 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4979 Swapchain->backBuffer[0] = Back;
4981 if(Swapchain->backBuffer[0]) {
4982 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
4984 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
4992 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
4993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4994 *ppZStencilSurface = This->depthStencilBuffer;
4995 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
4997 if(*ppZStencilSurface != NULL) {
4998 /* Note inc ref on returned surface */
4999 IWineD3DSurface_AddRef(*ppZStencilSurface);
5004 static void bind_fbo(IWineD3DDevice *iface) {
5005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5008 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5009 checkGLcall("glGenFramebuffersEXT()");
5011 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5012 checkGLcall("glBindFramebuffer()");
5015 /* TODO: Handle stencil attachments */
5016 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5018 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5020 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5024 if (depth_stencil_impl) {
5025 GLenum texttarget, target;
5026 GLint old_binding = 0;
5028 IWineD3DSurface_PreLoad(depth_stencil);
5029 texttarget = depth_stencil_impl->glDescription.target;
5030 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5032 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5033 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5034 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5035 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5036 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5037 glBindTexture(target, old_binding);
5039 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5040 checkGLcall("glFramebufferTexture2DEXT()");
5042 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5043 checkGLcall("glFramebufferTexture2DEXT()");
5046 if (!This->render_offscreen) {
5047 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5048 checkGLcall("glBindFramebuffer()");
5052 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5054 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5056 if (idx >= GL_LIMITS(buffers)) {
5057 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5063 GLenum texttarget, target;
5064 GLint old_binding = 0;
5066 IWineD3DSurface_PreLoad(render_target);
5067 texttarget = rtimpl->glDescription.target;
5068 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5070 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5071 glBindTexture(target, rtimpl->glDescription.textureName);
5072 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5073 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5074 glBindTexture(target, old_binding);
5076 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5077 checkGLcall("glFramebufferTexture2DEXT()");
5079 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5081 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5082 checkGLcall("glFramebufferTexture2DEXT()");
5084 This->draw_buffers[idx] = GL_NONE;
5087 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5088 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5089 checkGLcall("glDrawBuffers()");
5092 if (!This->render_offscreen) {
5093 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5094 checkGLcall("glBindFramebuffer()");
5098 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5100 WINED3DVIEWPORT viewport;
5102 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5104 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5105 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5106 return WINED3DERR_INVALIDCALL;
5109 /* MSDN says that null disables the render target
5110 but a device must always be associated with a render target
5111 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5113 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5116 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5117 FIXME("Trying to set render target 0 to NULL\n");
5118 return WINED3DERR_INVALIDCALL;
5120 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5121 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);
5122 return WINED3DERR_INVALIDCALL;
5125 /* If we are trying to set what we already have, don't bother */
5126 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5127 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5130 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5131 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5132 This->render_targets[RenderTargetIndex] = pRenderTarget;
5134 /* Render target 0 is special */
5135 if(RenderTargetIndex == 0) {
5136 /* Finally, reset the viewport as the MSDN states. */
5137 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5138 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5141 viewport.MaxZ = 1.0f;
5142 viewport.MinZ = 0.0f;
5143 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5144 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5145 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5147 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5149 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5151 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5152 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5154 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5156 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5157 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5162 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5164 HRESULT hr = WINED3D_OK;
5165 IWineD3DSurface *tmp;
5167 TRACE("(%p) Swapping z-buffer\n",This);
5169 if (pNewZStencil == This->stencilBufferTarget) {
5170 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5172 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5173 * depending on the renter target implementation being used.
5174 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5175 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5176 * stencil buffer and incure an extra memory overhead
5177 ******************************************************/
5179 tmp = This->stencilBufferTarget;
5180 This->stencilBufferTarget = pNewZStencil;
5181 /* should we be calling the parent or the wined3d surface? */
5182 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5183 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5186 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5187 set_depth_stencil_fbo(iface, pNewZStencil);
5190 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5191 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5193 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5201 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5202 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5204 /* TODO: the use of Impl is deprecated. */
5205 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5207 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5209 /* some basic validation checks */
5210 if(This->cursorTexture) {
5212 glDeleteTextures(1, &This->cursorTexture);
5214 This->cursorTexture = 0;
5218 /* MSDN: Cursor must be A8R8G8B8 */
5219 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5220 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5221 return WINED3DERR_INVALIDCALL;
5224 /* MSDN: Cursor must be smaller than the display mode */
5225 if(pSur->currentDesc.Width > This->ddraw_width ||
5226 pSur->currentDesc.Height > This->ddraw_height) {
5227 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);
5228 return WINED3DERR_INVALIDCALL;
5231 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5232 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5233 * Texture and Blitting code to draw the cursor
5235 pSur->Flags |= SFLAG_FORCELOAD;
5236 IWineD3DSurface_PreLoad(pCursorBitmap);
5237 pSur->Flags &= ~SFLAG_FORCELOAD;
5238 /* Do not store the surface's pointer because the application may release
5239 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5240 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5242 This->cursorTexture = pSur->glDescription.textureName;
5243 This->cursorWidth = pSur->currentDesc.Width;
5244 This->cursorHeight = pSur->currentDesc.Height;
5245 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5248 This->xHotSpot = XHotSpot;
5249 This->yHotSpot = YHotSpot;
5253 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5255 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5257 This->xScreenSpace = XScreenSpace;
5258 This->yScreenSpace = YScreenSpace;
5264 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5266 BOOL oldVisible = This->bCursorVisible;
5269 TRACE("(%p) : visible(%d)\n", This, bShow);
5271 if(This->cursorTexture)
5272 This->bCursorVisible = bShow;
5274 * When ShowCursor is first called it should make the cursor appear at the OS's last
5275 * known cursor position. Because of this, some applications just repetitively call
5276 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5279 This->xScreenSpace = pt.x;
5280 This->yScreenSpace = pt.y;
5285 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5287 TRACE("(%p) : state (%u)\n", This, This->state);
5288 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5289 switch (This->state) {
5292 case WINED3DERR_DEVICELOST:
5294 ResourceList *resourceList = This->resources;
5295 while (NULL != resourceList) {
5296 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5297 return WINED3DERR_DEVICENOTRESET;
5298 resourceList = resourceList->next;
5300 return WINED3DERR_DEVICELOST;
5302 case WINED3DERR_DRIVERINTERNALERROR:
5303 return WINED3DERR_DRIVERINTERNALERROR;
5307 return WINED3DERR_DRIVERINTERNALERROR;
5311 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5313 /** FIXME: Resource tracking needs to be done,
5314 * The closes we can do to this is set the priorities of all managed textures low
5315 * and then reset them.
5316 ***********************************************************/
5317 FIXME("(%p) : stub\n", This);
5321 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5322 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5324 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5325 if(surface->Flags & SFLAG_DIBSECTION) {
5326 /* Release the DC */
5327 SelectObject(surface->hDC, surface->dib.holdbitmap);
5328 DeleteDC(surface->hDC);
5329 /* Release the DIB section */
5330 DeleteObject(surface->dib.DIBsection);
5331 surface->dib.bitmap_data = NULL;
5332 surface->resource.allocatedMemory = NULL;
5333 surface->Flags &= ~SFLAG_DIBSECTION;
5335 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5336 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5337 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5338 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5339 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5341 surface->pow2Width = surface->pow2Height = 1;
5342 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5343 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5345 if(surface->glDescription.textureName) {
5347 glDeleteTextures(1, &surface->glDescription.textureName);
5349 surface->glDescription.textureName = 0;
5351 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5352 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5353 surface->Flags |= SFLAG_NONPOW2;
5355 surface->Flags &= ~SFLAG_NONPOW2;
5357 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5358 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5361 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5363 IWineD3DSwapChainImpl *swapchain;
5365 BOOL DisplayModeChanged = FALSE;
5366 WINED3DDISPLAYMODE mode;
5367 TRACE("(%p)\n", This);
5369 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5371 ERR("Failed to get the first implicit swapchain\n");
5375 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5376 * on an existing gl context, so there's no real need for recreation.
5378 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5380 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5382 TRACE("New params:\n");
5383 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5384 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5385 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5386 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5387 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5388 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5389 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5390 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5391 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5392 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5393 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5394 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5395 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5397 /* No special treatment of these parameters. Just store them */
5398 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5399 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5400 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5401 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5403 /* What to do about these? */
5404 if(pPresentationParameters->BackBufferCount != 0 &&
5405 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5406 ERR("Cannot change the back buffer count yet\n");
5408 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5409 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5410 ERR("Cannot change the back buffer format yet\n");
5412 if(pPresentationParameters->hDeviceWindow != NULL &&
5413 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5414 ERR("Cannot change the device window yet\n");
5416 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5417 ERR("What do do about a changed auto depth stencil parameter?\n");
5420 if(pPresentationParameters->Windowed) {
5421 mode.Width = swapchain->orig_width;
5422 mode.Height = swapchain->orig_height;
5423 mode.RefreshRate = 0;
5424 mode.Format = swapchain->presentParms.BackBufferFormat;
5426 mode.Width = pPresentationParameters->BackBufferWidth;
5427 mode.Height = pPresentationParameters->BackBufferHeight;
5428 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5429 mode.Format = swapchain->presentParms.BackBufferFormat;
5432 /* Should Width == 800 && Height == 0 set 800x600? */
5433 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5434 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5435 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5442 vp.Width = pPresentationParameters->BackBufferWidth;
5443 vp.Height = pPresentationParameters->BackBufferHeight;
5447 if(!pPresentationParameters->Windowed) {
5448 DisplayModeChanged = TRUE;
5450 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5451 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5453 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5454 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5455 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5458 /* Now set the new viewport */
5459 IWineD3DDevice_SetViewport(iface, &vp);
5462 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5463 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5464 DisplayModeChanged) {
5466 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5467 if(!pPresentationParameters->Windowed) {
5468 IWineD3DDevice_SetFullscreen(iface, TRUE);
5471 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5473 /* Switching out of fullscreen mode? First set the original res, then change the window */
5474 if(pPresentationParameters->Windowed) {
5475 IWineD3DDevice_SetFullscreen(iface, FALSE);
5477 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5480 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5484 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5486 /** FIXME: always true at the moment **/
5487 if(!bEnableDialogs) {
5488 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5494 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5496 TRACE("(%p) : pParameters %p\n", This, pParameters);
5498 *pParameters = This->createParms;
5502 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5503 IWineD3DSwapChain *swapchain;
5504 HRESULT hrc = WINED3D_OK;
5506 TRACE("Relaying to swapchain\n");
5508 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5509 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5510 IWineD3DSwapChain_Release(swapchain);
5515 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5516 IWineD3DSwapChain *swapchain;
5517 HRESULT hrc = WINED3D_OK;
5519 TRACE("Relaying to swapchain\n");
5521 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5522 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5523 IWineD3DSwapChain_Release(swapchain);
5529 /** ********************************************************
5530 * Notification functions
5531 ** ********************************************************/
5532 /** This function must be called in the release of a resource when ref == 0,
5533 * the contents of resource must still be correct,
5534 * any handels to other resource held by the caller must be closed
5535 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5536 *****************************************************/
5537 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5539 ResourceList* resourceList;
5541 TRACE("(%p) : resource %p\n", This, resource);
5543 EnterCriticalSection(&resourceStoreCriticalSection);
5545 /* add a new texture to the frot of the linked list */
5546 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5547 resourceList->resource = resource;
5549 /* Get the old head */
5550 resourceList->next = This->resources;
5552 This->resources = resourceList;
5553 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5556 LeaveCriticalSection(&resourceStoreCriticalSection);
5561 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 ResourceList* resourceList = NULL;
5564 ResourceList* previousResourceList = NULL;
5566 TRACE("(%p) : resource %p\n", This, resource);
5569 EnterCriticalSection(&resourceStoreCriticalSection);
5571 resourceList = This->resources;
5573 while (resourceList != NULL) {
5574 if(resourceList->resource == resource) break;
5575 previousResourceList = resourceList;
5576 resourceList = resourceList->next;
5579 if (resourceList == NULL) {
5580 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5582 LeaveCriticalSection(&resourceStoreCriticalSection);
5586 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5588 /* make sure we don't leave a hole in the list */
5589 if (previousResourceList != NULL) {
5590 previousResourceList->next = resourceList->next;
5592 This->resources = resourceList->next;
5596 LeaveCriticalSection(&resourceStoreCriticalSection);
5602 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5606 TRACE("(%p) : resource %p\n", This, resource);
5607 switch(IWineD3DResource_GetType(resource)){
5608 case WINED3DRTYPE_SURFACE:
5609 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5611 case WINED3DRTYPE_TEXTURE:
5612 case WINED3DRTYPE_CUBETEXTURE:
5613 case WINED3DRTYPE_VOLUMETEXTURE:
5614 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5615 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5616 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5617 This->stateBlock->textures[counter] = NULL;
5619 if (This->updateStateBlock != This->stateBlock ){
5620 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5621 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5622 This->updateStateBlock->textures[counter] = NULL;
5627 case WINED3DRTYPE_VOLUME:
5628 /* TODO: nothing really? */
5630 case WINED3DRTYPE_VERTEXBUFFER:
5631 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5634 TRACE("Cleaning up stream pointers\n");
5636 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5637 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5638 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5640 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5641 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5642 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5643 This->updateStateBlock->streamSource[streamNumber] = 0;
5644 /* Set changed flag? */
5647 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) */
5648 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5649 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5650 This->stateBlock->streamSource[streamNumber] = 0;
5653 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5654 else { /* This shouldn't happen */
5655 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5662 case WINED3DRTYPE_INDEXBUFFER:
5663 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5664 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5665 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5666 This->updateStateBlock->pIndexData = NULL;
5669 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5670 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5671 This->stateBlock->pIndexData = NULL;
5677 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5682 /* Remove the resoruce from the resourceStore */
5683 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5685 TRACE("Resource released\n");
5689 /**********************************************************
5690 * IWineD3DDevice VTbl follows
5691 **********************************************************/
5693 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5695 /*** IUnknown methods ***/
5696 IWineD3DDeviceImpl_QueryInterface,
5697 IWineD3DDeviceImpl_AddRef,
5698 IWineD3DDeviceImpl_Release,
5699 /*** IWineD3DDevice methods ***/
5700 IWineD3DDeviceImpl_GetParent,
5701 /*** Creation methods**/
5702 IWineD3DDeviceImpl_CreateVertexBuffer,
5703 IWineD3DDeviceImpl_CreateIndexBuffer,
5704 IWineD3DDeviceImpl_CreateStateBlock,
5705 IWineD3DDeviceImpl_CreateSurface,
5706 IWineD3DDeviceImpl_CreateTexture,
5707 IWineD3DDeviceImpl_CreateVolumeTexture,
5708 IWineD3DDeviceImpl_CreateVolume,
5709 IWineD3DDeviceImpl_CreateCubeTexture,
5710 IWineD3DDeviceImpl_CreateQuery,
5711 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5712 IWineD3DDeviceImpl_CreateVertexDeclaration,
5713 IWineD3DDeviceImpl_CreateVertexShader,
5714 IWineD3DDeviceImpl_CreatePixelShader,
5715 IWineD3DDeviceImpl_CreatePalette,
5716 /*** Odd functions **/
5717 IWineD3DDeviceImpl_Init3D,
5718 IWineD3DDeviceImpl_Uninit3D,
5719 IWineD3DDeviceImpl_SetFullscreen,
5720 IWineD3DDeviceImpl_EvictManagedResources,
5721 IWineD3DDeviceImpl_GetAvailableTextureMem,
5722 IWineD3DDeviceImpl_GetBackBuffer,
5723 IWineD3DDeviceImpl_GetCreationParameters,
5724 IWineD3DDeviceImpl_GetDeviceCaps,
5725 IWineD3DDeviceImpl_GetDirect3D,
5726 IWineD3DDeviceImpl_GetDisplayMode,
5727 IWineD3DDeviceImpl_SetDisplayMode,
5728 IWineD3DDeviceImpl_GetHWND,
5729 IWineD3DDeviceImpl_SetHWND,
5730 IWineD3DDeviceImpl_GetNumberOfSwapChains,
5731 IWineD3DDeviceImpl_GetRasterStatus,
5732 IWineD3DDeviceImpl_GetSwapChain,
5733 IWineD3DDeviceImpl_Reset,
5734 IWineD3DDeviceImpl_SetDialogBoxMode,
5735 IWineD3DDeviceImpl_SetCursorProperties,
5736 IWineD3DDeviceImpl_SetCursorPosition,
5737 IWineD3DDeviceImpl_ShowCursor,
5738 IWineD3DDeviceImpl_TestCooperativeLevel,
5739 /*** Getters and setters **/
5740 IWineD3DDeviceImpl_SetClipPlane,
5741 IWineD3DDeviceImpl_GetClipPlane,
5742 IWineD3DDeviceImpl_SetClipStatus,
5743 IWineD3DDeviceImpl_GetClipStatus,
5744 IWineD3DDeviceImpl_SetCurrentTexturePalette,
5745 IWineD3DDeviceImpl_GetCurrentTexturePalette,
5746 IWineD3DDeviceImpl_SetDepthStencilSurface,
5747 IWineD3DDeviceImpl_GetDepthStencilSurface,
5748 IWineD3DDeviceImpl_SetFVF,
5749 IWineD3DDeviceImpl_GetFVF,
5750 IWineD3DDeviceImpl_SetGammaRamp,
5751 IWineD3DDeviceImpl_GetGammaRamp,
5752 IWineD3DDeviceImpl_SetIndices,
5753 IWineD3DDeviceImpl_GetIndices,
5754 IWineD3DDeviceImpl_SetBasevertexIndex,
5755 IWineD3DDeviceImpl_SetLight,
5756 IWineD3DDeviceImpl_GetLight,
5757 IWineD3DDeviceImpl_SetLightEnable,
5758 IWineD3DDeviceImpl_GetLightEnable,
5759 IWineD3DDeviceImpl_SetMaterial,
5760 IWineD3DDeviceImpl_GetMaterial,
5761 IWineD3DDeviceImpl_SetNPatchMode,
5762 IWineD3DDeviceImpl_GetNPatchMode,
5763 IWineD3DDeviceImpl_SetPaletteEntries,
5764 IWineD3DDeviceImpl_GetPaletteEntries,
5765 IWineD3DDeviceImpl_SetPixelShader,
5766 IWineD3DDeviceImpl_GetPixelShader,
5767 IWineD3DDeviceImpl_SetPixelShaderConstantB,
5768 IWineD3DDeviceImpl_GetPixelShaderConstantB,
5769 IWineD3DDeviceImpl_SetPixelShaderConstantI,
5770 IWineD3DDeviceImpl_GetPixelShaderConstantI,
5771 IWineD3DDeviceImpl_SetPixelShaderConstantF,
5772 IWineD3DDeviceImpl_GetPixelShaderConstantF,
5773 IWineD3DDeviceImpl_SetRenderState,
5774 IWineD3DDeviceImpl_GetRenderState,
5775 IWineD3DDeviceImpl_SetRenderTarget,
5776 IWineD3DDeviceImpl_GetRenderTarget,
5777 IWineD3DDeviceImpl_SetFrontBackBuffers,
5778 IWineD3DDeviceImpl_SetSamplerState,
5779 IWineD3DDeviceImpl_GetSamplerState,
5780 IWineD3DDeviceImpl_SetScissorRect,
5781 IWineD3DDeviceImpl_GetScissorRect,
5782 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
5783 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
5784 IWineD3DDeviceImpl_SetStreamSource,
5785 IWineD3DDeviceImpl_GetStreamSource,
5786 IWineD3DDeviceImpl_SetStreamSourceFreq,
5787 IWineD3DDeviceImpl_GetStreamSourceFreq,
5788 IWineD3DDeviceImpl_SetTexture,
5789 IWineD3DDeviceImpl_GetTexture,
5790 IWineD3DDeviceImpl_SetTextureStageState,
5791 IWineD3DDeviceImpl_GetTextureStageState,
5792 IWineD3DDeviceImpl_SetTransform,
5793 IWineD3DDeviceImpl_GetTransform,
5794 IWineD3DDeviceImpl_SetVertexDeclaration,
5795 IWineD3DDeviceImpl_GetVertexDeclaration,
5796 IWineD3DDeviceImpl_SetVertexShader,
5797 IWineD3DDeviceImpl_GetVertexShader,
5798 IWineD3DDeviceImpl_SetVertexShaderConstantB,
5799 IWineD3DDeviceImpl_GetVertexShaderConstantB,
5800 IWineD3DDeviceImpl_SetVertexShaderConstantI,
5801 IWineD3DDeviceImpl_GetVertexShaderConstantI,
5802 IWineD3DDeviceImpl_SetVertexShaderConstantF,
5803 IWineD3DDeviceImpl_GetVertexShaderConstantF,
5804 IWineD3DDeviceImpl_SetViewport,
5805 IWineD3DDeviceImpl_GetViewport,
5806 IWineD3DDeviceImpl_MultiplyTransform,
5807 IWineD3DDeviceImpl_ValidateDevice,
5808 IWineD3DDeviceImpl_ProcessVertices,
5809 /*** State block ***/
5810 IWineD3DDeviceImpl_BeginStateBlock,
5811 IWineD3DDeviceImpl_EndStateBlock,
5812 /*** Scene management ***/
5813 IWineD3DDeviceImpl_BeginScene,
5814 IWineD3DDeviceImpl_EndScene,
5815 IWineD3DDeviceImpl_Present,
5816 IWineD3DDeviceImpl_Clear,
5818 IWineD3DDeviceImpl_DrawPrimitive,
5819 IWineD3DDeviceImpl_DrawIndexedPrimitive,
5820 IWineD3DDeviceImpl_DrawPrimitiveUP,
5821 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
5822 IWineD3DDeviceImpl_DrawPrimitiveStrided,
5823 IWineD3DDeviceImpl_DrawRectPatch,
5824 IWineD3DDeviceImpl_DrawTriPatch,
5825 IWineD3DDeviceImpl_DeletePatch,
5826 IWineD3DDeviceImpl_ColorFill,
5827 IWineD3DDeviceImpl_UpdateTexture,
5828 IWineD3DDeviceImpl_UpdateSurface,
5829 IWineD3DDeviceImpl_GetFrontBufferData,
5830 /*** object tracking ***/
5831 IWineD3DDeviceImpl_ResourceReleased
5835 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
5836 WINED3DRS_ALPHABLENDENABLE ,
5837 WINED3DRS_ALPHAFUNC ,
5838 WINED3DRS_ALPHAREF ,
5839 WINED3DRS_ALPHATESTENABLE ,
5841 WINED3DRS_COLORWRITEENABLE ,
5842 WINED3DRS_DESTBLEND ,
5843 WINED3DRS_DITHERENABLE ,
5844 WINED3DRS_FILLMODE ,
5845 WINED3DRS_FOGDENSITY ,
5847 WINED3DRS_FOGSTART ,
5848 WINED3DRS_LASTPIXEL ,
5849 WINED3DRS_SHADEMODE ,
5850 WINED3DRS_SRCBLEND ,
5851 WINED3DRS_STENCILENABLE ,
5852 WINED3DRS_STENCILFAIL ,
5853 WINED3DRS_STENCILFUNC ,
5854 WINED3DRS_STENCILMASK ,
5855 WINED3DRS_STENCILPASS ,
5856 WINED3DRS_STENCILREF ,
5857 WINED3DRS_STENCILWRITEMASK ,
5858 WINED3DRS_STENCILZFAIL ,
5859 WINED3DRS_TEXTUREFACTOR ,
5870 WINED3DRS_ZWRITEENABLE
5873 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
5874 WINED3DTSS_ADDRESSW ,
5875 WINED3DTSS_ALPHAARG0 ,
5876 WINED3DTSS_ALPHAARG1 ,
5877 WINED3DTSS_ALPHAARG2 ,
5878 WINED3DTSS_ALPHAOP ,
5879 WINED3DTSS_BUMPENVLOFFSET ,
5880 WINED3DTSS_BUMPENVLSCALE ,
5881 WINED3DTSS_BUMPENVMAT00 ,
5882 WINED3DTSS_BUMPENVMAT01 ,
5883 WINED3DTSS_BUMPENVMAT10 ,
5884 WINED3DTSS_BUMPENVMAT11 ,
5885 WINED3DTSS_COLORARG0 ,
5886 WINED3DTSS_COLORARG1 ,
5887 WINED3DTSS_COLORARG2 ,
5888 WINED3DTSS_COLOROP ,
5889 WINED3DTSS_RESULTARG ,
5890 WINED3DTSS_TEXCOORDINDEX ,
5891 WINED3DTSS_TEXTURETRANSFORMFLAGS
5894 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
5895 WINED3DSAMP_ADDRESSU ,
5896 WINED3DSAMP_ADDRESSV ,
5897 WINED3DSAMP_ADDRESSW ,
5898 WINED3DSAMP_BORDERCOLOR ,
5899 WINED3DSAMP_MAGFILTER ,
5900 WINED3DSAMP_MINFILTER ,
5901 WINED3DSAMP_MIPFILTER ,
5902 WINED3DSAMP_MIPMAPLODBIAS ,
5903 WINED3DSAMP_MAXMIPLEVEL ,
5904 WINED3DSAMP_MAXANISOTROPY ,
5905 WINED3DSAMP_SRGBTEXTURE ,
5906 WINED3DSAMP_ELEMENTINDEX
5909 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
5911 WINED3DRS_AMBIENTMATERIALSOURCE ,
5912 WINED3DRS_CLIPPING ,
5913 WINED3DRS_CLIPPLANEENABLE ,
5914 WINED3DRS_COLORVERTEX ,
5915 WINED3DRS_DIFFUSEMATERIALSOURCE ,
5916 WINED3DRS_EMISSIVEMATERIALSOURCE ,
5917 WINED3DRS_FOGDENSITY ,
5919 WINED3DRS_FOGSTART ,
5920 WINED3DRS_FOGTABLEMODE ,
5921 WINED3DRS_FOGVERTEXMODE ,
5922 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
5923 WINED3DRS_LIGHTING ,
5924 WINED3DRS_LOCALVIEWER ,
5925 WINED3DRS_MULTISAMPLEANTIALIAS ,
5926 WINED3DRS_MULTISAMPLEMASK ,
5927 WINED3DRS_NORMALIZENORMALS ,
5928 WINED3DRS_PATCHEDGESTYLE ,
5929 WINED3DRS_POINTSCALE_A ,
5930 WINED3DRS_POINTSCALE_B ,
5931 WINED3DRS_POINTSCALE_C ,
5932 WINED3DRS_POINTSCALEENABLE ,
5933 WINED3DRS_POINTSIZE ,
5934 WINED3DRS_POINTSIZE_MAX ,
5935 WINED3DRS_POINTSIZE_MIN ,
5936 WINED3DRS_POINTSPRITEENABLE ,
5937 WINED3DRS_RANGEFOGENABLE ,
5938 WINED3DRS_SPECULARMATERIALSOURCE ,
5939 WINED3DRS_TWEENFACTOR ,
5940 WINED3DRS_VERTEXBLEND
5943 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
5944 WINED3DTSS_TEXCOORDINDEX ,
5945 WINED3DTSS_TEXTURETRANSFORMFLAGS
5948 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
5949 WINED3DSAMP_DMAPOFFSET
5952 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
5953 DWORD rep = StateTable[state].representative;
5957 WineD3DContext *context;
5960 for(i = 0; i < This->numContexts; i++) {
5961 context = This->contexts[i];
5962 if(isStateDirty(context, rep)) continue;
5964 context->dirtyArray[context->numDirtyEntries++] = rep;
5967 context->isStateDirty[idx] |= (1 << shift);