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 WINE_DECLARE_DEBUG_CHANNEL(d3d_shader);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(This->wineD3D))->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* x11drv GDI escapes */
55 #define X11DRV_ESCAPE 6789
56 enum x11drv_escape_codes
58 X11DRV_GET_DISPLAY, /* get X11 display for a DC */
59 X11DRV_GET_DRAWABLE, /* get current drawable for a DC */
60 X11DRV_GET_FONT, /* get current X font for a DC */
63 /* retrieve the X display to use on a given DC */
64 inline static Display *get_display( HDC hdc )
67 enum x11drv_escape_codes escape = X11DRV_GET_DISPLAY;
69 if (!ExtEscape( hdc, X11DRV_ESCAPE, sizeof(escape), (LPCSTR)&escape,
70 sizeof(display), (LPSTR)&display )) display = NULL;
74 /* allocate one pbuffer per surface */
75 BOOL pbuffer_per_surface = FALSE;
77 /* static function declarations */
78 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
80 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil);
83 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
85 #define D3DCREATEOBJECTINSTANCE(object, type) { \
86 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
87 D3DMEMCHECK(object, pp##type); \
88 object->lpVtbl = &IWineD3D##type##_Vtbl; \
89 object->wineD3DDevice = This; \
90 object->parent = parent; \
92 *pp##type = (IWineD3D##type *) object; \
95 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
96 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
97 D3DMEMCHECK(object, pp##type); \
98 object->lpVtbl = &IWineD3D##type##_Vtbl; \
99 object->parent = parent; \
101 object->baseShader.device = (IWineD3DDevice*) This; \
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 * GLSL helper functions follow
153 **********************************************************/
155 /** Detach the GLSL pixel or vertex shader object from the shader program */
156 static void detach_glsl_shader(IWineD3DDevice *iface, GLhandleARB shaderObj, GLhandleARB programId) {
158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 if (shaderObj != 0 && programId != 0) {
161 TRACE_(d3d_shader)("Detaching GLSL shader object %u from program %u\n", shaderObj, programId);
162 GL_EXTCALL(glDetachObjectARB(programId, shaderObj));
163 checkGLcall("glDetachObjectARB");
167 /** Delete a GLSL shader program */
168 static void delete_glsl_shader_program(IWineD3DDevice *iface, GLhandleARB obj) {
170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
173 TRACE_(d3d_shader)("Deleting GLSL shader program %u\n", obj);
174 GL_EXTCALL(glDeleteObjectARB(obj));
175 checkGLcall("glDeleteObjectARB");
179 /** Delete the list of linked programs this shader is associated with.
180 * Also at this point, check to see if there are any objects left attached
181 * to each GLSL program. If not, delete the GLSL program object.
182 * This will be run when a device is released. */
183 static void delete_glsl_shader_list(IWineD3DDevice* iface) {
185 struct list *ptr = NULL;
186 struct glsl_shader_prog_link *curLink = NULL;
187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
191 GLhandleARB objList[2]; /* There should never be more than 2 objects attached
192 (one pixel shader and one vertex shader at most) */
194 ptr = list_head( &This->glsl_shader_progs );
196 /* First, get the current item,
197 * save the link to the next pointer,
198 * detach and delete shader objects,
199 * then de-allocate the list item's memory */
200 curLink = LIST_ENTRY( ptr, struct glsl_shader_prog_link, entry );
201 ptr = list_next( &This->glsl_shader_progs, ptr );
203 /* See if this object is still attached to the program - it may have been detached already */
204 GL_EXTCALL(glGetAttachedObjectsARB(curLink->programId, 2, &numAttached, objList));
205 TRACE_(d3d_shader)("%i GLSL objects are currently attached to program %u\n", numAttached, curLink->programId);
206 for (i = 0; i < numAttached; i++) {
207 detach_glsl_shader(iface, objList[i], curLink->programId);
210 delete_glsl_shader_program(iface, curLink->programId);
212 /* Free the uniform locations */
213 HeapFree(GetProcessHeap(), 0, curLink->vuniformF_locations);
214 HeapFree(GetProcessHeap(), 0, curLink->puniformF_locations);
216 /* Free the memory for this list item */
217 HeapFree(GetProcessHeap(), 0, curLink);
221 /**********************************************************
222 * IUnknown parts follows
223 **********************************************************/
225 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
229 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
230 if (IsEqualGUID(riid, &IID_IUnknown)
231 || IsEqualGUID(riid, &IID_IWineD3DBase)
232 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
233 IUnknown_AddRef(iface);
238 return E_NOINTERFACE;
241 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
243 ULONG refCount = InterlockedIncrement(&This->ref);
245 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
249 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
250 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
251 ULONG refCount = InterlockedDecrement(&This->ref);
253 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
257 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
260 HeapFree(GetProcessHeap(), 0, This->render_targets);
262 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
264 /* TODO: Clean up all the surfaces and textures! */
265 /* NOTE: You must release the parent if the object was created via a callback
266 ** ***************************/
268 /* Delete any GLSL shader programs that may exist */
269 if (This->vs_selected_mode == SHADER_GLSL ||
270 This->ps_selected_mode == SHADER_GLSL)
271 delete_glsl_shader_list(iface);
273 /* Release the update stateblock */
274 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
275 if(This->updateStateBlock != This->stateBlock)
276 FIXME("(%p) Something's still holding the Update stateblock\n",This);
278 This->updateStateBlock = NULL;
279 { /* because were not doing proper internal refcounts releasing the primary state block
280 causes recursion with the extra checks in ResourceReleased, to avoid this we have
281 to set this->stateBlock = NULL; first */
282 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
283 This->stateBlock = NULL;
285 /* Release the stateblock */
286 if(IWineD3DStateBlock_Release(stateBlock) > 0){
287 FIXME("(%p) Something's still holding the Update stateblock\n",This);
291 if (This->resources != NULL ) {
292 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
293 dumpResources(This->resources);
296 if(This->contexts) ERR("Context array not freed!\n");
298 IWineD3D_Release(This->wineD3D);
299 This->wineD3D = NULL;
300 HeapFree(GetProcessHeap(), 0, This);
301 TRACE("Freed device %p\n", This);
307 /**********************************************************
308 * IWineD3DDevice implementation follows
309 **********************************************************/
310 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 *pParent = This->parent;
313 IUnknown_AddRef(This->parent);
317 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
318 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
319 GLenum error, glUsage;
320 DWORD vboUsage = object->resource.usage;
321 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
322 WARN("Creating a vbo failed once, not trying again\n");
326 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
329 /* Make sure that the gl error is cleared. Do not use checkGLcall
330 * here because checkGLcall just prints a fixme and continues. However,
331 * if an error during VBO creation occurs we can fall back to non-vbo operation
332 * with full functionality(but performance loss)
334 while(glGetError() != GL_NO_ERROR);
336 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
337 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
338 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
339 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
340 * to check if the rhw and color values are in the correct format.
343 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
344 error = glGetError();
345 if(object->vbo == 0 || error != GL_NO_ERROR) {
346 WARN("Failed to create a VBO with error %d\n", error);
350 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
351 error = glGetError();
352 if(error != GL_NO_ERROR) {
353 WARN("Failed to bind the VBO, error %d\n", error);
357 /* Don't use static, because dx apps tend to update the buffer
358 * quite often even if they specify 0 usage. Because we always keep the local copy
359 * we never read from the vbo and can create a write only opengl buffer.
361 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
362 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
363 case WINED3DUSAGE_DYNAMIC:
364 TRACE("Gl usage = GL_STREAM_DRAW\n");
365 glUsage = GL_STREAM_DRAW_ARB;
367 case WINED3DUSAGE_WRITEONLY:
369 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
370 glUsage = GL_DYNAMIC_DRAW_ARB;
374 /* Reserve memory for the buffer. The amount of data won't change
375 * so we are safe with calling glBufferData once with a NULL ptr and
376 * calling glBufferSubData on updates
378 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
379 error = glGetError();
380 if(error != GL_NO_ERROR) {
381 WARN("glBufferDataARB failed with error %d\n", error);
389 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
390 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
391 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
393 object->Flags |= VBFLAG_VBOCREATEFAIL;
398 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
399 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
402 IWineD3DVertexBufferImpl *object;
403 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
404 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
408 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
409 *ppVertexBuffer = NULL;
410 return WINED3DERR_INVALIDCALL;
413 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
415 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
416 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
418 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
419 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
423 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
424 * drawStridedFast (half-life 2).
426 * Basically converting the vertices in the buffer is quite expensive, and observations
427 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
428 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
430 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
431 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
432 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
433 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
435 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
436 * more. In this call we can convert dx7 buffers too.
438 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
439 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
440 (dxVersion > 7 || !conv) ) {
446 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
447 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
448 HANDLE *sharedHandle, IUnknown *parent) {
449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
450 IWineD3DIndexBufferImpl *object;
451 TRACE("(%p) Creating index buffer\n", This);
453 /* Allocate the storage for the device */
454 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
457 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
458 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
461 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
462 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
463 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
468 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
471 IWineD3DStateBlockImpl *object;
475 D3DCREATEOBJECTINSTANCE(object, StateBlock)
476 object->blockType = Type;
478 for(i = 0; i < LIGHTMAP_SIZE; i++) {
479 list_init(&object->lightMap[i]);
482 /* Special case - Used during initialization to produce a placeholder stateblock
483 so other functions called can update a state block */
484 if (Type == WINED3DSBT_INIT) {
485 /* Don't bother increasing the reference count otherwise a device will never
486 be freed due to circular dependencies */
490 temp_result = allocate_shader_constants(object);
491 if (WINED3D_OK != temp_result)
494 /* Otherwise, might as well set the whole state block to the appropriate values */
495 if (This->stateBlock != NULL)
496 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
498 memset(object->streamFreq, 1, sizeof(object->streamFreq));
500 /* Reset the ref and type after kludging it */
501 object->wineD3DDevice = This;
503 object->blockType = Type;
505 TRACE("Updating changed flags appropriate for type %d\n", Type);
507 if (Type == WINED3DSBT_ALL) {
509 TRACE("ALL => Pretend everything has changed\n");
510 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
512 /* Lights are not part of the changed / set structure */
513 for(j = 0; j < LIGHTMAP_SIZE; j++) {
515 LIST_FOR_EACH(e, &object->lightMap[j]) {
516 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
517 light->changed = TRUE;
518 light->enabledChanged = TRUE;
521 } else if (Type == WINED3DSBT_PIXELSTATE) {
523 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
524 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
526 object->changed.pixelShader = TRUE;
528 /* Pixel Shader Constants */
529 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
530 object->changed.pixelShaderConstantsF[i] = TRUE;
531 for (i = 0; i < MAX_CONST_B; ++i)
532 object->changed.pixelShaderConstantsB[i] = TRUE;
533 for (i = 0; i < MAX_CONST_I; ++i)
534 object->changed.pixelShaderConstantsI[i] = TRUE;
536 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
537 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
539 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
540 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
541 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
544 for (j = 0 ; j < 16; j++) {
545 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
547 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
551 } else if (Type == WINED3DSBT_VERTEXSTATE) {
553 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
554 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
556 object->changed.vertexShader = TRUE;
558 /* Vertex Shader Constants */
559 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
560 object->changed.vertexShaderConstantsF[i] = TRUE;
561 for (i = 0; i < MAX_CONST_B; ++i)
562 object->changed.vertexShaderConstantsB[i] = TRUE;
563 for (i = 0; i < MAX_CONST_I; ++i)
564 object->changed.vertexShaderConstantsI[i] = TRUE;
566 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
567 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
569 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
570 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
571 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
574 for (j = 0 ; j < 16; j++){
575 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
576 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
580 for(j = 0; j < LIGHTMAP_SIZE; j++) {
582 LIST_FOR_EACH(e, &object->lightMap[j]) {
583 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
584 light->changed = TRUE;
585 light->enabledChanged = TRUE;
589 FIXME("Unrecognized state block type %d\n", Type);
592 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
597 /* ************************************
599 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
602 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
604 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.
606 ******************************** */
608 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) {
609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
610 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
611 unsigned int pow2Width, pow2Height;
612 unsigned int Size = 1;
613 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
614 TRACE("(%p) Create surface\n",This);
616 /** FIXME: Check ranges on the inputs are valid
619 * [in] Quality level. The valid range is between zero and one less than the level
620 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
621 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
622 * values of paired render targets, depth stencil surfaces, and the MultiSample type
624 *******************************/
629 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 * If this flag is set, the contents of the depth stencil buffer will be
632 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
633 * with a different depth surface.
635 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
636 ***************************/
638 if(MultisampleQuality < 0) {
639 FIXME("Invalid multisample level %d\n", MultisampleQuality);
640 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
643 if(MultisampleQuality > 0) {
644 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
645 MultisampleQuality=0;
648 /** FIXME: Check that the format is supported
650 *******************************/
652 /* Non-power2 support */
653 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
657 /* Find the nearest pow2 match */
658 pow2Width = pow2Height = 1;
659 while (pow2Width < Width) pow2Width <<= 1;
660 while (pow2Height < Height) pow2Height <<= 1;
663 if (pow2Width > Width || pow2Height > Height) {
664 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
665 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
666 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
667 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
668 This, Width, Height);
669 return WINED3DERR_NOTAVAILABLE;
673 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
674 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
676 *********************************/
677 if (WINED3DFMT_UNKNOWN == Format) {
679 } else if (Format == WINED3DFMT_DXT1) {
680 /* DXT1 is half byte per pixel */
681 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
683 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
684 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
685 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
687 /* The pitch is a multiple of 4 bytes */
688 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
692 /** Create and initialise the surface resource **/
693 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
694 /* "Standalone" surface */
695 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
697 object->currentDesc.Width = Width;
698 object->currentDesc.Height = Height;
699 object->currentDesc.MultiSampleType = MultiSample;
700 object->currentDesc.MultiSampleQuality = MultisampleQuality;
702 /* Setup some glformat defaults */
703 object->glDescription.glFormat = tableEntry->glFormat;
704 object->glDescription.glFormatInternal = tableEntry->glInternal;
705 object->glDescription.glType = tableEntry->glType;
707 object->glDescription.textureName = 0;
708 object->glDescription.level = Level;
709 object->glDescription.target = GL_TEXTURE_2D;
712 object->pow2Width = pow2Width;
713 object->pow2Height = pow2Height;
716 object->Flags = 0; /* We start without flags set */
717 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
718 object->Flags |= Discard ? SFLAG_DISCARD : 0;
719 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
720 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
723 if (WINED3DFMT_UNKNOWN != Format) {
724 object->bytesPerPixel = tableEntry->bpp;
726 object->bytesPerPixel = 0;
729 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
731 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
733 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
734 * this function is too deep to need to care about things like this.
735 * Levels need to be checked too, and possibly Type since they all affect what can be done.
736 * ****************************************/
738 case WINED3DPOOL_SCRATCH:
740 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
741 "which are mutually exclusive, setting lockable to TRUE\n");
744 case WINED3DPOOL_SYSTEMMEM:
745 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
746 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
747 case WINED3DPOOL_MANAGED:
748 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
749 "Usage of DYNAMIC which are mutually exclusive, not doing "
750 "anything just telling you.\n");
752 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
753 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
754 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
755 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
758 FIXME("(%p) Unknown pool %d\n", This, Pool);
762 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
763 FIXME("Trying to create a render target that isn't in the default pool\n");
766 /* mark the texture as dirty so that it gets loaded first time around*/
767 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
768 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
769 This, Width, Height, Format, debug_d3dformat(Format),
770 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
772 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
773 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
774 This->ddraw_primary = (IWineD3DSurface *) object;
776 /* Look at the implementation and set the correct Vtable */
779 /* Nothing to do, it's set already */
783 object->lpVtbl = &IWineGDISurface_Vtbl;
787 /* To be sure to catch this */
788 ERR("Unknown requested surface implementation %d!\n", Impl);
789 IWineD3DSurface_Release((IWineD3DSurface *) object);
790 return WINED3DERR_INVALIDCALL;
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
798 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
799 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
800 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
804 IWineD3DTextureImpl *object;
809 unsigned int pow2Width;
810 unsigned int pow2Height;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN >= Format) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
821 return WINED3DERR_INVALIDCALL;
824 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
825 D3DINITIALIZEBASETEXTURE(object->baseTexture);
826 object->width = Width;
827 object->height = Height;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
834 /* Find the nearest pow2 match */
835 pow2Width = pow2Height = 1;
836 while (pow2Width < Width) pow2Width <<= 1;
837 while (pow2Height < Height) pow2Height <<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
843 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
844 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
846 /* Calculate levels for mip mapping */
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
884 TRACE("(%p) : Created texture %p\n", This, object);
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Depth,
890 UINT Levels, DWORD Usage,
891 WINED3DFORMAT Format, WINED3DPOOL Pool,
892 IWineD3DVolumeTexture **ppVolumeTexture,
893 HANDLE *pSharedHandle, IUnknown *parent,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 IWineD3DVolumeTextureImpl *object;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN >= Format) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
907 return WINED3DERR_INVALIDCALL;
910 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
911 D3DINITIALIZEBASETEXTURE(object->baseTexture);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
914 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
916 object->width = Width;
917 object->height = Height;
918 object->depth = Depth;
920 /* Calculate levels for mip mapping */
922 object->baseTexture.levels++;
926 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 tmpD = max(1, tmpD >> 1);
930 object->baseTexture.levels++;
932 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
935 /* Generate all the surfaces */
940 for (i = 0; i < object->baseTexture.levels; i++)
942 /* Create the volume */
943 D3DCB_CreateVolume(This->parent, parent, Width, Height, Depth, Format, Pool, Usage,
944 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
946 /* Set its container to this object */
947 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
949 /* calcualte the next mipmap level */
950 tmpW = max(1, tmpW >> 1);
951 tmpH = max(1, tmpH >> 1);
952 tmpD = max(1, tmpD >> 1);
955 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
956 TRACE("(%p) : Created volume texture %p\n", This, object);
960 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
961 UINT Width, UINT Height, UINT Depth,
963 WINED3DFORMAT Format, WINED3DPOOL Pool,
964 IWineD3DVolume** ppVolume,
965 HANDLE* pSharedHandle, IUnknown *parent) {
967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
968 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
969 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
971 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
973 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
974 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
976 object->currentDesc.Width = Width;
977 object->currentDesc.Height = Height;
978 object->currentDesc.Depth = Depth;
979 object->bytesPerPixel = formatDesc->bpp;
981 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
982 object->lockable = TRUE;
983 object->locked = FALSE;
984 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
985 object->dirty = TRUE;
987 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
990 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
991 UINT Levels, DWORD Usage,
992 WINED3DFORMAT Format, WINED3DPOOL Pool,
993 IWineD3DCubeTexture **ppCubeTexture,
994 HANDLE *pSharedHandle, IUnknown *parent,
995 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
998 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1002 unsigned int pow2EdgeLength = EdgeLength;
1004 /* TODO: It should only be possible to create textures for formats
1005 that are reported as supported */
1006 if (WINED3DFMT_UNKNOWN >= Format) {
1007 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1008 return WINED3DERR_INVALIDCALL;
1011 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1012 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1014 TRACE("(%p) Create Cube Texture\n", This);
1016 /** Non-power2 support **/
1018 /* Find the nearest pow2 match */
1020 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1022 object->edgeLength = EdgeLength;
1023 /* TODO: support for native non-power 2 */
1024 /* Precalculated scaling for 'faked' non power of two texture coords */
1025 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1027 /* Calculate levels for mip mapping */
1029 object->baseTexture.levels++;
1032 tmpW = max(1, tmpW >> 1);
1033 object->baseTexture.levels++;
1035 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1038 /* Generate all the surfaces */
1040 for (i = 0; i < object->baseTexture.levels; i++) {
1042 /* Create the 6 faces */
1043 for (j = 0; j < 6; j++) {
1045 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1046 i /* Level */, &object->surfaces[j][i],pSharedHandle);
1048 if(hr!= WINED3D_OK) {
1052 for (l = 0; l < j; l++) {
1053 IWineD3DSurface_Release(object->surfaces[j][i]);
1055 for (k = 0; k < i; k++) {
1056 for (l = 0; l < 6; l++) {
1057 IWineD3DSurface_Release(object->surfaces[l][j]);
1061 FIXME("(%p) Failed to create surface\n",object);
1062 HeapFree(GetProcessHeap(),0,object);
1063 *ppCubeTexture = NULL;
1066 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1067 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1069 tmpW = max(1, tmpW >> 1);
1072 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1073 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1077 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1079 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1080 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1082 /* Just a check to see if we support this type of query */
1084 case WINED3DQUERYTYPE_OCCLUSION:
1085 TRACE("(%p) occlusion query\n", This);
1086 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1089 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1091 case WINED3DQUERYTYPE_VCACHE:
1092 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1093 case WINED3DQUERYTYPE_VERTEXSTATS:
1094 case WINED3DQUERYTYPE_EVENT:
1095 case WINED3DQUERYTYPE_TIMESTAMP:
1096 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1097 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1098 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1099 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1100 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1101 case WINED3DQUERYTYPE_PIXELTIMINGS:
1102 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1103 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1105 FIXME("(%p) Unhandled query type %d\n", This, Type);
1107 if(NULL == ppQuery || hr != WINED3D_OK) {
1111 D3DCREATEOBJECTINSTANCE(object, Query)
1112 object->type = Type;
1113 /* allocated the 'extended' data based on the type of query requested */
1115 case WINED3DQUERYTYPE_OCCLUSION:
1116 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1117 TRACE("(%p) Allocating data for an occlusion query\n", This);
1118 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1119 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1122 case WINED3DQUERYTYPE_VCACHE:
1123 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1124 case WINED3DQUERYTYPE_VERTEXSTATS:
1125 case WINED3DQUERYTYPE_EVENT:
1126 case WINED3DQUERYTYPE_TIMESTAMP:
1127 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1128 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1129 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1130 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1131 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1132 case WINED3DQUERYTYPE_PIXELTIMINGS:
1133 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1134 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1136 object->extendedData = 0;
1137 FIXME("(%p) Unhandled query type %d\n",This , Type);
1139 TRACE("(%p) : Created Query %p\n", This, object);
1143 /*****************************************************************************
1144 * IWineD3DDeviceImpl_SetupFullscreenWindow
1146 * Helper function that modifies a HWND's Style and ExStyle for proper
1150 * iface: Pointer to the IWineD3DDevice interface
1151 * window: Window to setup
1153 *****************************************************************************/
1154 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1157 LONG style, exStyle;
1158 /* Don't do anything if an original style is stored.
1159 * That shouldn't happen
1161 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1162 if (This->style || This->exStyle) {
1163 ERR("(%p): Want to change the window parameters of HWND %p, but "
1164 "another style is stored for restoration afterwards\n", This, window);
1167 /* Get the parameters and save them */
1168 style = GetWindowLongW(window, GWL_STYLE);
1169 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1170 This->style = style;
1171 This->exStyle = exStyle;
1173 /* Filter out window decorations */
1174 style &= ~WS_CAPTION;
1175 style &= ~WS_THICKFRAME;
1176 exStyle &= ~WS_EX_WINDOWEDGE;
1177 exStyle &= ~WS_EX_CLIENTEDGE;
1179 /* Make sure the window is managed, otherwise we won't get keyboard input */
1180 style |= WS_POPUP | WS_SYSMENU;
1182 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1183 This->style, This->exStyle, style, exStyle);
1185 SetWindowLongW(window, GWL_STYLE, style);
1186 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1188 /* Inform the window about the update. */
1189 SetWindowPos(window, HWND_TOP, 0, 0,
1190 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1191 ShowWindow(window, TRUE);
1194 /*****************************************************************************
1195 * IWineD3DDeviceImpl_RestoreWindow
1197 * Helper function that restores a windows' properties when taking it out
1198 * of fullscreen mode
1201 * iface: Pointer to the IWineD3DDevice interface
1202 * window: Window to setup
1204 *****************************************************************************/
1205 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1208 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1209 * switch, do nothing
1211 if (!This->style && !This->exStyle) return;
1213 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1214 This, window, This->style, This->exStyle);
1216 SetWindowLongW(window, GWL_STYLE, This->style);
1217 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1219 /* Delete the old values */
1223 /* Inform the window about the update */
1224 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1225 0, 0, 0, 0, /* Pos, Size, ignored */
1226 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1229 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1230 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1232 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1233 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1237 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1238 HRESULT hr = WINED3D_OK;
1239 IUnknown *bufferParent;
1242 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1244 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1245 * does a device hold a reference to a swap chain giving them a lifetime of the device
1246 * or does the swap chain notify the device of its destruction.
1247 *******************************/
1249 /* Check the params */
1250 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1251 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1252 return WINED3DERR_INVALIDCALL;
1253 } else if (pPresentationParameters->BackBufferCount > 1) {
1254 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");
1257 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1259 /*********************
1260 * Lookup the window Handle and the relating X window handle
1261 ********************/
1263 /* Setup hwnd we are using, plus which display this equates to */
1264 object->win_handle = pPresentationParameters->hDeviceWindow;
1265 if (!object->win_handle) {
1266 object->win_handle = This->createParms.hFocusWindow;
1269 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1270 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1271 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1272 return WINED3DERR_NOTAVAILABLE;
1274 hDc = GetDC(object->win_handle);
1275 display = get_display(hDc);
1276 ReleaseDC(object->win_handle, hDc);
1277 TRACE("Using a display of %p %p\n", display, hDc);
1279 if (NULL == display || NULL == hDc) {
1280 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1281 return WINED3DERR_NOTAVAILABLE;
1284 if (object->win == 0) {
1285 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1286 return WINED3DERR_NOTAVAILABLE;
1289 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1290 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1291 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1293 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1294 * then the corresponding dimension of the client area of the hDeviceWindow
1295 * (or the focus window, if hDeviceWindow is NULL) is taken.
1296 **********************/
1298 if (pPresentationParameters->Windowed &&
1299 ((pPresentationParameters->BackBufferWidth == 0) ||
1300 (pPresentationParameters->BackBufferHeight == 0))) {
1303 GetClientRect(object->win_handle, &Rect);
1305 if (pPresentationParameters->BackBufferWidth == 0) {
1306 pPresentationParameters->BackBufferWidth = Rect.right;
1307 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1309 if (pPresentationParameters->BackBufferHeight == 0) {
1310 pPresentationParameters->BackBufferHeight = Rect.bottom;
1311 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1315 /* Put the correct figures in the presentation parameters */
1316 TRACE("Copying across presentation parameters\n");
1317 object->presentParms = *pPresentationParameters;
1319 TRACE("calling rendertarget CB\n");
1320 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1322 object->presentParms.BackBufferWidth,
1323 object->presentParms.BackBufferHeight,
1324 object->presentParms.BackBufferFormat,
1325 object->presentParms.MultiSampleType,
1326 object->presentParms.MultiSampleQuality,
1327 TRUE /* Lockable */,
1328 &object->frontBuffer,
1329 NULL /* pShared (always null)*/);
1330 if (object->frontBuffer != NULL) {
1331 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1333 ERR("Failed to create the front buffer\n");
1338 * Create an opengl context for the display visual
1339 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1340 * use different properties after that point in time. FIXME: How to handle when requested format
1341 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1342 * it chooses is identical to the one already being used!
1343 **********************************/
1345 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1347 object->context = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1350 if (!object->context) {
1351 ERR("Failed to create a new context\n");
1352 hr = WINED3DERR_NOTAVAILABLE;
1355 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1356 object->win_handle, object->context->glCtx, object->win);
1359 /*********************
1360 * Windowed / Fullscreen
1361 *******************/
1364 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1365 * so we should really check to see if there is a fullscreen swapchain already
1366 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1367 **************************************/
1369 if (!pPresentationParameters->Windowed) {
1376 /* Get info on the current display setup */
1378 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1381 /* Change the display settings */
1382 memset(&devmode, 0, sizeof(DEVMODEW));
1383 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1384 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1385 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1386 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1387 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1388 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1390 /* For GetDisplayMode */
1391 This->ddraw_width = devmode.dmPelsWidth;
1392 This->ddraw_height = devmode.dmPelsHeight;
1393 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1395 IWineD3DDevice_SetFullscreen(iface, TRUE);
1397 /* And finally clip mouse to our screen */
1398 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1399 ClipCursor(&clip_rc);
1402 /*********************
1403 * Create the back, front and stencil buffers
1404 *******************/
1405 if(object->presentParms.BackBufferCount > 0) {
1408 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1409 if(!object->backBuffer) {
1410 ERR("Out of memory\n");
1415 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1416 TRACE("calling rendertarget CB\n");
1417 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1419 object->presentParms.BackBufferWidth,
1420 object->presentParms.BackBufferHeight,
1421 object->presentParms.BackBufferFormat,
1422 object->presentParms.MultiSampleType,
1423 object->presentParms.MultiSampleQuality,
1424 TRUE /* Lockable */,
1425 &object->backBuffer[i],
1426 NULL /* pShared (always null)*/);
1427 if(hr == WINED3D_OK && object->backBuffer[i]) {
1428 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1430 ERR("Cannot create new back buffer\n");
1434 glDrawBuffer(GL_BACK);
1435 checkGLcall("glDrawBuffer(GL_BACK)");
1439 object->backBuffer = NULL;
1441 /* Single buffering - draw to front buffer */
1443 glDrawBuffer(GL_FRONT);
1444 checkGLcall("glDrawBuffer(GL_FRONT)");
1448 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1449 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1450 TRACE("Creating depth stencil buffer\n");
1451 if (This->depthStencilBuffer == NULL ) {
1452 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1454 object->presentParms.BackBufferWidth,
1455 object->presentParms.BackBufferHeight,
1456 object->presentParms.AutoDepthStencilFormat,
1457 object->presentParms.MultiSampleType,
1458 object->presentParms.MultiSampleQuality,
1459 FALSE /* FIXME: Discard */,
1460 &This->depthStencilBuffer,
1461 NULL /* pShared (always null)*/ );
1462 if (This->depthStencilBuffer != NULL)
1463 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1466 /** TODO: A check on width, height and multisample types
1467 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1468 ****************************/
1469 object->wantsDepthStencilBuffer = TRUE;
1471 object->wantsDepthStencilBuffer = FALSE;
1474 TRACE("Created swapchain %p\n", object);
1475 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1479 if (object->backBuffer) {
1481 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1482 if(object->backBuffer[i]) {
1483 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1484 IUnknown_Release(bufferParent); /* once for the get parent */
1485 if (IUnknown_Release(bufferParent) > 0) {
1486 FIXME("(%p) Something's still holding the back buffer\n",This);
1490 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1491 object->backBuffer = NULL;
1493 if(object->context) {
1494 DestroyContext(This, object->context);
1496 if(object->frontBuffer) {
1497 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1498 IUnknown_Release(bufferParent); /* once for the get parent */
1499 if (IUnknown_Release(bufferParent) > 0) {
1500 FIXME("(%p) Something's still holding the front buffer\n",This);
1503 if(object) HeapFree(GetProcessHeap(), 0, object);
1507 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1508 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1510 TRACE("(%p)\n", This);
1512 return This->NumberOfSwapChains;
1515 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1517 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1519 if(iSwapChain < This->NumberOfSwapChains) {
1520 *pSwapChain = This->swapchains[iSwapChain];
1521 IWineD3DSwapChain_AddRef(*pSwapChain);
1522 TRACE("(%p) returning %p\n", This, *pSwapChain);
1525 TRACE("Swapchain out of range\n");
1527 return WINED3DERR_INVALIDCALL;
1532 * Vertex Declaration
1534 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1535 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1537 IWineD3DVertexDeclarationImpl *object = NULL;
1538 HRESULT hr = WINED3D_OK;
1540 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1541 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1543 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1546 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1551 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1552 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1554 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1555 HRESULT hr = WINED3D_OK;
1556 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1557 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1559 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1561 if (vertex_declaration) {
1562 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1565 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1567 if (WINED3D_OK != hr) {
1568 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1569 IWineD3DVertexShader_Release(*ppVertexShader);
1570 return WINED3DERR_INVALIDCALL;
1573 #if 0 /* TODO: In D3D* SVP is atatched to the shader, in D3D9 it's attached to the device and isn't stored in the stateblock. */
1574 if(Usage == WINED3DUSAGE_SOFTWAREVERTEXPROCESSING) {
1585 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1587 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1588 HRESULT hr = WINED3D_OK;
1590 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1591 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1592 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1593 if (WINED3D_OK == hr) {
1594 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1596 WARN("(%p) : Failed to create pixel shader\n", This);
1602 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1604 IWineD3DPaletteImpl *object;
1606 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1608 /* Create the new object */
1609 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1611 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1612 return E_OUTOFMEMORY;
1615 object->lpVtbl = &IWineD3DPalette_Vtbl;
1617 object->Flags = Flags;
1618 object->parent = Parent;
1619 object->wineD3DDevice = This;
1620 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1622 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1625 HeapFree( GetProcessHeap(), 0, object);
1626 return E_OUTOFMEMORY;
1629 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1631 IWineD3DPalette_Release((IWineD3DPalette *) object);
1635 *Palette = (IWineD3DPalette *) object;
1640 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1642 IWineD3DSwapChainImpl *swapchain;
1645 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1646 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1648 /* TODO: Test if OpenGL is compiled in and loaded */
1650 /* Initialize the texture unit mapping to a 1:1 mapping */
1651 for(state = 0; state < MAX_SAMPLERS; state++) {
1652 This->texUnitMap[state] = state;
1654 This->oneToOneTexUnitMap = TRUE;
1656 /* Setup the implicit swapchain */
1657 TRACE("Creating implicit swapchain\n");
1658 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1659 WARN("Failed to create implicit swapchain\n");
1660 return WINED3DERR_INVALIDCALL;
1663 This->NumberOfSwapChains = 1;
1664 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1665 if(!This->swapchains) {
1666 ERR("Out of memory!\n");
1667 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1668 return E_OUTOFMEMORY;
1670 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1672 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1674 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1675 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1676 This->render_targets[0] = swapchain->backBuffer[0];
1677 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1680 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1681 This->render_targets[0] = swapchain->frontBuffer;
1682 This->lastActiveRenderTarget = swapchain->frontBuffer;
1684 IWineD3DSurface_AddRef(This->render_targets[0]);
1685 This->activeContext = swapchain->context;
1687 /* Depth Stencil support */
1688 This->stencilBufferTarget = This->depthStencilBuffer;
1689 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
1690 set_depth_stencil_fbo(iface, This->depthStencilBuffer);
1692 if (NULL != This->stencilBufferTarget) {
1693 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1696 /* Set up some starting GL setup */
1699 * Initialize openGL extension related variables
1700 * with Default values
1703 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps( This->wineD3D, swapchain->context->display);
1704 /* Setup all the devices defaults */
1705 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1707 IWineD3DImpl_CheckGraphicsMemory();
1710 /* Initialize our list of GLSL programs */
1711 list_init(&This->glsl_shader_progs);
1713 { /* Set a default viewport */
1717 vp.Width = pPresentationParameters->BackBufferWidth;
1718 vp.Height = pPresentationParameters->BackBufferHeight;
1721 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1724 /* Initialize the current view state */
1725 This->view_ident = 1;
1726 This->contexts[0]->last_was_rhw = 0;
1727 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1728 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1729 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1732 /* Clear the screen */
1733 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL, WINED3DCLEAR_STENCIL|WINED3DCLEAR_ZBUFFER|WINED3DCLEAR_TARGET, 0x00, 1.0, 0);
1735 This->d3d_initialized = TRUE;
1739 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1743 TRACE("(%p)\n", This);
1745 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1747 /* Delete the pbuffer context if there is any */
1748 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1750 /* Delete the mouse cursor texture */
1751 if(This->cursorTexture) {
1753 glDeleteTextures(1, &This->cursorTexture);
1755 This->cursorTexture = 0;
1758 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1759 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1762 /* Release the buffers (with sanity checks)*/
1763 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1764 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1765 if(This->depthStencilBuffer != This->stencilBufferTarget)
1766 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1768 This->stencilBufferTarget = NULL;
1770 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1771 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1772 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1774 TRACE("Setting rendertarget to NULL\n");
1775 This->render_targets[0] = NULL;
1777 if (This->depthStencilBuffer) {
1778 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1779 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1781 This->depthStencilBuffer = NULL;
1784 for(i=0; i < This->NumberOfSwapChains; i++) {
1785 TRACE("Releasing the implicit swapchain %d\n", i);
1786 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1787 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1791 HeapFree(GetProcessHeap(), 0, This->swapchains);
1792 This->swapchains = NULL;
1793 This->NumberOfSwapChains = 0;
1795 This->d3d_initialized = FALSE;
1799 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1801 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1803 /* Setup the window for fullscreen mode */
1804 if(fullscreen && !This->ddraw_fullscreen) {
1805 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1806 } else if(!fullscreen && This->ddraw_fullscreen) {
1807 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1810 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1811 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1812 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1815 This->ddraw_fullscreen = fullscreen;
1818 static HRESULT WINAPI IWineD3DDeviceImpl_EnumDisplayModes(IWineD3DDevice *iface, DWORD Flags, UINT Width, UINT Height, WINED3DFORMAT pixelformat, LPVOID context, D3DCB_ENUMDISPLAYMODESCALLBACK callback) {
1819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1823 const PixelFormatDesc *formatDesc = getFormatDescEntry(pixelformat);
1825 TRACE("(%p)->(%x,%d,%d,%d,%p,%p)\n", This, Flags, Width, Height, pixelformat, context, callback);
1827 for (i = 0; EnumDisplaySettingsExW(NULL, i, &DevModeW, 0); i++) {
1828 /* Ignore some modes if a description was passed */
1829 if ( (Width > 0) && (Width != DevModeW.dmPelsWidth)) continue;
1830 if ( (Height > 0) && (Height != DevModeW.dmPelsHeight)) continue;
1831 if ( (pixelformat != WINED3DFMT_UNKNOWN) && ( formatDesc->bpp != DevModeW.dmBitsPerPel) ) continue;
1833 TRACE("Enumerating %dx%d@%s\n", DevModeW.dmPelsWidth, DevModeW.dmPelsHeight, debug_d3dformat(pixelformat_for_depth(DevModeW.dmBitsPerPel)));
1835 if (callback((IUnknown *) This, (UINT) DevModeW.dmPelsWidth, (UINT) DevModeW.dmPelsHeight, pixelformat_for_depth(DevModeW.dmBitsPerPel), 60.0, context) == DDENUMRET_CANCEL)
1842 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
1844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1846 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
1849 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
1851 /* Resize the screen even without a window:
1852 * The app could have unset it with SetCooperativeLevel, but not called
1853 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
1854 * but we don't have any hwnd
1857 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1858 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1859 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
1860 devmode.dmPelsWidth = pMode->Width;
1861 devmode.dmPelsHeight = pMode->Height;
1863 devmode.dmDisplayFrequency = pMode->RefreshRate;
1864 if (pMode->RefreshRate != 0) {
1865 devmode.dmFields |= DM_DISPLAYFREQUENCY;
1868 /* Only change the mode if necessary */
1869 if( (This->ddraw_width == pMode->Width) &&
1870 (This->ddraw_height == pMode->Height) &&
1871 (This->ddraw_format == pMode->Format) &&
1872 (pMode->RefreshRate == 0) ) {
1876 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
1877 if (ret != DISP_CHANGE_SUCCESSFUL) {
1878 if(devmode.dmDisplayFrequency != 0) {
1879 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
1880 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
1881 devmode.dmDisplayFrequency = 0;
1882 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
1884 if(ret != DISP_CHANGE_SUCCESSFUL) {
1885 return DDERR_INVALIDMODE;
1889 /* Store the new values */
1890 This->ddraw_width = pMode->Width;
1891 This->ddraw_height = pMode->Height;
1892 This->ddraw_format = pMode->Format;
1894 /* Only do this with a window of course */
1895 if(This->ddraw_window)
1896 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
1898 /* And finally clip mouse to our screen */
1899 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
1900 ClipCursor(&clip_rc);
1905 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
1906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1907 *ppD3D= This->wineD3D;
1908 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
1909 IWineD3D_AddRef(*ppD3D);
1913 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
1914 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
1915 * into the video ram as possible and seeing how many fit
1916 * you can also get the correct initial value from nvidia and ATI's driver via X
1917 * texture memory is video memory + AGP memory
1918 *******************/
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1920 static BOOL showfixmes = TRUE;
1922 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
1923 (wined3d_settings.emulated_textureram/(1024*1024)),
1924 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1927 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
1928 (wined3d_settings.emulated_textureram/(1024*1024)),
1929 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
1930 /* return simulated texture memory left */
1931 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
1939 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
1940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1942 /* Update the current state block */
1943 This->updateStateBlock->changed.fvf = TRUE;
1944 This->updateStateBlock->set.fvf = TRUE;
1946 if(This->updateStateBlock->fvf == fvf) {
1947 TRACE("Application is setting the old fvf over, nothing to do\n");
1951 This->updateStateBlock->fvf = fvf;
1952 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
1953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
1958 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
1959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1960 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
1961 *pfvf = This->stateBlock->fvf;
1966 * Get / Set Stream Source
1968 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1970 IWineD3DVertexBuffer *oldSrc;
1972 if (StreamNumber >= MAX_STREAMS) {
1973 WARN("Stream out of range %d\n", StreamNumber);
1974 return WINED3DERR_INVALIDCALL;
1977 oldSrc = This->stateBlock->streamSource[StreamNumber];
1978 TRACE("(%p) : StreamNo: %d, OldStream (%p), NewStream (%p), NewStride %d\n", This, StreamNumber, oldSrc, pStreamData, Stride);
1980 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
1981 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
1983 if(oldSrc == pStreamData &&
1984 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
1985 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
1986 TRACE("Application is setting the old values over, nothing to do\n");
1990 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
1992 This->updateStateBlock->streamStride[StreamNumber] = Stride;
1993 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
1996 /* Handle recording of state blocks */
1997 if (This->isRecordingState) {
1998 TRACE("Recording... not performing anything\n");
2002 /* Need to do a getParent and pass the reffs up */
2003 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2004 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2005 so for now, just count internally */
2006 if (pStreamData != NULL) {
2007 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2008 InterlockedIncrement(&vbImpl->bindCount);
2010 if (oldSrc != NULL) {
2011 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2019 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2023 TRACE("(%p) : StreamNo: %d, Stream (%p), Stride %d\n", This, StreamNumber,
2024 This->stateBlock->streamSource[StreamNumber], This->stateBlock->streamStride[StreamNumber]);
2027 streamFlags = StreamNumber &(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2029 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2030 FIXME("stream index data not supported\n");
2032 if (streamFlags & WINED3DSTREAMSOURCE_INDEXEDDATA) {
2033 FIXME("stream instance data not supported\n");
2037 StreamNumber&= ~(WINED3DSTREAMSOURCE_INDEXEDDATA | WINED3DSTREAMSOURCE_INSTANCEDATA);
2039 if (StreamNumber >= MAX_STREAMS) {
2040 WARN("Stream out of range %d\n", StreamNumber);
2041 return WINED3DERR_INVALIDCALL;
2043 *pStream = This->stateBlock->streamSource[StreamNumber];
2044 *pStride = This->stateBlock->streamStride[StreamNumber];
2046 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2049 if (*pStream != NULL) {
2050 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2055 /*Should be quite easy, just an extension of vertexdata
2057 http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c_Summer_04/directx/graphics/programmingguide/advancedtopics/DrawingMultipleInstances.asp
2059 The divider is a bit odd though
2061 VertexOffset = StartVertex / Divider * StreamStride +
2062 VertexIndex / Divider * StreamStride + StreamOffset
2065 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2067 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2068 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2070 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2071 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2073 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2074 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2075 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2077 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2078 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2079 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2085 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2088 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2089 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2091 TRACE("(%p) : returning %d\n", This, *Divider);
2097 * Get / Set & Multiply Transform
2099 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2102 /* Most of this routine, comments included copied from ddraw tree initially: */
2103 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2105 /* Handle recording of state blocks */
2106 if (This->isRecordingState) {
2107 TRACE("Recording... not performing anything\n");
2108 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2109 This->updateStateBlock->set.transform[d3dts] = TRUE;
2110 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2115 * If the new matrix is the same as the current one,
2116 * we cut off any further processing. this seems to be a reasonable
2117 * optimization because as was noticed, some apps (warcraft3 for example)
2118 * tend towards setting the same matrix repeatedly for some reason.
2120 * From here on we assume that the new matrix is different, wherever it matters.
2122 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2123 TRACE("The app is setting the same matrix over again\n");
2126 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2130 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2131 where ViewMat = Camera space, WorldMat = world space.
2133 In OpenGL, camera and world space is combined into GL_MODELVIEW
2134 matrix. The Projection matrix stay projection matrix.
2137 /* Capture the times we can just ignore the change for now */
2138 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2139 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2140 /* Handled by the state manager */
2143 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2147 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2149 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2150 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2154 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2155 WINED3DMATRIX *mat = NULL;
2158 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2159 * below means it will be recorded in a state block change, but it
2160 * works regardless where it is recorded.
2161 * If this is found to be wrong, change to StateBlock.
2163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2164 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2166 if (State < HIGHEST_TRANSFORMSTATE)
2168 mat = &This->updateStateBlock->transforms[State];
2170 FIXME("Unhandled transform state!!\n");
2173 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2175 /* Apply change via set transform - will reapply to eg. lights this way */
2176 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2182 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2183 you can reference any indexes you want as long as that number max are enabled at any
2184 one point in time! Therefore since the indexes can be anything, we need a linked list of them.
2185 However, this causes stateblock problems. When capturing the state block, I duplicate the list,
2186 but when recording, just build a chain pretty much of commands to be replayed. */
2188 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2190 PLIGHTINFOEL *object = NULL;
2191 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2195 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2197 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2198 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2199 if(object->OriginalIndex == Index) break;
2204 TRACE("Adding new light\n");
2205 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2207 ERR("Out of memory error when allocating a light\n");
2208 return E_OUTOFMEMORY;
2210 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2211 object->glIndex = -1;
2212 object->OriginalIndex = Index;
2213 object->changed = TRUE;
2216 /* Initialize the object */
2217 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,
2218 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2219 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2220 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2221 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2222 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2223 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2225 /* Save away the information */
2226 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2228 switch (pLight->Type) {
2229 case WINED3DLIGHT_POINT:
2231 object->lightPosn[0] = pLight->Position.x;
2232 object->lightPosn[1] = pLight->Position.y;
2233 object->lightPosn[2] = pLight->Position.z;
2234 object->lightPosn[3] = 1.0f;
2235 object->cutoff = 180.0f;
2239 case WINED3DLIGHT_DIRECTIONAL:
2241 object->lightPosn[0] = -pLight->Direction.x;
2242 object->lightPosn[1] = -pLight->Direction.y;
2243 object->lightPosn[2] = -pLight->Direction.z;
2244 object->lightPosn[3] = 0.0;
2245 object->exponent = 0.0f;
2246 object->cutoff = 180.0f;
2249 case WINED3DLIGHT_SPOT:
2251 object->lightPosn[0] = pLight->Position.x;
2252 object->lightPosn[1] = pLight->Position.y;
2253 object->lightPosn[2] = pLight->Position.z;
2254 object->lightPosn[3] = 1.0;
2257 object->lightDirn[0] = pLight->Direction.x;
2258 object->lightDirn[1] = pLight->Direction.y;
2259 object->lightDirn[2] = pLight->Direction.z;
2260 object->lightDirn[3] = 1.0;
2263 * opengl-ish and d3d-ish spot lights use too different models for the
2264 * light "intensity" as a function of the angle towards the main light direction,
2265 * so we only can approximate very roughly.
2266 * however spot lights are rather rarely used in games (if ever used at all).
2267 * furthermore if still used, probably nobody pays attention to such details.
2269 if (pLight->Falloff == 0) {
2272 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2274 if (rho < 0.0001) rho = 0.0001f;
2275 object->exponent = -0.3/log(cos(rho/2));
2276 if (object->exponent > 128.0) {
2277 object->exponent = 128.0;
2279 object->cutoff = pLight->Phi*90/M_PI;
2285 FIXME("Unrecognized light type %d\n", pLight->Type);
2288 /* Update the live definitions if the light is currently assigned a glIndex */
2289 if (object->glIndex != -1 && !This->isRecordingState) {
2290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2295 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2296 PLIGHTINFOEL *lightInfo = NULL;
2297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2298 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2300 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2302 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2303 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2304 if(lightInfo->OriginalIndex == Index) break;
2308 if (lightInfo == NULL) {
2309 TRACE("Light information requested but light not defined\n");
2310 return WINED3DERR_INVALIDCALL;
2313 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2318 * Get / Set Light Enable
2319 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2321 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2322 PLIGHTINFOEL *lightInfo = NULL;
2323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2324 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2326 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2328 /* Tests show true = 128...not clear why */
2329 Enable = Enable? 128: 0;
2331 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2332 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2333 if(lightInfo->OriginalIndex == Index) break;
2336 TRACE("Found light: %p\n", lightInfo);
2338 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2339 if (lightInfo == NULL) {
2341 TRACE("Light enabled requested but light not defined, so defining one!\n");
2342 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2344 /* Search for it again! Should be fairly quick as near head of list */
2345 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2346 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2347 if(lightInfo->OriginalIndex == Index) break;
2350 if (lightInfo == NULL) {
2351 FIXME("Adding default lights has failed dismally\n");
2352 return WINED3DERR_INVALIDCALL;
2356 lightInfo->enabledChanged = TRUE;
2358 if(lightInfo->glIndex != -1) {
2359 if(!This->isRecordingState) {
2360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2363 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2364 lightInfo->glIndex = -1;
2366 TRACE("Light already disabled, nothing to do\n");
2369 if (lightInfo->glIndex != -1) {
2371 TRACE("Nothing to do as light was enabled\n");
2374 /* Find a free gl light */
2375 for(i = 0; i < This->maxConcurrentLights; i++) {
2376 if(This->stateBlock->activeLights[i] == NULL) {
2377 This->stateBlock->activeLights[i] = lightInfo;
2378 lightInfo->glIndex = i;
2382 if(lightInfo->glIndex == -1) {
2383 ERR("Too many concurrently active lights\n");
2384 return WINED3DERR_INVALIDCALL;
2387 /* i == lightInfo->glIndex */
2388 if(!This->isRecordingState) {
2389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2397 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2399 PLIGHTINFOEL *lightInfo = NULL;
2400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2402 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2403 TRACE("(%p) : for idx(%d)\n", This, Index);
2405 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2406 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2407 if(lightInfo->OriginalIndex == Index) break;
2411 if (lightInfo == NULL) {
2412 TRACE("Light enabled state requested but light not defined\n");
2413 return WINED3DERR_INVALIDCALL;
2415 /* true is 128 according to SetLightEnable */
2416 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2421 * Get / Set Clip Planes
2423 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2427 /* Validate Index */
2428 if (Index >= GL_LIMITS(clipplanes)) {
2429 TRACE("Application has requested clipplane this device doesn't support\n");
2430 return WINED3DERR_INVALIDCALL;
2433 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2434 This->updateStateBlock->set.clipplane[Index] = TRUE;
2435 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];
2440 /* Handle recording of state blocks */
2441 if (This->isRecordingState) {
2442 TRACE("Recording... not performing anything\n");
2450 /* Clip Plane settings are affected by the model view in OpenGL, the View transform in direct3d */
2451 glMatrixMode(GL_MODELVIEW);
2453 glLoadMatrixf((float *) &This->stateBlock->transforms[WINED3DTS_VIEW].u.m[0][0]);
2455 TRACE("Clipplane [%f,%f,%f,%f]\n",
2456 This->updateStateBlock->clipplane[Index][0],
2457 This->updateStateBlock->clipplane[Index][1],
2458 This->updateStateBlock->clipplane[Index][2],
2459 This->updateStateBlock->clipplane[Index][3]);
2460 glClipPlane(GL_CLIP_PLANE0 + Index, This->updateStateBlock->clipplane[Index]);
2461 checkGLcall("glClipPlane");
2469 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2471 TRACE("(%p) : for idx %d\n", This, Index);
2473 /* Validate Index */
2474 if (Index >= GL_LIMITS(clipplanes)) {
2475 TRACE("Application has requested clipplane this device doesn't support\n");
2476 return WINED3DERR_INVALIDCALL;
2479 pPlane[0] = This->stateBlock->clipplane[Index][0];
2480 pPlane[1] = This->stateBlock->clipplane[Index][1];
2481 pPlane[2] = This->stateBlock->clipplane[Index][2];
2482 pPlane[3] = This->stateBlock->clipplane[Index][3];
2487 * Get / Set Clip Plane Status
2488 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2490 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2492 FIXME("(%p) : stub\n", This);
2493 if (NULL == pClipStatus) {
2494 return WINED3DERR_INVALIDCALL;
2496 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2497 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2501 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2503 FIXME("(%p) : stub\n", This);
2504 if (NULL == pClipStatus) {
2505 return WINED3DERR_INVALIDCALL;
2507 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2508 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2513 * Get / Set Material
2515 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2518 This->updateStateBlock->changed.material = TRUE;
2519 This->updateStateBlock->set.material = TRUE;
2520 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2522 /* Handle recording of state blocks */
2523 if (This->isRecordingState) {
2524 TRACE("Recording... not performing anything\n");
2529 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2530 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2531 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2532 pMaterial->Ambient.b, pMaterial->Ambient.a);
2533 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2534 pMaterial->Specular.b, pMaterial->Specular.a);
2535 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2536 pMaterial->Emissive.b, pMaterial->Emissive.a);
2537 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2539 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2540 checkGLcall("glMaterialfv(GL_AMBIENT)");
2541 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2542 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2544 /* Only change material color if specular is enabled, otherwise it is set to black */
2545 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2546 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2547 checkGLcall("glMaterialfv(GL_SPECULAR");
2549 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2550 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2551 checkGLcall("glMaterialfv(GL_SPECULAR");
2553 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2554 checkGLcall("glMaterialfv(GL_EMISSION)");
2555 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2556 checkGLcall("glMaterialf(GL_SHININESS");
2562 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2564 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2565 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2566 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2567 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2568 pMaterial->Ambient.b, pMaterial->Ambient.a);
2569 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2570 pMaterial->Specular.b, pMaterial->Specular.a);
2571 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2572 pMaterial->Emissive.b, pMaterial->Emissive.a);
2573 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2581 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData,
2582 UINT BaseVertexIndex) {
2583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2584 IWineD3DIndexBuffer *oldIdxs;
2585 UINT oldBaseIndex = This->updateStateBlock->baseVertexIndex;
2587 TRACE("(%p) : Setting to %p, base %d\n", This, pIndexData, BaseVertexIndex);
2588 oldIdxs = This->updateStateBlock->pIndexData;
2590 This->updateStateBlock->changed.indices = TRUE;
2591 This->updateStateBlock->set.indices = TRUE;
2592 This->updateStateBlock->pIndexData = pIndexData;
2593 This->updateStateBlock->baseVertexIndex = BaseVertexIndex;
2595 /* Handle recording of state blocks */
2596 if (This->isRecordingState) {
2597 TRACE("Recording... not performing anything\n");
2601 /* So far only the base vertex index is tracked */
2602 if(BaseVertexIndex != oldBaseIndex) {
2603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2608 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 *ppIndexData = This->stateBlock->pIndexData;
2613 /* up ref count on ppindexdata */
2615 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2616 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2617 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2619 TRACE("(%p) No index data set\n", This);
2621 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2626 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2627 static HRESULT WINAPI IWineD3DDeviceImpl_SetBasevertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 TRACE("(%p)->(%d)\n", This, BaseIndex);
2631 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2632 TRACE("Application is setting the old value over, nothing to do\n");
2636 This->updateStateBlock->baseVertexIndex = BaseIndex;
2638 if (This->isRecordingState) {
2639 TRACE("Recording... not performing anything\n");
2642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2647 * Get / Set Viewports
2649 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 TRACE("(%p)\n", This);
2653 This->updateStateBlock->changed.viewport = TRUE;
2654 This->updateStateBlock->set.viewport = TRUE;
2655 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2657 /* Handle recording of state blocks */
2658 if (This->isRecordingState) {
2659 TRACE("Recording... not performing anything\n");
2663 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2664 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2671 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2673 TRACE("(%p)\n", This);
2674 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2679 * Get / Set Render States
2680 * TODO: Verify against dx9 definitions
2682 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2685 DWORD oldValue = This->stateBlock->renderState[State];
2687 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2689 This->updateStateBlock->changed.renderState[State] = TRUE;
2690 This->updateStateBlock->set.renderState[State] = TRUE;
2691 This->updateStateBlock->renderState[State] = Value;
2693 /* Handle recording of state blocks */
2694 if (This->isRecordingState) {
2695 TRACE("Recording... not performing anything\n");
2699 /* Compared here and not before the assignment to allow proper stateblock recording */
2700 if(Value == oldValue) {
2701 TRACE("Application is setting the old value over, nothing to do\n");
2703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2709 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2711 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2712 *pValue = This->stateBlock->renderState[State];
2717 * Get / Set Sampler States
2718 * TODO: Verify against dx9 definitions
2721 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2726 * SetSampler is designed to allow for more than the standard up to 8 textures
2727 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2728 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2730 * http://developer.nvidia.com/object/General_FAQ.html#t6
2732 * There are two new settings for GForce
2734 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2735 * and the texture one:
2736 * GL_MAX_TEXTURE_COORDS_ARB.
2737 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2739 /** NOTE: States are applied in IWineD3DBaseTextre ApplyStateChanges the sampler state handler**/
2740 if(Sampler > GL_LIMITS(sampler_stages) || Sampler < 0 || Type > WINED3D_HIGHEST_SAMPLER_STATE || Type < 0) {
2741 FIXME("sampler %d type %s(%u) is out of range [max_samplers=%d, highest_state=%d]\n",
2742 Sampler, debug_d3dsamplerstate(Type), Type, GL_LIMITS(sampler_stages), WINED3D_HIGHEST_SAMPLER_STATE);
2743 return WINED3DERR_INVALIDCALL;
2746 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2747 debug_d3dsamplerstate(Type), Type, Value);
2748 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2749 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2750 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2752 /* Handle recording of state blocks */
2753 if (This->isRecordingState) {
2754 TRACE("Recording... not performing anything\n");
2758 if(oldValue == Value) {
2759 TRACE("Application is setting the old value over, nothing to do\n");
2763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2768 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2770 /** TODO: check that sampler is in range **/
2771 *Value = This->stateBlock->samplerState[Sampler][Type];
2772 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2777 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2782 This->updateStateBlock->set.scissorRect = TRUE;
2783 This->updateStateBlock->changed.scissorRect = TRUE;
2784 memcpy(&This->updateStateBlock->scissorRect, pRect, sizeof(*pRect));
2786 if(This->isRecordingState) {
2787 TRACE("Recording... not performing anything\n");
2791 GetClientRect(((IWineD3DSwapChainImpl *)This->swapchains[0])->win_handle, &windowRect);
2792 /* Warning: glScissor uses window coordinates, not viewport coordinates, so our viewport correction does not apply
2793 * Warning2: Even in windowed mode the coords are relative to the window, not the screen
2795 winHeight = windowRect.bottom - windowRect.top;
2796 TRACE("(%p)Setting new Scissor Rect to %d:%d-%d:%d\n", This, pRect->left, pRect->bottom - winHeight,
2797 pRect->right - pRect->left, pRect->bottom - pRect->top);
2799 glScissor(pRect->left, winHeight - pRect->bottom, pRect->right - pRect->left, pRect->bottom - pRect->top);
2800 checkGLcall("glScissor");
2806 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2809 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2810 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2814 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2816 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2818 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2820 This->updateStateBlock->vertexDecl = pDecl;
2821 This->updateStateBlock->changed.vertexDecl = TRUE;
2822 This->updateStateBlock->set.vertexDecl = TRUE;
2824 if (This->isRecordingState) {
2825 TRACE("Recording... not performing anything\n");
2827 } else if(pDecl == oldDecl) {
2828 /* Checked after the assignment to allow proper stateblock recording */
2829 TRACE("Application is setting the old declaration over, nothing to do\n");
2833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2837 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2840 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2842 *ppDecl = This->stateBlock->vertexDecl;
2843 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2847 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2851 This->updateStateBlock->vertexShader = pShader;
2852 This->updateStateBlock->changed.vertexShader = TRUE;
2853 This->updateStateBlock->set.vertexShader = TRUE;
2855 if (This->isRecordingState) {
2856 TRACE("Recording... not performing anything\n");
2858 } else if(oldShader == pShader) {
2859 /* Checked here to allow proper stateblock recording */
2860 TRACE("App is setting the old shader over, nothing to do\n");
2864 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
2871 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
2872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2874 if (NULL == ppShader) {
2875 return WINED3DERR_INVALIDCALL;
2877 *ppShader = This->stateBlock->vertexShader;
2878 if( NULL != *ppShader)
2879 IWineD3DVertexShader_AddRef(*ppShader);
2881 TRACE("(%p) : returning %p\n", This, *ppShader);
2885 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
2886 IWineD3DDevice *iface,
2888 CONST BOOL *srcData,
2891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2892 int i, cnt = min(count, MAX_CONST_B - start);
2894 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2895 iface, srcData, start, count);
2897 if (srcData == NULL || cnt < 0)
2898 return WINED3DERR_INVALIDCALL;
2900 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
2901 for (i = 0; i < cnt; i++)
2902 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
2904 for (i = start; i < cnt + start; ++i) {
2905 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
2906 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
2909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2914 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
2915 IWineD3DDevice *iface,
2920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2921 int cnt = min(count, MAX_CONST_B - start);
2923 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2924 iface, dstData, start, count);
2926 if (dstData == NULL || cnt < 0)
2927 return WINED3DERR_INVALIDCALL;
2929 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
2933 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
2934 IWineD3DDevice *iface,
2939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 int i, cnt = min(count, MAX_CONST_I - start);
2942 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2943 iface, srcData, start, count);
2945 if (srcData == NULL || cnt < 0)
2946 return WINED3DERR_INVALIDCALL;
2948 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
2949 for (i = 0; i < cnt; i++)
2950 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
2951 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
2953 for (i = start; i < cnt + start; ++i) {
2954 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
2955 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
2958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
2963 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
2964 IWineD3DDevice *iface,
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 int cnt = min(count, MAX_CONST_I - start);
2972 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
2973 iface, dstData, start, count);
2975 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
2976 return WINED3DERR_INVALIDCALL;
2978 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
2982 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
2983 IWineD3DDevice *iface,
2985 CONST float *srcData,
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 int i, cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
2991 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
2992 iface, srcData, start, count);
2994 if (srcData == NULL || ((signed int) GL_LIMITS(vshader_constantsF) - (signed int) start) <= (signed int) 0)
2995 return WINED3DERR_INVALIDCALL;
2997 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
2998 for (i = 0; i < cnt; i++)
2999 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3000 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3002 for (i = start; i < cnt + start; ++i) {
3003 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3004 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3006 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3007 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3009 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3017 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3018 IWineD3DDevice *iface,
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3026 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3027 iface, dstData, start, count);
3029 if (dstData == NULL || cnt < 0)
3030 return WINED3DERR_INVALIDCALL;
3032 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3036 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3038 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3043 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3045 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3046 * it is never called.
3049 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3050 * that would be really messy and require shader recompilation
3051 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3052 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3053 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3054 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3056 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3057 if(This->oneToOneTexUnitMap) {
3058 TRACE("Not touching 1:1 map\n");
3061 TRACE("Restoring 1:1 texture unit mapping\n");
3062 /* Restore a 1:1 mapping */
3063 for(i = 0; i < MAX_SAMPLERS; i++) {
3064 if(This->texUnitMap[i] != i) {
3065 This->texUnitMap[i] = i;
3066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3067 markTextureStagesDirty(This, i);
3070 This->oneToOneTexUnitMap = TRUE;
3073 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3074 * First, see if we can succeed at all
3077 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3078 if(This->stateBlock->textures[i] == NULL) tex++;
3081 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3082 FIXME("Too many bound textures to support the combiner settings\n");
3086 /* Now work out the mapping */
3088 This->oneToOneTexUnitMap = FALSE;
3089 WARN("Non 1:1 mapping UNTESTED!\n");
3090 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3091 /* Skip NULL textures */
3092 if (!This->stateBlock->textures[i]) {
3093 /* Map to -1, so the check below doesn't fail if a non-NULL
3094 * texture is set on this stage */
3095 TRACE("Mapping texture stage %d to -1\n", i);
3096 This->texUnitMap[i] = -1;
3101 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3102 if(This->texUnitMap[i] != tex) {
3103 This->texUnitMap[i] = tex;
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3105 markTextureStagesDirty(This, i);
3113 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3115 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3116 This->updateStateBlock->pixelShader = pShader;
3117 This->updateStateBlock->changed.pixelShader = TRUE;
3118 This->updateStateBlock->set.pixelShader = TRUE;
3120 /* Handle recording of state blocks */
3121 if (This->isRecordingState) {
3122 TRACE("Recording... not performing anything\n");
3125 if (This->isRecordingState) {
3126 TRACE("Recording... not performing anything\n");
3130 if(pShader == oldShader) {
3131 TRACE("App is setting the old pixel shader over, nothing to do\n");
3135 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3138 /* Rebuild the texture unit mapping if nvrc's are supported */
3139 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3140 IWineD3DDeviceImpl_FindTexUnitMap(This);
3146 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3149 if (NULL == ppShader) {
3150 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3151 return WINED3DERR_INVALIDCALL;
3154 *ppShader = This->stateBlock->pixelShader;
3155 if (NULL != *ppShader) {
3156 IWineD3DPixelShader_AddRef(*ppShader);
3158 TRACE("(%p) : returning %p\n", This, *ppShader);
3162 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3163 IWineD3DDevice *iface,
3165 CONST BOOL *srcData,
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3169 int i, cnt = min(count, MAX_CONST_B - start);
3171 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3172 iface, srcData, start, count);
3174 if (srcData == NULL || cnt < 0)
3175 return WINED3DERR_INVALIDCALL;
3177 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3178 for (i = 0; i < cnt; i++)
3179 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3181 for (i = start; i < cnt + start; ++i) {
3182 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3183 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3192 IWineD3DDevice *iface,
3197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 int cnt = min(count, MAX_CONST_B - start);
3200 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3201 iface, dstData, start, count);
3203 if (dstData == NULL || cnt < 0)
3204 return WINED3DERR_INVALIDCALL;
3206 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3210 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3211 IWineD3DDevice *iface,
3216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 int i, cnt = min(count, MAX_CONST_I - start);
3219 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3220 iface, srcData, start, count);
3222 if (srcData == NULL || cnt < 0)
3223 return WINED3DERR_INVALIDCALL;
3225 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3226 for (i = 0; i < cnt; i++)
3227 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3228 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3230 for (i = start; i < cnt + start; ++i) {
3231 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3232 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3240 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3241 IWineD3DDevice *iface,
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 int cnt = min(count, MAX_CONST_I - start);
3249 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3250 iface, dstData, start, count);
3252 if (dstData == NULL || cnt < 0)
3253 return WINED3DERR_INVALIDCALL;
3255 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3259 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3260 IWineD3DDevice *iface,
3262 CONST float *srcData,
3265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3266 int i, cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3268 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3269 iface, srcData, start, count);
3271 if (srcData == NULL || cnt < 0)
3272 return WINED3DERR_INVALIDCALL;
3274 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, cnt * sizeof(float) * 4);
3275 for (i = 0; i < cnt; i++)
3276 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3277 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3279 for (i = start; i < cnt + start; ++i) {
3280 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3281 constant_entry *ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(constant_entry));
3283 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3284 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3286 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3294 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3295 IWineD3DDevice *iface,
3300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3303 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3304 iface, dstData, start, count);
3306 if (dstData == NULL || cnt < 0)
3307 return WINED3DERR_INVALIDCALL;
3309 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3313 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3315 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, DWORD SrcFVF, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3316 char *dest_ptr, *dest_conv = NULL;
3318 DWORD DestFVF = dest->fvf;
3320 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3324 if (SrcFVF & WINED3DFVF_NORMAL) {
3325 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3328 if ( (SrcFVF & WINED3DFVF_POSITION_MASK) != WINED3DFVF_XYZ) {
3329 ERR("Source has no position mask\n");
3330 return WINED3DERR_INVALIDCALL;
3333 /* We might access VBOs from this code, so hold the lock */
3336 if (dest->resource.allocatedMemory == NULL) {
3337 /* This may happen if we do direct locking into a vbo. Unlikely,
3338 * but theoretically possible(ddraw processvertices test)
3340 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3341 if(!dest->resource.allocatedMemory) {
3343 ERR("Out of memory\n");
3344 return E_OUTOFMEMORY;
3348 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3349 checkGLcall("glBindBufferARB");
3350 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3352 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3354 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3355 checkGLcall("glUnmapBufferARB");
3359 /* Get a pointer into the destination vbo(create one if none exists) and
3360 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3362 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3367 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3368 dest_conv = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB));
3370 ERR("glMapBuffer failed\n");
3371 /* Continue without storing converted vertices */
3376 * a) WINED3DRS_CLIPPING is enabled
3377 * b) WINED3DVOP_CLIP is passed
3379 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3380 static BOOL warned = FALSE;
3382 * The clipping code is not quite correct. Some things need
3383 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3384 * so disable clipping for now.
3385 * (The graphics in Half-Life are broken, and my processvertices
3386 * test crashes with IDirect3DDevice3)
3392 FIXME("Clipping is broken and disabled for now\n");
3394 } else doClip = FALSE;
3395 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3397 dest_conv = ((char *) dest_conv) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3400 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3403 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3404 WINED3DTS_PROJECTION,
3406 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3407 WINED3DTS_WORLDMATRIX(0),
3410 TRACE("View mat:\n");
3411 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);
3412 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);
3413 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);
3414 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);
3416 TRACE("Proj mat:\n");
3417 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);
3418 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);
3419 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);
3420 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);
3422 TRACE("World mat:\n");
3423 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);
3424 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);
3425 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);
3426 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);
3428 /* Get the viewport */
3429 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3430 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3431 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3433 multiply_matrix(&mat,&view_mat,&world_mat);
3434 multiply_matrix(&mat,&proj_mat,&mat);
3436 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3438 for (i = 0; i < dwCount; i+= 1) {
3439 unsigned int tex_index;
3441 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3442 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3443 /* The position first */
3445 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3447 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3449 /* Multiplication with world, view and projection matrix */
3450 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);
3451 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);
3452 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);
3453 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);
3455 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3457 /* WARNING: The following things are taken from d3d7 and were not yet checked
3458 * against d3d8 or d3d9!
3461 /* Clipping conditions: From
3462 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3464 * A vertex is clipped if it does not match the following requirements
3468 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3470 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3471 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3476 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3477 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3480 /* "Normal" viewport transformation (not clipped)
3481 * 1) The values are divided by rhw
3482 * 2) The y axis is negative, so multiply it with -1
3483 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3484 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3485 * 4) Multiply x with Width/2 and add Width/2
3486 * 5) The same for the height
3487 * 6) Add the viewpoint X and Y to the 2D coordinates and
3488 * The minimum Z value to z
3489 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3491 * Well, basically it's simply a linear transformation into viewport
3503 z *= vp.MaxZ - vp.MinZ;
3505 x += vp.Width / 2 + vp.X;
3506 y += vp.Height / 2 + vp.Y;
3511 /* That vertex got clipped
3512 * Contrary to OpenGL it is not dropped completely, it just
3513 * undergoes a different calculation.
3515 TRACE("Vertex got clipped\n");
3522 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3523 * outside of the main vertex buffer memory. That needs some more
3528 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3531 ( (float *) dest_ptr)[0] = x;
3532 ( (float *) dest_ptr)[1] = y;
3533 ( (float *) dest_ptr)[2] = z;
3534 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3536 dest_ptr += 3 * sizeof(float);
3538 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3539 dest_ptr += sizeof(float);
3544 ( (float *) dest_conv)[0] = x * w;
3545 ( (float *) dest_conv)[1] = y * w;
3546 ( (float *) dest_conv)[2] = z * w;
3547 ( (float *) dest_conv)[3] = w;
3549 dest_conv += 3 * sizeof(float);
3551 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3552 dest_conv += sizeof(float);
3556 if (DestFVF & WINED3DFVF_PSIZE) {
3557 dest_ptr += sizeof(DWORD);
3558 if(dest_conv) dest_conv += sizeof(DWORD);
3560 if (DestFVF & WINED3DFVF_NORMAL) {
3562 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3563 /* AFAIK this should go into the lighting information */
3564 FIXME("Didn't expect the destination to have a normal\n");
3565 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3567 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3571 if (DestFVF & WINED3DFVF_DIFFUSE) {
3573 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3575 static BOOL warned = FALSE;
3578 ERR("No diffuse color in source, but destination has one\n");
3582 *( (DWORD *) dest_ptr) = 0xffffffff;
3583 dest_ptr += sizeof(DWORD);
3586 *( (DWORD *) dest_conv) = 0xffffffff;
3587 dest_conv += sizeof(DWORD);
3591 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3593 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3594 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3595 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3596 dest_conv += sizeof(DWORD);
3601 if (DestFVF & WINED3DFVF_SPECULAR) {
3602 /* What's the color value in the feedback buffer? */
3604 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3606 static BOOL warned = FALSE;
3609 ERR("No specular color in source, but destination has one\n");
3613 *( (DWORD *) dest_ptr) = 0xFF000000;
3614 dest_ptr += sizeof(DWORD);
3617 *( (DWORD *) dest_conv) = 0xFF000000;
3618 dest_conv += sizeof(DWORD);
3622 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3624 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3625 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3626 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3627 dest_conv += sizeof(DWORD);
3632 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3634 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3635 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3637 ERR("No source texture, but destination requests one\n");
3638 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3639 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3642 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3644 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3651 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3652 checkGLcall("glUnmapBufferARB(GL_ARRAY_BUFFER_ARB)");
3659 #undef copy_and_next
3661 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexBuffer* pVertexDecl, DWORD Flags) {
3662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3663 IWineD3DVertexBufferImpl *SrcImpl = (IWineD3DVertexBufferImpl *) pVertexDecl;
3664 WineDirect3DVertexStridedData strided;
3665 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3668 WARN("NULL source vertex buffer\n");
3669 return WINED3DERR_INVALIDCALL;
3671 /* We don't need the source vbo because this buffer is only used as
3672 * a source for ProcessVertices. Avoid wasting resources by converting the
3673 * buffer and loading the VBO
3676 TRACE("Releasing the source vbo, it won't be needed\n");
3678 if(!SrcImpl->resource.allocatedMemory) {
3679 /* Rescue the data from the buffer */
3681 SrcImpl->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, SrcImpl->resource.size);
3682 if(!SrcImpl->resource.allocatedMemory) {
3683 ERR("Out of memory\n");
3684 return E_OUTOFMEMORY;
3688 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, SrcImpl->vbo));
3689 checkGLcall("glBindBufferARB");
3691 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3693 memcpy(SrcImpl->resource.allocatedMemory, src, SrcImpl->resource.size);
3696 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3697 checkGLcall("glUnmapBufferARB");
3702 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0));
3703 checkGLcall("glBindBufferARB");
3704 GL_EXTCALL(glDeleteBuffersARB(1, &SrcImpl->vbo));
3705 checkGLcall("glDeleteBuffersARB");
3711 memset(&strided, 0, sizeof(strided));
3712 primitiveConvertFVFtoOffset(SrcImpl->fvf, get_flexible_vertex_size(SrcImpl->fvf), SrcImpl->resource.allocatedMemory + get_flexible_vertex_size(SrcImpl->fvf) * SrcStartIndex, &strided, 0, 0);
3714 return process_vertices_strided(This, DestIndex, VertexCount, &strided, SrcImpl->fvf, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3718 * Get / Set Texture Stage States
3719 * TODO: Verify against dx9 definitions
3721 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3723 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3725 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3727 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3729 /* Reject invalid texture units */
3730 if (Stage >= GL_LIMITS(texture_stages)) {
3731 TRACE("Attempt to access invalid texture rejected\n");
3732 return WINED3DERR_INVALIDCALL;
3735 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3736 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3737 This->updateStateBlock->textureState[Stage][Type] = Value;
3739 if (This->isRecordingState) {
3740 TRACE("Recording... not performing anything\n");
3744 /* Checked after the assignments to allow proper stateblock recording */
3745 if(oldValue == Value) {
3746 TRACE("App is setting the old value over, nothing to do\n");
3750 if(Stage > This->stateBlock->lowest_disabled_stage &&
3751 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3752 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3753 * Changes in other states are important on disabled stages too
3758 if(Type == WINED3DTSS_COLOROP) {
3761 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3762 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3763 * they have to be disabled
3765 * The current stage is dirtified below.
3767 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3768 TRACE("Additionally dirtifying stage %d\n", i);
3769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3771 This->stateBlock->lowest_disabled_stage = Stage;
3772 TRACE("New lowest disabled: %d\n", Stage);
3773 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3774 /* Previously disabled stage enabled. Stages above it may need enabling
3775 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3776 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3778 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3781 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3782 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3785 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3788 This->stateBlock->lowest_disabled_stage = i;
3789 TRACE("New lowest disabled: %d\n", i);
3791 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3792 /* TODO: Built a stage -> texture unit mapping for register combiners */
3796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3798 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3799 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3800 * will call FindTexUnitMap too.
3802 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3803 IWineD3DDeviceImpl_FindTexUnitMap(This);
3808 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
3809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3810 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
3811 *pValue = This->updateStateBlock->textureState[Stage][Type];
3818 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
3820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3821 IWineD3DBaseTexture *oldTexture;
3823 oldTexture = This->updateStateBlock->textures[Stage];
3824 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
3826 #if 0 /* TODO: check so vertex textures */
3827 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
3828 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
3833 /* Reject invalid texture units */
3834 if (Stage >= GL_LIMITS(sampler_stages) || Stage < 0) {
3835 WARN("Attempt to access invalid texture rejected\n");
3836 return WINED3DERR_INVALIDCALL;
3839 if(pTexture != NULL) {
3840 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
3842 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
3843 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
3844 return WINED3DERR_INVALIDCALL;
3846 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
3849 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
3850 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
3852 This->updateStateBlock->set.textures[Stage] = TRUE;
3853 This->updateStateBlock->changed.textures[Stage] = TRUE;
3854 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
3855 This->updateStateBlock->textures[Stage] = pTexture;
3857 /* Handle recording of state blocks */
3858 if (This->isRecordingState) {
3859 TRACE("Recording... not performing anything\n");
3863 if(oldTexture == pTexture) {
3864 TRACE("App is setting the same texture again, nothing to do\n");
3868 /** NOTE: MSDN says that setTexture increases the reference count,
3869 * and the the application nust set the texture back to null (or have a leaky application),
3870 * This means we should pass the refcount up to the parent
3871 *******************************/
3872 if (NULL != This->updateStateBlock->textures[Stage]) {
3873 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
3874 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
3876 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
3877 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
3878 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
3879 * so the COLOROP and ALPHAOP have to be dirtified.
3881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3884 if(bindCount == 1) {
3885 new->baseTexture.sampler = Stage;
3887 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
3891 if (NULL != oldTexture) {
3892 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
3893 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
3895 IWineD3DBaseTexture_Release(oldTexture);
3896 if(pTexture == NULL && Stage < MAX_TEXTURES) {
3897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
3898 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
3901 if(bindCount && old->baseTexture.sampler == Stage) {
3903 /* Have to do a search for the other sampler(s) where the texture is bound to
3904 * Shouldn't happen as long as apps bind a texture only to one stage
3906 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
3907 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
3908 if(This->updateStateBlock->textures[i] == oldTexture) {
3909 old->baseTexture.sampler = i;
3916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
3918 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
3919 * pixel shader is used
3921 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3922 IWineD3DDeviceImpl_FindTexUnitMap(This);
3928 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
3929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3930 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
3932 /* Reject invalid texture units */
3933 if (Stage >= GL_LIMITS(sampler_stages)) {
3934 TRACE("Attempt to access invalid texture rejected\n");
3935 return WINED3DERR_INVALIDCALL;
3937 *ppTexture=This->stateBlock->textures[Stage];
3939 IWineD3DBaseTexture_AddRef(*ppTexture);
3947 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
3948 IWineD3DSurface **ppBackBuffer) {
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 IWineD3DSwapChain *swapChain;
3953 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
3955 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
3956 if (hr == WINED3D_OK) {
3957 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
3958 IWineD3DSwapChain_Release(swapChain);
3960 *ppBackBuffer = NULL;
3965 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
3966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3967 WARN("(%p) : stub, calling idirect3d for now\n", This);
3968 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
3971 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
3972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3973 IWineD3DSwapChain *swapChain;
3976 if(iSwapChain > 0) {
3977 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
3978 if (hr == WINED3D_OK) {
3979 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
3980 IWineD3DSwapChain_Release(swapChain);
3982 FIXME("(%p) Error getting display mode\n", This);
3985 /* Don't read the real display mode,
3986 but return the stored mode instead. X11 can't change the color
3987 depth, and some apps are pretty angry if they SetDisplayMode from
3988 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
3990 Also don't relay to the swapchain because with ddraw it's possible
3991 that there isn't a swapchain at all */
3992 pMode->Width = This->ddraw_width;
3993 pMode->Height = This->ddraw_height;
3994 pMode->Format = This->ddraw_format;
3995 pMode->RefreshRate = 0;
4002 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4004 TRACE("(%p)->(%p)\n", This, hWnd);
4006 if(This->ddraw_fullscreen) {
4007 if(This->ddraw_window && This->ddraw_window != hWnd) {
4008 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4010 if(hWnd && This->ddraw_window != hWnd) {
4011 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4015 This->ddraw_window = hWnd;
4019 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4021 TRACE("(%p)->(%p)\n", This, hWnd);
4023 *hWnd = This->ddraw_window;
4028 * Stateblock related functions
4031 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4033 IWineD3DStateBlockImpl *object;
4034 HRESULT temp_result;
4037 TRACE("(%p)\n", This);
4039 if (This->isRecordingState) {
4040 return WINED3DERR_INVALIDCALL;
4043 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4044 if (NULL == object ) {
4045 FIXME("(%p)Error allocating memory for stateblock\n", This);
4046 return E_OUTOFMEMORY;
4048 TRACE("(%p) created object %p\n", This, object);
4049 object->wineD3DDevice= This;
4050 /** FIXME: object->parent = parent; **/
4051 object->parent = NULL;
4052 object->blockType = WINED3DSBT_ALL;
4054 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4056 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4057 list_init(&object->lightMap[i]);
4060 temp_result = allocate_shader_constants(object);
4061 if (WINED3D_OK != temp_result)
4064 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4065 This->updateStateBlock = object;
4066 This->isRecordingState = TRUE;
4068 TRACE("(%p) recording stateblock %p\n",This , object);
4072 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4075 if (!This->isRecordingState) {
4076 FIXME("(%p) not recording! returning error\n", This);
4077 *ppStateBlock = NULL;
4078 return WINED3DERR_INVALIDCALL;
4081 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4082 This->isRecordingState = FALSE;
4083 This->updateStateBlock = This->stateBlock;
4084 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4085 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4086 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4091 * Scene related functions
4093 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4094 /* At the moment we have no need for any functionality at the beginning
4096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4097 TRACE("(%p)\n", This);
4100 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4101 return WINED3DERR_INVALIDCALL;
4103 This->inScene = TRUE;
4107 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4109 TRACE("(%p)\n", This);
4111 if(!This->inScene) {
4112 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4113 return WINED3DERR_INVALIDCALL;
4117 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4119 checkGLcall("glFlush");
4122 This->inScene = FALSE;
4126 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4127 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4128 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4130 IWineD3DSwapChain *swapChain = NULL;
4132 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4134 TRACE("(%p) Presenting the frame\n", This);
4136 for(i = 0 ; i < swapchains ; i ++) {
4138 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4139 TRACE("presentinng chain %d, %p\n", i, swapChain);
4140 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4141 IWineD3DSwapChain_Release(swapChain);
4147 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4148 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4151 /* TODO: From MSDN This method fails if you specify the WINED3DCLEAR_ZBUFFER or WINED3DCLEAR_STENCIL flags when the
4152 render target does not have an attached depth buffer. Similarly, if you specify the WINED3DCLEAR_STENCIL flag
4153 when the depth-buffer format does not contain stencil buffer information, this method fails. */
4154 GLbitfield glMask = 0;
4155 GLboolean old_ztest;
4156 GLfloat old_z_clear_value;
4157 GLint old_stencil_clear_value;
4158 GLfloat old_color_clear_value[4];
4160 CONST WINED3DRECT* curRect;
4162 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Z (%f), Stencil (%d)\n", This,
4163 Count, pRects, Flags, Z, Stencil);
4167 glEnable(GL_SCISSOR_TEST);
4168 checkGLcall("glEnable GL_SCISSOR_TEST");
4170 if (Count > 0 && pRects) {
4176 /* Only set the values up once, as they are not changing */
4177 if (Flags & WINED3DCLEAR_STENCIL) {
4178 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &old_stencil_clear_value);
4179 glClearStencil(Stencil);
4180 checkGLcall("glClearStencil");
4181 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4182 glStencilMask(0xFFFFFFFF);
4185 if (Flags & WINED3DCLEAR_ZBUFFER) {
4186 glGetBooleanv(GL_DEPTH_WRITEMASK, &old_ztest);
4187 glDepthMask(GL_TRUE);
4188 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &old_z_clear_value);
4190 checkGLcall("glClearDepth");
4191 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4194 if (Flags & WINED3DCLEAR_TARGET) {
4195 TRACE("Clearing screen with glClear to color %x\n", Color);
4196 glGetFloatv(GL_COLOR_CLEAR_VALUE, old_color_clear_value);
4197 glClearColor(D3DCOLOR_R(Color),
4201 checkGLcall("glClearColor");
4203 /* Clear ALL colors! */
4204 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4205 glMask = glMask | GL_COLOR_BUFFER_BIT;
4208 /* Now process each rect in turn */
4209 for (i = 0; i < Count || i == 0; i++) {
4212 /* Note gl uses lower left, width/height */
4213 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4214 curRect->x1, curRect->y1, curRect->x2, curRect->y2,
4215 curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4216 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4217 glScissor(curRect->x1, (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height - curRect->y2),
4218 curRect->x2 - curRect->x1, curRect->y2 - curRect->y1);
4219 checkGLcall("glScissor");
4221 glScissor(This->stateBlock->viewport.X,
4222 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4223 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4224 This->stateBlock->viewport.Width,
4225 This->stateBlock->viewport.Height);
4226 checkGLcall("glScissor");
4229 /* Clear the selected rectangle (or full screen) */
4231 checkGLcall("glClear");
4233 /* Step to the next rectangle */
4234 if (curRect) curRect = curRect + sizeof(WINED3DRECT);
4237 /* Restore the old values (why..?) */
4238 if (Flags & WINED3DCLEAR_STENCIL) {
4239 glClearStencil(old_stencil_clear_value);
4240 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4242 if (Flags & WINED3DCLEAR_ZBUFFER) {
4243 glDepthMask(old_ztest);
4244 glClearDepth(old_z_clear_value);
4246 if (Flags & WINED3DCLEAR_TARGET) {
4247 glClearColor(old_color_clear_value[0],
4248 old_color_clear_value[1],
4249 old_color_clear_value[2],
4250 old_color_clear_value[3]);
4251 glColorMask(This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4252 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4253 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4254 This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE] & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4257 glDisable(GL_SCISSOR_TEST);
4258 checkGLcall("glDisable");
4267 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4268 UINT PrimitiveCount) {
4270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4271 This->stateBlock->streamIsUP = FALSE;
4273 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4274 debug_d3dprimitivetype(PrimitiveType),
4275 StartVertex, PrimitiveCount);
4277 if(This->stateBlock->loadBaseVertexIndex != 0) {
4278 This->stateBlock->loadBaseVertexIndex = 0;
4279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4281 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4282 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4283 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4287 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4288 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4289 WINED3DPRIMITIVETYPE PrimitiveType,
4290 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4294 IWineD3DIndexBuffer *pIB;
4295 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4297 pIB = This->stateBlock->pIndexData;
4298 This->stateBlock->streamIsUP = FALSE;
4300 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4301 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4302 minIndex, NumVertices, startIndex, primCount);
4304 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4305 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4311 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4312 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4316 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4317 idxStride, ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4322 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4323 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4324 UINT VertexStreamZeroStride) {
4325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4327 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4328 debug_d3dprimitivetype(PrimitiveType),
4329 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4331 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4332 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4333 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4334 This->stateBlock->streamIsUP = TRUE;
4335 This->stateBlock->loadBaseVertexIndex = 0;
4337 /* TODO: Only mark dirty if drawing from a different UP address */
4338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4340 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4341 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4343 /* MSDN specifies stream zero settings must be set to NULL */
4344 This->stateBlock->streamStride[0] = 0;
4345 This->stateBlock->streamSource[0] = NULL;
4347 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4348 * the new stream sources or use UP drawing again
4353 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4354 UINT MinVertexIndex, UINT NumVertices,
4355 UINT PrimitiveCount, CONST void* pIndexData,
4356 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4357 UINT VertexStreamZeroStride) {
4359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4361 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4362 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4363 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4364 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4366 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4372 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4373 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4374 This->stateBlock->streamIsUP = TRUE;
4375 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4377 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4378 This->stateBlock->baseVertexIndex = 0;
4379 This->stateBlock->loadBaseVertexIndex = 0;
4380 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4383 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4385 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4386 This->stateBlock->streamSource[0] = NULL;
4387 This->stateBlock->streamStride[0] = 0;
4388 This->stateBlock->pIndexData = NULL;
4389 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4390 * SetStreamSource to specify a vertex buffer
4396 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4399 /* Mark the state dirty until we have nicer tracking
4400 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4403 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4404 This->stateBlock->baseVertexIndex = 0;
4405 This->up_strided = DrawPrimStrideData;
4406 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4407 This->up_strided = NULL;
4410 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4411 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4413 HRESULT hr = WINED3D_OK;
4414 WINED3DRESOURCETYPE sourceType;
4415 WINED3DRESOURCETYPE destinationType;
4418 /* TODO: think about moving the code into IWineD3DBaseTexture */
4420 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4422 /* verify that the source and destination textures aren't NULL */
4423 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4424 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4425 This, pSourceTexture, pDestinationTexture);
4426 hr = WINED3DERR_INVALIDCALL;
4429 if (pSourceTexture == pDestinationTexture) {
4430 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4431 This, pSourceTexture, pDestinationTexture);
4432 hr = WINED3DERR_INVALIDCALL;
4434 /* Verify that the source and destination textures are the same type */
4435 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4436 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4438 if (sourceType != destinationType) {
4439 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4441 hr = WINED3DERR_INVALIDCALL;
4444 /* check that both textures have the identical numbers of levels */
4445 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4446 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4447 hr = WINED3DERR_INVALIDCALL;
4450 if (WINED3D_OK == hr) {
4452 /* Make sure that the destination texture is loaded */
4453 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4455 /* Update every surface level of the texture */
4456 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4458 switch (sourceType) {
4459 case WINED3DRTYPE_TEXTURE:
4461 IWineD3DSurface *srcSurface;
4462 IWineD3DSurface *destSurface;
4464 for (i = 0 ; i < levels ; ++i) {
4465 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4466 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4467 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4468 IWineD3DSurface_Release(srcSurface);
4469 IWineD3DSurface_Release(destSurface);
4470 if (WINED3D_OK != hr) {
4471 WARN("(%p) : Call to update surface failed\n", This);
4477 case WINED3DRTYPE_CUBETEXTURE:
4479 IWineD3DSurface *srcSurface;
4480 IWineD3DSurface *destSurface;
4481 WINED3DCUBEMAP_FACES faceType;
4483 for (i = 0 ; i < levels ; ++i) {
4484 /* Update each cube face */
4485 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4486 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4487 if (WINED3D_OK != hr) {
4488 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4490 TRACE("Got srcSurface %p\n", srcSurface);
4492 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4493 if (WINED3D_OK != hr) {
4494 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4496 TRACE("Got desrSurface %p\n", destSurface);
4498 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4499 IWineD3DSurface_Release(srcSurface);
4500 IWineD3DSurface_Release(destSurface);
4501 if (WINED3D_OK != hr) {
4502 WARN("(%p) : Call to update surface failed\n", This);
4509 #if 0 /* TODO: Add support for volume textures */
4510 case WINED3DRTYPE_VOLUMETEXTURE:
4512 IWineD3DVolume srcVolume = NULL;
4513 IWineD3DSurface destVolume = NULL;
4515 for (i = 0 ; i < levels ; ++i) {
4516 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4517 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4518 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4519 IWineD3DVolume_Release(srcSurface);
4520 IWineD3DVolume_Release(destSurface);
4521 if (WINED3D_OK != hr) {
4522 WARN("(%p) : Call to update volume failed\n", This);
4530 FIXME("(%p) : Unsupported source and destination type\n", This);
4531 hr = WINED3DERR_INVALIDCALL;
4538 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4539 IWineD3DSwapChain *swapChain;
4541 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4542 if(hr == WINED3D_OK) {
4543 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4544 IWineD3DSwapChain_Release(swapChain);
4549 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4551 /* return a sensible default */
4553 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4554 FIXME("(%p) : stub\n", This);
4558 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4561 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4562 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4563 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4564 return WINED3DERR_INVALIDCALL;
4566 for (j = 0; j < 256; ++j) {
4567 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4568 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4569 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4570 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4572 TRACE("(%p) : returning\n", This);
4576 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4580 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4581 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4582 return WINED3DERR_INVALIDCALL;
4584 for (j = 0; j < 256; ++j) {
4585 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4586 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4587 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4588 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4590 TRACE("(%p) : returning\n", This);
4594 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4596 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4597 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4598 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4599 return WINED3DERR_INVALIDCALL;
4601 /*TODO: stateblocks */
4602 This->currentPalette = PaletteNumber;
4603 TRACE("(%p) : returning\n", This);
4607 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4609 if (PaletteNumber == NULL) {
4610 WARN("(%p) : returning Invalid Call\n", This);
4611 return WINED3DERR_INVALIDCALL;
4613 /*TODO: stateblocks */
4614 *PaletteNumber = This->currentPalette;
4615 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4619 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4621 static BOOL showFixmes = TRUE;
4623 FIXME("(%p) : stub\n", This);
4627 This->softwareVertexProcessing = bSoftware;
4632 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4634 static BOOL showFixmes = TRUE;
4636 FIXME("(%p) : stub\n", This);
4639 return This->softwareVertexProcessing;
4643 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 IWineD3DSwapChain *swapChain;
4648 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4650 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4651 if(hr == WINED3D_OK){
4652 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4653 IWineD3DSwapChain_Release(swapChain);
4655 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4661 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 static BOOL showfixmes = TRUE;
4664 if(nSegments != 0.0f) {
4666 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4673 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 static BOOL showfixmes = TRUE;
4677 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4683 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4685 /** TODO: remove casts to IWineD3DSurfaceImpl
4686 * NOTE: move code to surface to accomplish this
4687 ****************************************/
4688 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4689 int srcWidth, srcHeight;
4690 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4691 WINED3DFORMAT destFormat, srcFormat;
4693 int srcLeft, destLeft, destTop;
4694 WINED3DPOOL srcPool, destPool;
4696 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4697 glDescriptor *glDescription = NULL;
4698 GLenum textureDimensions = GL_TEXTURE_2D;
4699 IWineD3DBaseTexture *baseTexture;
4701 WINED3DSURFACE_DESC winedesc;
4703 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4704 memset(&winedesc, 0, sizeof(winedesc));
4705 winedesc.Width = &srcSurfaceWidth;
4706 winedesc.Height = &srcSurfaceHeight;
4707 winedesc.Pool = &srcPool;
4708 winedesc.Format = &srcFormat;
4710 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4712 winedesc.Width = &destSurfaceWidth;
4713 winedesc.Height = &destSurfaceHeight;
4714 winedesc.Pool = &destPool;
4715 winedesc.Format = &destFormat;
4716 winedesc.Size = &destSize;
4718 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4720 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4721 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4722 return WINED3DERR_INVALIDCALL;
4725 if (destFormat == WINED3DFMT_UNKNOWN) {
4726 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4727 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4729 /* Get the update surface description */
4730 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4733 /* Make sure the surface is loaded and up to date */
4734 IWineD3DSurface_PreLoad(pDestinationSurface);
4736 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4740 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4741 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4742 srcHeight = pSourceRect ? pSourceRect->top - pSourceRect->bottom : srcSurfaceHeight;
4743 srcLeft = pSourceRect ? pSourceRect->left : 0;
4744 destLeft = pDestPoint ? pDestPoint->x : 0;
4745 destTop = pDestPoint ? pDestPoint->y : 0;
4748 /* This function doesn't support compressed textures
4749 the pitch is just bytesPerPixel * width */
4750 if(srcWidth != srcSurfaceWidth || srcLeft ){
4751 rowoffset = (srcSurfaceWidth - srcWidth) * pSrcSurface->bytesPerPixel;
4752 offset += srcLeft * pSrcSurface->bytesPerPixel;
4753 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
4755 /* TODO DXT formats */
4757 if(pSourceRect != NULL && pSourceRect->top != 0){
4758 offset += pSourceRect->top * srcWidth * pSrcSurface->bytesPerPixel;
4760 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
4762 ,glDescription->level
4767 ,glDescription->glFormat
4768 ,glDescription->glType
4769 ,IWineD3DSurface_GetData(pSourceSurface)
4773 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
4775 /* need to lock the surface to get the data */
4776 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
4779 /* TODO: Cube and volume support */
4781 /* not a whole row so we have to do it a line at a time */
4784 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
4785 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
4787 for(j = destTop ; j < (srcHeight + destTop) ; j++){
4789 glTexSubImage2D(glDescription->target
4790 ,glDescription->level
4795 ,glDescription->glFormat
4796 ,glDescription->glType
4797 ,data /* could be quicker using */
4802 } else { /* Full width, so just write out the whole texture */
4804 if (WINED3DFMT_DXT1 == destFormat ||
4805 WINED3DFMT_DXT2 == destFormat ||
4806 WINED3DFMT_DXT3 == destFormat ||
4807 WINED3DFMT_DXT4 == destFormat ||
4808 WINED3DFMT_DXT5 == destFormat) {
4809 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
4810 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
4811 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
4812 FIXME("Updating part of a compressed texture is not supported at the moment\n");
4813 } if (destFormat != srcFormat) {
4814 FIXME("Updating mixed format compressed texture is not curretly support\n");
4816 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
4817 glDescription->level,
4818 glDescription->glFormatInternal,
4823 IWineD3DSurface_GetData(pSourceSurface));
4826 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
4831 glTexSubImage2D(glDescription->target
4832 ,glDescription->level
4837 ,glDescription->glFormat
4838 ,glDescription->glType
4839 ,IWineD3DSurface_GetData(pSourceSurface)
4843 checkGLcall("glTexSubImage2D");
4844 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_GLDIRTY;
4846 /* I only need to look up baseTexture here, so it may be a good idea to hava a GL_TARGET ->
4847 * GL_DIMENSIONS lookup, or maybe store the dimensions on the surface (but that's making the
4848 * surface bigger than it needs to be hmm.. */
4849 if (WINED3D_OK == IWineD3DSurface_GetContainer(pDestinationSurface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)) {
4850 textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(baseTexture);
4851 IWineD3DBaseTexture_Release(baseTexture);
4854 glDisable(textureDimensions); /* This needs to be managed better.... */
4860 /* Implementation details at http://developer.nvidia.com/attach/6494
4862 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
4863 hmm.. no longer supported use
4864 OpenGL evaluators or tessellate surfaces within your application.
4867 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
4868 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
4869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4870 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
4871 FIXME("(%p) : Stub\n", This);
4876 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
4877 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
4878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4879 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
4880 FIXME("(%p) : Stub\n", This);
4884 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
4885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4886 TRACE("(%p) Handle(%d)\n", This, Handle);
4887 FIXME("(%p) : Stub\n", This);
4891 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
4892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4893 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
4895 TRACE("(%p) Colour fill Surface: %p rect: %p color: %d\n", This, pSurface, pRect, color);
4897 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
4898 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
4899 return WINED3DERR_INVALIDCALL;
4902 /* Just forward this to the DirectDraw blitting engine */
4903 memset(&BltFx, 0, sizeof(BltFx));
4904 BltFx.dwSize = sizeof(BltFx);
4905 BltFx.u5.dwFillColor = color;
4906 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, DDBLT_COLORFILL, &BltFx);
4909 /* rendertarget and deptth stencil functions */
4910 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
4911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4913 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
4914 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
4915 return WINED3DERR_INVALIDCALL;
4918 *ppRenderTarget = This->render_targets[RenderTargetIndex];
4919 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
4920 /* Note inc ref on returned surface */
4921 if(*ppRenderTarget != NULL)
4922 IWineD3DSurface_AddRef(*ppRenderTarget);
4926 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
4927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4928 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
4929 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
4930 IWineD3DSwapChainImpl *Swapchain;
4933 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
4935 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
4936 if(hr != WINED3D_OK) {
4937 ERR("Can't get the swapchain\n");
4941 /* Make sure to release the swapchain */
4942 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
4944 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4945 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4946 return WINED3DERR_INVALIDCALL;
4948 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
4949 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
4950 return WINED3DERR_INVALIDCALL;
4953 if(Swapchain->frontBuffer != Front) {
4954 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
4956 if(Swapchain->frontBuffer)
4957 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
4958 Swapchain->frontBuffer = Front;
4960 if(Swapchain->frontBuffer) {
4961 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
4965 if(Back && !Swapchain->backBuffer) {
4966 /* We need memory for the back buffer array - only one back buffer this way */
4967 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
4968 if(!Swapchain->backBuffer) {
4969 ERR("Out of memory\n");
4970 return E_OUTOFMEMORY;
4974 if(Swapchain->backBuffer[0] != Back) {
4975 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
4977 if(!Swapchain->backBuffer[0]) {
4978 /* GL was told to draw to the front buffer at creation,
4981 glDrawBuffer(GL_BACK);
4982 checkGLcall("glDrawBuffer(GL_BACK)");
4983 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
4984 Swapchain->presentParms.BackBufferCount = 1;
4986 /* That makes problems - disable for now */
4987 /* glDrawBuffer(GL_FRONT); */
4988 checkGLcall("glDrawBuffer(GL_FRONT)");
4989 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
4990 Swapchain->presentParms.BackBufferCount = 0;
4994 if(Swapchain->backBuffer[0])
4995 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
4996 Swapchain->backBuffer[0] = Back;
4998 if(Swapchain->backBuffer[0]) {
4999 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5001 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5009 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5011 *ppZStencilSurface = This->depthStencilBuffer;
5012 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5014 if(*ppZStencilSurface != NULL) {
5015 /* Note inc ref on returned surface */
5016 IWineD3DSurface_AddRef(*ppZStencilSurface);
5021 static void bind_fbo(IWineD3DDevice *iface) {
5022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5025 GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
5026 checkGLcall("glGenFramebuffersEXT()");
5028 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
5029 checkGLcall("glBindFramebuffer()");
5032 /* TODO: Handle stencil attachments */
5033 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5035 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5037 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5041 if (depth_stencil_impl) {
5042 GLenum texttarget, target;
5043 GLint old_binding = 0;
5045 IWineD3DSurface_PreLoad(depth_stencil);
5046 texttarget = depth_stencil_impl->glDescription.target;
5047 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5049 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5050 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
5051 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5052 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5053 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5054 glBindTexture(target, old_binding);
5056 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5057 checkGLcall("glFramebufferTexture2DEXT()");
5059 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5060 checkGLcall("glFramebufferTexture2DEXT()");
5063 if (!This->render_offscreen) {
5064 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5065 checkGLcall("glBindFramebuffer()");
5069 void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5071 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5073 if (idx >= GL_LIMITS(buffers)) {
5074 ERR("%p : Trying to set render target %d, but only %d supported\n", This, idx, GL_LIMITS(buffers));
5080 GLenum texttarget, target;
5081 GLint old_binding = 0;
5083 IWineD3DSurface_PreLoad(render_target);
5084 texttarget = rtimpl->glDescription.target;
5085 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5087 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5088 glBindTexture(target, rtimpl->glDescription.textureName);
5089 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5090 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5091 glBindTexture(target, old_binding);
5093 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, rtimpl->glDescription.textureName, 0));
5094 checkGLcall("glFramebufferTexture2DEXT()");
5096 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5098 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5099 checkGLcall("glFramebufferTexture2DEXT()");
5101 This->draw_buffers[idx] = GL_NONE;
5104 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5105 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5106 checkGLcall("glDrawBuffers()");
5109 if (!This->render_offscreen) {
5110 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5111 checkGLcall("glBindFramebuffer()");
5115 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5117 WINED3DVIEWPORT viewport;
5119 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5121 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5122 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5123 return WINED3DERR_INVALIDCALL;
5126 /* MSDN says that null disables the render target
5127 but a device must always be associated with a render target
5128 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5130 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5133 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5134 FIXME("Trying to set render target 0 to NULL\n");
5135 return WINED3DERR_INVALIDCALL;
5137 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5138 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);
5139 return WINED3DERR_INVALIDCALL;
5142 /* If we are trying to set what we already have, don't bother */
5143 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5144 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5147 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5148 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5149 This->render_targets[RenderTargetIndex] = pRenderTarget;
5151 /* Render target 0 is special */
5152 if(RenderTargetIndex == 0) {
5153 /* Finally, reset the viewport as the MSDN states. */
5154 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5155 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5158 viewport.MaxZ = 1.0f;
5159 viewport.MinZ = 0.0f;
5160 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5162 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5164 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5165 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5167 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5169 /* We only get more than 1 render target with fbos, so no need to check the offscreen rendering method */
5170 set_render_target_fbo(iface, RenderTargetIndex, pRenderTarget);
5175 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5177 HRESULT hr = WINED3D_OK;
5178 IWineD3DSurface *tmp;
5180 TRACE("(%p) Swapping z-buffer\n",This);
5182 if (pNewZStencil == This->stencilBufferTarget) {
5183 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5185 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5186 * depending on the renter target implementation being used.
5187 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5188 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5189 * stencil buffer and incure an extra memory overhead
5190 ******************************************************/
5193 tmp = This->stencilBufferTarget;
5194 This->stencilBufferTarget = pNewZStencil;
5195 /* should we be calling the parent or the wined3d surface? */
5196 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5197 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5199 /** TODO: glEnable/glDisable on depth/stencil depending on
5200 * pNewZStencil is NULL and the depth/stencil is enabled in d3d
5201 **********************************************************/
5202 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5203 set_depth_stencil_fbo(iface, pNewZStencil);
5210 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5211 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5213 /* TODO: the use of Impl is deprecated. */
5214 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5216 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5218 /* some basic validation checks */
5219 if(This->cursorTexture) {
5221 glDeleteTextures(1, &This->cursorTexture);
5223 This->cursorTexture = 0;
5227 /* MSDN: Cursor must be A8R8G8B8 */
5228 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5229 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5230 return WINED3DERR_INVALIDCALL;
5233 /* MSDN: Cursor must be smaller than the display mode */
5234 if(pSur->currentDesc.Width > This->ddraw_width ||
5235 pSur->currentDesc.Height > This->ddraw_height) {
5236 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);
5237 return WINED3DERR_INVALIDCALL;
5240 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5241 /* This is to tell our texture code to load a SCRATCH surface. This allows us to use out
5242 * Texture and Blitting code to draw the cursor
5244 pSur->Flags |= SFLAG_FORCELOAD;
5245 IWineD3DSurface_PreLoad(pCursorBitmap);
5246 pSur->Flags &= ~SFLAG_FORCELOAD;
5247 /* Do not store the surface's pointer because the application may release
5248 * it after setting the cursor image. Windows doesn't addref the set surface, so we can't
5249 * do this either without creating circular refcount dependencies. Copy out the gl texture instead.
5251 This->cursorTexture = pSur->glDescription.textureName;
5252 This->cursorWidth = pSur->currentDesc.Width;
5253 This->cursorHeight = pSur->currentDesc.Height;
5254 pSur->glDescription.textureName = 0; /* Prevent the texture from being changed or deleted */
5257 This->xHotSpot = XHotSpot;
5258 This->yHotSpot = YHotSpot;
5262 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5264 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5266 This->xScreenSpace = XScreenSpace;
5267 This->yScreenSpace = YScreenSpace;
5273 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5275 BOOL oldVisible = This->bCursorVisible;
5276 TRACE("(%p) : visible(%d)\n", This, bShow);
5278 if(This->cursorTexture)
5279 This->bCursorVisible = bShow;
5284 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5286 TRACE("(%p) : state (%u)\n", This, This->state);
5287 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5288 switch (This->state) {
5291 case WINED3DERR_DEVICELOST:
5293 ResourceList *resourceList = This->resources;
5294 while (NULL != resourceList) {
5295 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5296 return WINED3DERR_DEVICENOTRESET;
5297 resourceList = resourceList->next;
5299 return WINED3DERR_DEVICELOST;
5301 case WINED3DERR_DRIVERINTERNALERROR:
5302 return WINED3DERR_DRIVERINTERNALERROR;
5306 return WINED3DERR_DRIVERINTERNALERROR;
5310 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5312 /** FIXME: Resource tracking needs to be done,
5313 * The closes we can do to this is set the priorities of all managed textures low
5314 * and then reset them.
5315 ***********************************************************/
5316 FIXME("(%p) : stub\n", This);
5320 void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5321 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5323 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5324 if(surface->Flags & SFLAG_DIBSECTION) {
5325 /* Release the DC */
5326 SelectObject(surface->hDC, surface->dib.holdbitmap);
5327 DeleteDC(surface->hDC);
5328 /* Release the DIB section */
5329 DeleteObject(surface->dib.DIBsection);
5330 surface->dib.bitmap_data = NULL;
5331 surface->resource.allocatedMemory = NULL;
5332 surface->Flags &= ~SFLAG_DIBSECTION;
5334 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5335 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5336 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5337 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5338 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5340 surface->pow2Width = surface->pow2Height = 1;
5341 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5342 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5344 if(surface->glDescription.textureName) {
5346 glDeleteTextures(1, &surface->glDescription.textureName);
5348 surface->glDescription.textureName = 0;
5350 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5351 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5352 surface->Flags |= SFLAG_NONPOW2;
5354 surface->Flags &= ~SFLAG_NONPOW2;
5356 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5357 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5360 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5362 IWineD3DSwapChainImpl *swapchain;
5364 BOOL DisplayModeChanged = FALSE;
5365 WINED3DDISPLAYMODE mode;
5366 TRACE("(%p)\n", This);
5368 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5370 ERR("Failed to get the first implicit swapchain\n");
5374 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5375 * on an existing gl context, so there's no real need for recreation.
5377 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5379 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5381 TRACE("New params:\n");
5382 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5383 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5384 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5385 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5386 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
5387 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
5388 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
5389 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
5390 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
5391 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
5392 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
5393 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
5394 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
5396 /* No special treatment of these parameters. Just store them */
5397 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
5398 swapchain->presentParms.Flags = pPresentationParameters->Flags;
5399 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
5400 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
5402 /* What to do about these? */
5403 if(pPresentationParameters->BackBufferCount != 0 &&
5404 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
5405 ERR("Cannot change the back buffer count yet\n");
5407 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
5408 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
5409 ERR("Cannot change the back buffer format yet\n");
5411 if(pPresentationParameters->hDeviceWindow != NULL &&
5412 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
5413 ERR("Cannot change the device window yet\n");
5415 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
5416 ERR("What do do about a changed auto depth stencil parameter?\n");
5419 if(pPresentationParameters->Windowed) {
5420 mode.Width = swapchain->orig_width;
5421 mode.Height = swapchain->orig_height;
5422 mode.RefreshRate = 0;
5423 mode.Format = swapchain->presentParms.BackBufferFormat;
5425 mode.Width = pPresentationParameters->BackBufferWidth;
5426 mode.Height = pPresentationParameters->BackBufferHeight;
5427 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
5428 mode.Format = swapchain->presentParms.BackBufferFormat;
5431 /* Should Width == 800 && Height == 0 set 800x600? */
5432 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
5433 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
5434 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
5441 vp.Width = pPresentationParameters->BackBufferWidth;
5442 vp.Height = pPresentationParameters->BackBufferHeight;
5446 if(!pPresentationParameters->Windowed) {
5447 DisplayModeChanged = TRUE;
5449 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
5450 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
5452 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
5453 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
5454 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
5457 /* Now set the new viewport */
5458 IWineD3DDevice_SetViewport(iface, &vp);
5461 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
5462 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
5463 DisplayModeChanged) {
5465 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
5466 if(!pPresentationParameters->Windowed) {
5467 IWineD3DDevice_SetFullscreen(iface, TRUE);
5470 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
5472 /* Switching out of fullscreen mode? First set the original res, then change the window */
5473 if(pPresentationParameters->Windowed) {
5474 IWineD3DDevice_SetFullscreen(iface, FALSE);
5476 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
5479 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5483 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
5484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5485 /** FIXME: always true at the moment **/
5486 if(!bEnableDialogs) {
5487 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
5493 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
5494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5495 TRACE("(%p) : pParameters %p\n", This, pParameters);
5497 *pParameters = This->createParms;
5501 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
5502 IWineD3DSwapChain *swapchain;
5503 HRESULT hrc = WINED3D_OK;
5505 TRACE("Relaying to swapchain\n");
5507 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5508 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
5509 IWineD3DSwapChain_Release(swapchain);
5514 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
5515 IWineD3DSwapChain *swapchain;
5516 HRESULT hrc = WINED3D_OK;
5518 TRACE("Relaying to swapchain\n");
5520 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
5521 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
5522 IWineD3DSwapChain_Release(swapchain);
5528 /** ********************************************************
5529 * Notification functions
5530 ** ********************************************************/
5531 /** This function must be called in the release of a resource when ref == 0,
5532 * the contents of resource must still be correct,
5533 * any handels to other resource held by the caller must be closed
5534 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
5535 *****************************************************/
5536 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5538 ResourceList* resourceList;
5540 TRACE("(%p) : resource %p\n", This, resource);
5542 EnterCriticalSection(&resourceStoreCriticalSection);
5544 /* add a new texture to the frot of the linked list */
5545 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
5546 resourceList->resource = resource;
5548 /* Get the old head */
5549 resourceList->next = This->resources;
5551 This->resources = resourceList;
5552 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
5555 LeaveCriticalSection(&resourceStoreCriticalSection);
5560 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
5561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5562 ResourceList* resourceList = NULL;
5563 ResourceList* previousResourceList = NULL;
5565 TRACE("(%p) : resource %p\n", This, resource);
5568 EnterCriticalSection(&resourceStoreCriticalSection);
5570 resourceList = This->resources;
5572 while (resourceList != NULL) {
5573 if(resourceList->resource == resource) break;
5574 previousResourceList = resourceList;
5575 resourceList = resourceList->next;
5578 if (resourceList == NULL) {
5579 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
5581 LeaveCriticalSection(&resourceStoreCriticalSection);
5585 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
5587 /* make sure we don't leave a hole in the list */
5588 if (previousResourceList != NULL) {
5589 previousResourceList->next = resourceList->next;
5591 This->resources = resourceList->next;
5595 LeaveCriticalSection(&resourceStoreCriticalSection);
5601 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5605 TRACE("(%p) : resource %p\n", This, resource);
5606 switch(IWineD3DResource_GetType(resource)){
5607 case WINED3DRTYPE_SURFACE:
5608 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
5610 case WINED3DRTYPE_TEXTURE:
5611 case WINED3DRTYPE_CUBETEXTURE:
5612 case WINED3DRTYPE_VOLUMETEXTURE:
5613 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
5614 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5615 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5616 This->stateBlock->textures[counter] = NULL;
5618 if (This->updateStateBlock != This->stateBlock ){
5619 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
5620 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
5621 This->updateStateBlock->textures[counter] = NULL;
5626 case WINED3DRTYPE_VOLUME:
5627 /* TODO: nothing really? */
5629 case WINED3DRTYPE_VERTEXBUFFER:
5630 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
5633 TRACE("Cleaning up stream pointers\n");
5635 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
5636 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
5637 FINDOUT: should changes.streamSource[StreamNumber] be set ?
5639 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5640 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
5641 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5642 This->updateStateBlock->streamSource[streamNumber] = 0;
5643 /* Set changed flag? */
5646 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) */
5647 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
5648 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
5649 This->stateBlock->streamSource[streamNumber] = 0;
5652 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
5653 else { /* This shouldn't happen */
5654 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
5661 case WINED3DRTYPE_INDEXBUFFER:
5662 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
5663 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
5664 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5665 This->updateStateBlock->pIndexData = NULL;
5668 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
5669 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
5670 This->stateBlock->pIndexData = NULL;
5676 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
5681 /* Remove the resoruce from the resourceStore */
5682 IWineD3DDeviceImpl_RemoveResource(iface, resource);
5684 TRACE("Resource released\n");
5688 /**********************************************************
5689 * IWineD3DDevice VTbl follows
5690 **********************************************************/
5692 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
5694 /*** IUnknown methods ***/
5695 IWineD3DDeviceImpl_QueryInterface,
5696 IWineD3DDeviceImpl_AddRef,
5697 IWineD3DDeviceImpl_Release,
5698 /*** IWineD3DDevice methods ***/
5699 IWineD3DDeviceImpl_GetParent,
5700 /*** Creation methods**/
5701 IWineD3DDeviceImpl_CreateVertexBuffer,
5702 IWineD3DDeviceImpl_CreateIndexBuffer,
5703 IWineD3DDeviceImpl_CreateStateBlock,
5704 IWineD3DDeviceImpl_CreateSurface,
5705 IWineD3DDeviceImpl_CreateTexture,
5706 IWineD3DDeviceImpl_CreateVolumeTexture,
5707 IWineD3DDeviceImpl_CreateVolume,
5708 IWineD3DDeviceImpl_CreateCubeTexture,
5709 IWineD3DDeviceImpl_CreateQuery,
5710 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
5711 IWineD3DDeviceImpl_CreateVertexDeclaration,
5712 IWineD3DDeviceImpl_CreateVertexShader,
5713 IWineD3DDeviceImpl_CreatePixelShader,
5714 IWineD3DDeviceImpl_CreatePalette,
5715 /*** Odd functions **/
5716 IWineD3DDeviceImpl_Init3D,
5717 IWineD3DDeviceImpl_Uninit3D,
5718 IWineD3DDeviceImpl_SetFullscreen,
5719 IWineD3DDeviceImpl_EnumDisplayModes,
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);