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-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
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 static inline 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 /* static function declarations */
75 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
78 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
80 #define D3DCREATEOBJECTINSTANCE(object, type) { \
81 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
82 D3DMEMCHECK(object, pp##type); \
83 object->lpVtbl = &IWineD3D##type##_Vtbl; \
84 object->wineD3DDevice = This; \
85 object->parent = parent; \
87 *pp##type = (IWineD3D##type *) object; \
90 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
91 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
92 D3DMEMCHECK(object, pp##type); \
93 object->lpVtbl = &IWineD3D##type##_Vtbl; \
94 object->parent = parent; \
96 object->baseShader.device = (IWineD3DDevice*) This; \
97 list_init(&object->baseShader.linked_programs); \
98 *pp##type = (IWineD3D##type *) object; \
101 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
102 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
103 D3DMEMCHECK(object, pp##type); \
104 object->lpVtbl = &IWineD3D##type##_Vtbl; \
105 object->resource.wineD3DDevice = This; \
106 object->resource.parent = parent; \
107 object->resource.resourceType = d3dtype; \
108 object->resource.ref = 1; \
109 object->resource.pool = Pool; \
110 object->resource.format = Format; \
111 object->resource.usage = Usage; \
112 object->resource.size = _size; \
113 list_init(&object->resource.privateData); \
114 /* Check that we have enough video ram left */ \
115 if (Pool == WINED3DPOOL_DEFAULT) { \
116 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
117 WARN("Out of 'bogus' video memory\n"); \
118 HeapFree(GetProcessHeap(), 0, object); \
120 return WINED3DERR_OUTOFVIDEOMEMORY; \
122 globalChangeGlRam(_size); \
124 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
125 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
126 FIXME("Out of memory!\n"); \
127 HeapFree(GetProcessHeap(), 0, object); \
129 return WINED3DERR_OUTOFVIDEOMEMORY; \
131 *pp##type = (IWineD3D##type *) object; \
132 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
133 TRACE("(%p) : Created resource %p\n", This, object); \
136 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
137 _basetexture.levels = Levels; \
138 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
139 _basetexture.LOD = 0; \
140 _basetexture.dirty = TRUE; \
143 /**********************************************************
144 * Global variable / Constants follow
145 **********************************************************/
146 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
148 /**********************************************************
149 * IUnknown parts follows
150 **********************************************************/
152 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
156 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
157 if (IsEqualGUID(riid, &IID_IUnknown)
158 || IsEqualGUID(riid, &IID_IWineD3DBase)
159 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
160 IUnknown_AddRef(iface);
165 return E_NOINTERFACE;
168 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
170 ULONG refCount = InterlockedIncrement(&This->ref);
172 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
176 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
178 ULONG refCount = InterlockedDecrement(&This->ref);
180 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
184 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
187 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
190 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
193 HeapFree(GetProcessHeap(), 0, This->render_targets);
194 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
195 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
197 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
199 /* TODO: Clean up all the surfaces and textures! */
200 /* NOTE: You must release the parent if the object was created via a callback
201 ** ***************************/
203 /* Release the update stateblock */
204 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
205 if(This->updateStateBlock != This->stateBlock)
206 FIXME("(%p) Something's still holding the Update stateblock\n",This);
208 This->updateStateBlock = NULL;
209 { /* because were not doing proper internal refcounts releasing the primary state block
210 causes recursion with the extra checks in ResourceReleased, to avoid this we have
211 to set this->stateBlock = NULL; first */
212 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
213 This->stateBlock = NULL;
215 /* Release the stateblock */
216 if(IWineD3DStateBlock_Release(stateBlock) > 0){
217 FIXME("(%p) Something's still holding the Update stateblock\n",This);
221 if (This->resources != NULL ) {
222 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
223 dumpResources(This->resources);
226 if(This->contexts) ERR("Context array not freed!\n");
227 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
228 This->haveHardwareCursor = FALSE;
230 IWineD3D_Release(This->wineD3D);
231 This->wineD3D = NULL;
232 HeapFree(GetProcessHeap(), 0, This);
233 TRACE("Freed device %p\n", This);
239 /**********************************************************
240 * IWineD3DDevice implementation follows
241 **********************************************************/
242 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
244 *pParent = This->parent;
245 IUnknown_AddRef(This->parent);
249 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
250 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
251 GLenum error, glUsage;
252 DWORD vboUsage = object->resource.usage;
253 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
254 WARN("Creating a vbo failed once, not trying again\n");
258 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
261 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
262 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
264 /* Make sure that the gl error is cleared. Do not use checkGLcall
265 * here because checkGLcall just prints a fixme and continues. However,
266 * if an error during VBO creation occurs we can fall back to non-vbo operation
267 * with full functionality(but performance loss)
269 while(glGetError() != GL_NO_ERROR);
271 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
272 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
273 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
274 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
275 * to check if the rhw and color values are in the correct format.
278 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
279 error = glGetError();
280 if(object->vbo == 0 || error != GL_NO_ERROR) {
281 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
285 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
286 error = glGetError();
287 if(error != GL_NO_ERROR) {
288 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
292 /* Don't use static, because dx apps tend to update the buffer
293 * quite often even if they specify 0 usage. Because we always keep the local copy
294 * we never read from the vbo and can create a write only opengl buffer.
296 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
297 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
298 case WINED3DUSAGE_DYNAMIC:
299 TRACE("Gl usage = GL_STREAM_DRAW\n");
300 glUsage = GL_STREAM_DRAW_ARB;
302 case WINED3DUSAGE_WRITEONLY:
304 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
305 glUsage = GL_DYNAMIC_DRAW_ARB;
309 /* Reserve memory for the buffer. The amount of data won't change
310 * so we are safe with calling glBufferData once with a NULL ptr and
311 * calling glBufferSubData on updates
313 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
314 error = glGetError();
315 if(error != GL_NO_ERROR) {
316 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
324 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
325 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
326 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
328 object->Flags |= VBFLAG_VBOCREATEFAIL;
333 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
334 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
337 IWineD3DVertexBufferImpl *object;
338 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
339 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
343 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
344 *ppVertexBuffer = NULL;
345 return WINED3DERR_INVALIDCALL;
348 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
350 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
351 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
353 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
354 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
358 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
359 * drawStridedFast (half-life 2).
361 * Basically converting the vertices in the buffer is quite expensive, and observations
362 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
363 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
365 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
366 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
367 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
368 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
370 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
371 * more. In this call we can convert dx7 buffers too.
373 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
374 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
375 (dxVersion > 7 || !conv) ) {
381 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
382 GLenum error, glUsage;
383 TRACE("Creating VBO for Index Buffer %p\n", object);
385 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
386 * restored on the next draw
388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
391 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
392 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
396 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
397 error = glGetError();
398 if(error != GL_NO_ERROR || object->vbo == 0) {
399 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
403 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
404 error = glGetError();
405 if(error != GL_NO_ERROR) {
406 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
410 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
411 * copy no readback will be needed
413 glUsage = GL_STATIC_DRAW_ARB;
414 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
415 error = glGetError();
416 if(error != GL_NO_ERROR) {
417 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
421 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
425 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
426 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
431 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
432 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
433 HANDLE *sharedHandle, IUnknown *parent) {
434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
435 IWineD3DIndexBufferImpl *object;
436 TRACE("(%p) Creating index buffer\n", This);
438 /* Allocate the storage for the device */
439 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
441 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
442 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
445 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
446 CreateIndexBufferVBO(This, object);
449 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
450 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
451 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
456 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
459 IWineD3DStateBlockImpl *object;
463 D3DCREATEOBJECTINSTANCE(object, StateBlock)
464 object->blockType = Type;
466 for(i = 0; i < LIGHTMAP_SIZE; i++) {
467 list_init(&object->lightMap[i]);
470 /* Special case - Used during initialization to produce a placeholder stateblock
471 so other functions called can update a state block */
472 if (Type == WINED3DSBT_INIT) {
473 /* Don't bother increasing the reference count otherwise a device will never
474 be freed due to circular dependencies */
478 temp_result = allocate_shader_constants(object);
479 if (WINED3D_OK != temp_result)
482 /* Otherwise, might as well set the whole state block to the appropriate values */
483 if (This->stateBlock != NULL)
484 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
486 memset(object->streamFreq, 1, sizeof(object->streamFreq));
488 /* Reset the ref and type after kludging it */
489 object->wineD3DDevice = This;
491 object->blockType = Type;
493 TRACE("Updating changed flags appropriate for type %d\n", Type);
495 if (Type == WINED3DSBT_ALL) {
497 TRACE("ALL => Pretend everything has changed\n");
498 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
500 /* Lights are not part of the changed / set structure */
501 for(j = 0; j < LIGHTMAP_SIZE; j++) {
503 LIST_FOR_EACH(e, &object->lightMap[j]) {
504 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
505 light->changed = TRUE;
506 light->enabledChanged = TRUE;
509 } else if (Type == WINED3DSBT_PIXELSTATE) {
511 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
512 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
514 object->changed.pixelShader = TRUE;
516 /* Pixel Shader Constants */
517 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
518 object->changed.pixelShaderConstantsF[i] = TRUE;
519 for (i = 0; i < MAX_CONST_B; ++i)
520 object->changed.pixelShaderConstantsB[i] = TRUE;
521 for (i = 0; i < MAX_CONST_I; ++i)
522 object->changed.pixelShaderConstantsI[i] = TRUE;
524 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
525 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
527 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
528 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
529 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
532 for (j = 0 ; j < 16; j++) {
533 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
535 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
539 } else if (Type == WINED3DSBT_VERTEXSTATE) {
541 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
542 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
544 object->changed.vertexShader = TRUE;
546 /* Vertex Shader Constants */
547 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
548 object->changed.vertexShaderConstantsF[i] = TRUE;
549 for (i = 0; i < MAX_CONST_B; ++i)
550 object->changed.vertexShaderConstantsB[i] = TRUE;
551 for (i = 0; i < MAX_CONST_I; ++i)
552 object->changed.vertexShaderConstantsI[i] = TRUE;
554 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
555 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
557 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
558 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
559 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
562 for (j = 0 ; j < 16; j++){
563 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
564 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
568 for(j = 0; j < LIGHTMAP_SIZE; j++) {
570 LIST_FOR_EACH(e, &object->lightMap[j]) {
571 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
572 light->changed = TRUE;
573 light->enabledChanged = TRUE;
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
584 /* ************************************
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 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.
593 ******************************** */
595 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) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int pow2Width, pow2Height;
599 unsigned int Size = 1;
600 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
601 TRACE("(%p) Create surface\n",This);
603 /** FIXME: Check ranges on the inputs are valid
606 * [in] Quality level. The valid range is between zero and one less than the level
607 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
608 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
609 * values of paired render targets, depth stencil surfaces, and the MultiSample type
611 *******************************/
616 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
618 * If this flag is set, the contents of the depth stencil buffer will be
619 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
620 * with a different depth surface.
622 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
623 ***************************/
625 if(MultisampleQuality < 0) {
626 FIXME("Invalid multisample level %d\n", MultisampleQuality);
627 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
630 if(MultisampleQuality > 0) {
631 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
632 MultisampleQuality=0;
635 /** FIXME: Check that the format is supported
637 *******************************/
639 /* Non-power2 support */
640 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
644 /* Find the nearest pow2 match */
645 pow2Width = pow2Height = 1;
646 while (pow2Width < Width) pow2Width <<= 1;
647 while (pow2Height < Height) pow2Height <<= 1;
650 if (pow2Width > Width || pow2Height > Height) {
651 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
652 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
653 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
654 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
655 This, Width, Height);
656 return WINED3DERR_NOTAVAILABLE;
660 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
661 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
663 *********************************/
664 if (WINED3DFMT_UNKNOWN == Format) {
666 } else if (Format == WINED3DFMT_DXT1) {
667 /* DXT1 is half byte per pixel */
668 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
670 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
671 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
672 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
674 /* The pitch is a multiple of 4 bytes */
675 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
679 /** Create and initialise the surface resource **/
680 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
681 /* "Standalone" surface */
682 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
684 object->currentDesc.Width = Width;
685 object->currentDesc.Height = Height;
686 object->currentDesc.MultiSampleType = MultiSample;
687 object->currentDesc.MultiSampleQuality = MultisampleQuality;
689 /* Setup some glformat defaults */
690 object->glDescription.glFormat = tableEntry->glFormat;
691 object->glDescription.glFormatInternal = tableEntry->glInternal;
692 object->glDescription.glType = tableEntry->glType;
694 object->glDescription.textureName = 0;
695 object->glDescription.level = Level;
696 object->glDescription.target = GL_TEXTURE_2D;
699 object->pow2Width = pow2Width;
700 object->pow2Height = pow2Height;
703 object->Flags = SFLAG_DYNLOCK;
704 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
705 object->Flags |= Discard ? SFLAG_DISCARD : 0;
706 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
707 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
710 if (WINED3DFMT_UNKNOWN != Format) {
711 object->bytesPerPixel = tableEntry->bpp;
713 object->bytesPerPixel = 0;
716 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
718 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
720 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
721 * this function is too deep to need to care about things like this.
722 * Levels need to be checked too, and possibly Type since they all affect what can be done.
723 * ****************************************/
725 case WINED3DPOOL_SCRATCH:
727 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
728 "which are mutually exclusive, setting lockable to TRUE\n");
731 case WINED3DPOOL_SYSTEMMEM:
732 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
733 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
734 case WINED3DPOOL_MANAGED:
735 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
736 "Usage of DYNAMIC which are mutually exclusive, not doing "
737 "anything just telling you.\n");
739 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
740 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
741 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
742 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
745 FIXME("(%p) Unknown pool %d\n", This, Pool);
749 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
750 FIXME("Trying to create a render target that isn't in the default pool\n");
753 /* mark the texture as dirty so that it gets loaded first time around*/
754 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
755 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
756 This, Width, Height, Format, debug_d3dformat(Format),
757 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
759 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
760 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
761 This->ddraw_primary = (IWineD3DSurface *) object;
763 /* Look at the implementation and set the correct Vtable */
766 /* Nothing to do, it's set already */
770 object->lpVtbl = &IWineGDISurface_Vtbl;
774 /* To be sure to catch this */
775 ERR("Unknown requested surface implementation %d!\n", Impl);
776 IWineD3DSurface_Release((IWineD3DSurface *) object);
777 return WINED3DERR_INVALIDCALL;
780 list_init(&object->renderbuffers);
782 /* Call the private setup routine */
783 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
787 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
788 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
789 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
790 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
793 IWineD3DTextureImpl *object;
798 unsigned int pow2Width;
799 unsigned int pow2Height;
802 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
803 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
804 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
806 /* TODO: It should only be possible to create textures for formats
807 that are reported as supported */
808 if (WINED3DFMT_UNKNOWN >= Format) {
809 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
810 return WINED3DERR_INVALIDCALL;
813 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
814 D3DINITIALIZEBASETEXTURE(object->baseTexture);
815 object->width = Width;
816 object->height = Height;
818 /** Non-power2 support **/
819 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
823 /* Find the nearest pow2 match */
824 pow2Width = pow2Height = 1;
825 while (pow2Width < Width) pow2Width <<= 1;
826 while (pow2Height < Height) pow2Height <<= 1;
829 /** FIXME: add support for real non-power-two if it's provided by the video card **/
830 /* Precalculated scaling for 'faked' non power of two texture coords */
831 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
832 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
833 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
835 /* Calculate levels for mip mapping */
837 TRACE("calculating levels %d\n", object->baseTexture.levels);
838 object->baseTexture.levels++;
841 while (tmpW > 1 || tmpH > 1) {
842 tmpW = max(1, tmpW >> 1);
843 tmpH = max(1, tmpH >> 1);
844 object->baseTexture.levels++;
846 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
849 /* Generate all the surfaces */
852 for (i = 0; i < object->baseTexture.levels; i++)
854 /* use the callback to create the texture surface */
855 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
856 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
857 FIXME("Failed to create surface %p\n", object);
859 object->surfaces[i] = NULL;
860 IWineD3DTexture_Release((IWineD3DTexture *)object);
866 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
867 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
868 /* calculate the next mipmap level */
869 tmpW = max(1, tmpW >> 1);
870 tmpH = max(1, tmpH >> 1);
873 TRACE("(%p) : Created texture %p\n", This, object);
877 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
878 UINT Width, UINT Height, UINT Depth,
879 UINT Levels, DWORD Usage,
880 WINED3DFORMAT Format, WINED3DPOOL Pool,
881 IWineD3DVolumeTexture **ppVolumeTexture,
882 HANDLE *pSharedHandle, IUnknown *parent,
883 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
886 IWineD3DVolumeTextureImpl *object;
892 /* TODO: It should only be possible to create textures for formats
893 that are reported as supported */
894 if (WINED3DFMT_UNKNOWN >= Format) {
895 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
896 return WINED3DERR_INVALIDCALL;
899 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
900 D3DINITIALIZEBASETEXTURE(object->baseTexture);
902 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
903 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
905 object->width = Width;
906 object->height = Height;
907 object->depth = Depth;
909 /* Calculate levels for mip mapping */
911 object->baseTexture.levels++;
915 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
916 tmpW = max(1, tmpW >> 1);
917 tmpH = max(1, tmpH >> 1);
918 tmpD = max(1, tmpD >> 1);
919 object->baseTexture.levels++;
921 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
924 /* Generate all the surfaces */
929 for (i = 0; i < object->baseTexture.levels; i++)
932 /* Create the volume */
933 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
934 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
937 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
938 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
939 *ppVolumeTexture = NULL;
943 /* Set its container to this object */
944 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
946 /* calcualte the next mipmap level */
947 tmpW = max(1, tmpW >> 1);
948 tmpH = max(1, tmpH >> 1);
949 tmpD = max(1, tmpD >> 1);
952 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
953 TRACE("(%p) : Created volume texture %p\n", This, object);
957 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
958 UINT Width, UINT Height, UINT Depth,
960 WINED3DFORMAT Format, WINED3DPOOL Pool,
961 IWineD3DVolume** ppVolume,
962 HANDLE* pSharedHandle, IUnknown *parent) {
964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
965 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
966 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
968 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
970 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
971 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
973 object->currentDesc.Width = Width;
974 object->currentDesc.Height = Height;
975 object->currentDesc.Depth = Depth;
976 object->bytesPerPixel = formatDesc->bpp;
978 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
979 object->lockable = TRUE;
980 object->locked = FALSE;
981 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
982 object->dirty = TRUE;
984 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
987 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
988 UINT Levels, DWORD Usage,
989 WINED3DFORMAT Format, WINED3DPOOL Pool,
990 IWineD3DCubeTexture **ppCubeTexture,
991 HANDLE *pSharedHandle, IUnknown *parent,
992 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
995 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
999 unsigned int pow2EdgeLength = EdgeLength;
1001 /* TODO: It should only be possible to create textures for formats
1002 that are reported as supported */
1003 if (WINED3DFMT_UNKNOWN >= Format) {
1004 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1005 return WINED3DERR_INVALIDCALL;
1008 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1009 WARN("(%p) : Tried to create not supported cube texture\n", This);
1010 return WINED3DERR_INVALIDCALL;
1013 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1014 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1016 TRACE("(%p) Create Cube Texture\n", This);
1018 /** Non-power2 support **/
1020 /* Find the nearest pow2 match */
1022 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1024 object->edgeLength = EdgeLength;
1025 /* TODO: support for native non-power 2 */
1026 /* Precalculated scaling for 'faked' non power of two texture coords */
1027 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1029 /* Calculate levels for mip mapping */
1031 object->baseTexture.levels++;
1034 tmpW = max(1, tmpW >> 1);
1035 object->baseTexture.levels++;
1037 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1040 /* Generate all the surfaces */
1042 for (i = 0; i < object->baseTexture.levels; i++) {
1044 /* Create the 6 faces */
1045 for (j = 0; j < 6; j++) {
1047 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1048 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1050 if(hr!= WINED3D_OK) {
1054 for (l = 0; l < j; l++) {
1055 IWineD3DSurface_Release(object->surfaces[j][i]);
1057 for (k = 0; k < i; k++) {
1058 for (l = 0; l < 6; l++) {
1059 IWineD3DSurface_Release(object->surfaces[l][j]);
1063 FIXME("(%p) Failed to create surface\n",object);
1064 HeapFree(GetProcessHeap(),0,object);
1065 *ppCubeTexture = NULL;
1068 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1069 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1071 tmpW = max(1, tmpW >> 1);
1074 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1075 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1079 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1081 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1082 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1084 /* Just a check to see if we support this type of query */
1086 case WINED3DQUERYTYPE_OCCLUSION:
1087 TRACE("(%p) occlusion query\n", This);
1088 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1091 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1094 case WINED3DQUERYTYPE_EVENT:
1095 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1096 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1097 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1099 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1104 case WINED3DQUERYTYPE_VCACHE:
1105 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1106 case WINED3DQUERYTYPE_VERTEXSTATS:
1107 case WINED3DQUERYTYPE_TIMESTAMP:
1108 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1109 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1110 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1111 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1112 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1113 case WINED3DQUERYTYPE_PIXELTIMINGS:
1114 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1115 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1117 FIXME("(%p) Unhandled query type %d\n", This, Type);
1119 if(NULL == ppQuery || hr != WINED3D_OK) {
1123 D3DCREATEOBJECTINSTANCE(object, Query)
1124 object->type = Type;
1125 /* allocated the 'extended' data based on the type of query requested */
1127 case WINED3DQUERYTYPE_OCCLUSION:
1128 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1129 TRACE("(%p) Allocating data for an occlusion query\n", This);
1130 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1131 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1134 case WINED3DQUERYTYPE_EVENT:
1135 /* TODO: GL_APPLE_fence */
1136 if(GL_SUPPORT(APPLE_FENCE)) {
1137 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1138 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1139 checkGLcall("glGenFencesAPPLE");
1140 } else if(GL_SUPPORT(NV_FENCE)) {
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1142 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1143 checkGLcall("glGenFencesNV");
1147 case WINED3DQUERYTYPE_VCACHE:
1148 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1149 case WINED3DQUERYTYPE_VERTEXSTATS:
1150 case WINED3DQUERYTYPE_TIMESTAMP:
1151 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1152 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1153 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1154 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1155 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1156 case WINED3DQUERYTYPE_PIXELTIMINGS:
1157 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1158 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1160 object->extendedData = 0;
1161 FIXME("(%p) Unhandled query type %d\n",This , Type);
1163 TRACE("(%p) : Created Query %p\n", This, object);
1167 /*****************************************************************************
1168 * IWineD3DDeviceImpl_SetupFullscreenWindow
1170 * Helper function that modifies a HWND's Style and ExStyle for proper
1174 * iface: Pointer to the IWineD3DDevice interface
1175 * window: Window to setup
1177 *****************************************************************************/
1178 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1181 LONG style, exStyle;
1182 /* Don't do anything if an original style is stored.
1183 * That shouldn't happen
1185 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1186 if (This->style || This->exStyle) {
1187 ERR("(%p): Want to change the window parameters of HWND %p, but "
1188 "another style is stored for restoration afterwards\n", This, window);
1191 /* Get the parameters and save them */
1192 style = GetWindowLongW(window, GWL_STYLE);
1193 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1194 This->style = style;
1195 This->exStyle = exStyle;
1197 /* Filter out window decorations */
1198 style &= ~WS_CAPTION;
1199 style &= ~WS_THICKFRAME;
1200 exStyle &= ~WS_EX_WINDOWEDGE;
1201 exStyle &= ~WS_EX_CLIENTEDGE;
1203 /* Make sure the window is managed, otherwise we won't get keyboard input */
1204 style |= WS_POPUP | WS_SYSMENU;
1206 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1207 This->style, This->exStyle, style, exStyle);
1209 SetWindowLongW(window, GWL_STYLE, style);
1210 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1212 /* Inform the window about the update. */
1213 SetWindowPos(window, HWND_TOP, 0, 0,
1214 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1215 ShowWindow(window, SW_NORMAL);
1218 /*****************************************************************************
1219 * IWineD3DDeviceImpl_RestoreWindow
1221 * Helper function that restores a windows' properties when taking it out
1222 * of fullscreen mode
1225 * iface: Pointer to the IWineD3DDevice interface
1226 * window: Window to setup
1228 *****************************************************************************/
1229 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1232 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1233 * switch, do nothing
1235 if (!This->style && !This->exStyle) return;
1237 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1238 This, window, This->style, This->exStyle);
1240 SetWindowLongW(window, GWL_STYLE, This->style);
1241 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1243 /* Delete the old values */
1247 /* Inform the window about the update */
1248 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1249 0, 0, 0, 0, /* Pos, Size, ignored */
1250 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1253 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1254 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1256 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1257 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1261 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1262 HRESULT hr = WINED3D_OK;
1263 IUnknown *bufferParent;
1266 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1268 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1269 * does a device hold a reference to a swap chain giving them a lifetime of the device
1270 * or does the swap chain notify the device of its destruction.
1271 *******************************/
1273 /* Check the params */
1274 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1275 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1276 return WINED3DERR_INVALIDCALL;
1277 } else if (pPresentationParameters->BackBufferCount > 1) {
1278 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");
1281 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1283 /*********************
1284 * Lookup the window Handle and the relating X window handle
1285 ********************/
1287 /* Setup hwnd we are using, plus which display this equates to */
1288 object->win_handle = pPresentationParameters->hDeviceWindow;
1289 if (!object->win_handle) {
1290 object->win_handle = This->createParms.hFocusWindow;
1293 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1294 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1295 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1296 return WINED3DERR_NOTAVAILABLE;
1298 hDc = GetDC(object->win_handle);
1299 display = get_display(hDc);
1300 ReleaseDC(object->win_handle, hDc);
1301 TRACE("Using a display of %p %p\n", display, hDc);
1303 if (NULL == display || NULL == hDc) {
1304 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1305 return WINED3DERR_NOTAVAILABLE;
1308 if (object->win == 0) {
1309 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1310 return WINED3DERR_NOTAVAILABLE;
1313 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1314 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1315 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1317 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1318 * then the corresponding dimension of the client area of the hDeviceWindow
1319 * (or the focus window, if hDeviceWindow is NULL) is taken.
1320 **********************/
1322 if (pPresentationParameters->Windowed &&
1323 ((pPresentationParameters->BackBufferWidth == 0) ||
1324 (pPresentationParameters->BackBufferHeight == 0))) {
1327 GetClientRect(object->win_handle, &Rect);
1329 if (pPresentationParameters->BackBufferWidth == 0) {
1330 pPresentationParameters->BackBufferWidth = Rect.right;
1331 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1333 if (pPresentationParameters->BackBufferHeight == 0) {
1334 pPresentationParameters->BackBufferHeight = Rect.bottom;
1335 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1339 /* Put the correct figures in the presentation parameters */
1340 TRACE("Copying across presentation parameters\n");
1341 object->presentParms = *pPresentationParameters;
1343 TRACE("calling rendertarget CB\n");
1344 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1346 object->presentParms.BackBufferWidth,
1347 object->presentParms.BackBufferHeight,
1348 object->presentParms.BackBufferFormat,
1349 object->presentParms.MultiSampleType,
1350 object->presentParms.MultiSampleQuality,
1351 TRUE /* Lockable */,
1352 &object->frontBuffer,
1353 NULL /* pShared (always null)*/);
1354 if (object->frontBuffer != NULL) {
1355 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1357 ERR("Failed to create the front buffer\n");
1362 * Create an opengl context for the display visual
1363 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1364 * use different properties after that point in time. FIXME: How to handle when requested format
1365 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1366 * it chooses is identical to the one already being used!
1367 **********************************/
1368 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1370 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1371 if(!object->context)
1372 return E_OUTOFMEMORY;
1373 object->num_contexts = 1;
1376 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1379 if (!object->context[0]) {
1380 ERR("Failed to create a new context\n");
1381 hr = WINED3DERR_NOTAVAILABLE;
1384 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1385 object->win_handle, object->context[0]->glCtx, object->win);
1388 /*********************
1389 * Windowed / Fullscreen
1390 *******************/
1393 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1394 * so we should really check to see if there is a fullscreen swapchain already
1395 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1396 **************************************/
1398 if (!pPresentationParameters->Windowed) {
1405 /* Get info on the current display setup */
1407 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1410 /* Change the display settings */
1411 memset(&devmode, 0, sizeof(DEVMODEW));
1412 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1413 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1414 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1415 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1416 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1417 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1419 /* For GetDisplayMode */
1420 This->ddraw_width = devmode.dmPelsWidth;
1421 This->ddraw_height = devmode.dmPelsHeight;
1422 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1424 IWineD3DDevice_SetFullscreen(iface, TRUE);
1426 /* And finally clip mouse to our screen */
1427 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1428 ClipCursor(&clip_rc);
1431 /*********************
1432 * Create the back, front and stencil buffers
1433 *******************/
1434 if(object->presentParms.BackBufferCount > 0) {
1437 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1438 if(!object->backBuffer) {
1439 ERR("Out of memory\n");
1444 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1445 TRACE("calling rendertarget CB\n");
1446 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1448 object->presentParms.BackBufferWidth,
1449 object->presentParms.BackBufferHeight,
1450 object->presentParms.BackBufferFormat,
1451 object->presentParms.MultiSampleType,
1452 object->presentParms.MultiSampleQuality,
1453 TRUE /* Lockable */,
1454 &object->backBuffer[i],
1455 NULL /* pShared (always null)*/);
1456 if(hr == WINED3D_OK && object->backBuffer[i]) {
1457 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1459 ERR("Cannot create new back buffer\n");
1463 glDrawBuffer(GL_BACK);
1464 checkGLcall("glDrawBuffer(GL_BACK)");
1468 object->backBuffer = NULL;
1470 /* Single buffering - draw to front buffer */
1472 glDrawBuffer(GL_FRONT);
1473 checkGLcall("glDrawBuffer(GL_FRONT)");
1477 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1478 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1479 TRACE("Creating depth stencil buffer\n");
1480 if (This->depthStencilBuffer == NULL ) {
1481 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1483 object->presentParms.BackBufferWidth,
1484 object->presentParms.BackBufferHeight,
1485 object->presentParms.AutoDepthStencilFormat,
1486 object->presentParms.MultiSampleType,
1487 object->presentParms.MultiSampleQuality,
1488 FALSE /* FIXME: Discard */,
1489 &This->depthStencilBuffer,
1490 NULL /* pShared (always null)*/ );
1491 if (This->depthStencilBuffer != NULL)
1492 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1495 /** TODO: A check on width, height and multisample types
1496 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1497 ****************************/
1498 object->wantsDepthStencilBuffer = TRUE;
1500 object->wantsDepthStencilBuffer = FALSE;
1503 TRACE("Created swapchain %p\n", object);
1504 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1508 if (object->backBuffer) {
1510 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1511 if(object->backBuffer[i]) {
1512 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1513 IUnknown_Release(bufferParent); /* once for the get parent */
1514 if (IUnknown_Release(bufferParent) > 0) {
1515 FIXME("(%p) Something's still holding the back buffer\n",This);
1519 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1520 object->backBuffer = NULL;
1522 if(object->context[0])
1523 DestroyContext(This, object->context[0]);
1524 if(object->frontBuffer) {
1525 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1526 IUnknown_Release(bufferParent); /* once for the get parent */
1527 if (IUnknown_Release(bufferParent) > 0) {
1528 FIXME("(%p) Something's still holding the front buffer\n",This);
1531 HeapFree(GetProcessHeap(), 0, object);
1535 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1536 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 TRACE("(%p)\n", This);
1540 return This->NumberOfSwapChains;
1543 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1545 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1547 if(iSwapChain < This->NumberOfSwapChains) {
1548 *pSwapChain = This->swapchains[iSwapChain];
1549 IWineD3DSwapChain_AddRef(*pSwapChain);
1550 TRACE("(%p) returning %p\n", This, *pSwapChain);
1553 TRACE("Swapchain out of range\n");
1555 return WINED3DERR_INVALIDCALL;
1560 * Vertex Declaration
1562 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1563 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1565 IWineD3DVertexDeclarationImpl *object = NULL;
1566 HRESULT hr = WINED3D_OK;
1568 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1569 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1571 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1573 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1578 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1580 unsigned int idx, idx2;
1581 unsigned int offset;
1582 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1583 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1584 BOOL has_blend_idx = has_blend &&
1585 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1586 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1587 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1588 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1589 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1590 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1591 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1593 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1594 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1596 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1597 WINED3DVERTEXELEMENT *elements = NULL;
1600 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1601 if (has_blend_idx) num_blends--;
1603 /* Compute declaration size */
1604 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1605 has_psize + has_diffuse + has_specular + num_textures + 1;
1607 /* convert the declaration */
1608 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1612 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1615 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1616 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1617 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1620 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1621 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1623 elements[idx].UsageIndex = 0;
1626 if (has_blend && (num_blends > 0)) {
1627 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1628 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1630 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1631 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1632 elements[idx].UsageIndex = 0;
1635 if (has_blend_idx) {
1636 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1637 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1638 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1639 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1640 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1642 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1643 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1644 elements[idx].UsageIndex = 0;
1648 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1649 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1650 elements[idx].UsageIndex = 0;
1654 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1655 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1656 elements[idx].UsageIndex = 0;
1660 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1661 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1662 elements[idx].UsageIndex = 0;
1666 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1667 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1668 elements[idx].UsageIndex = 1;
1671 for (idx2 = 0; idx2 < num_textures; idx2++) {
1672 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1673 switch (numcoords) {
1674 case WINED3DFVF_TEXTUREFORMAT1:
1675 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1677 case WINED3DFVF_TEXTUREFORMAT2:
1678 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1680 case WINED3DFVF_TEXTUREFORMAT3:
1681 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1683 case WINED3DFVF_TEXTUREFORMAT4:
1684 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1687 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1688 elements[idx].UsageIndex = idx2;
1692 /* Now compute offsets, and initialize the rest of the fields */
1693 for (idx = 0, offset = 0; idx < size-1; idx++) {
1694 elements[idx].Stream = 0;
1695 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1696 elements[idx].Offset = offset;
1697 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1700 *ppVertexElements = elements;
1704 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1705 WINED3DVERTEXELEMENT* elements = NULL;
1709 size = ConvertFvfToDeclaration(Fvf, &elements);
1710 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1712 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1713 HeapFree(GetProcessHeap(), 0, elements);
1714 if (hr != S_OK) return hr;
1719 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1723 HRESULT hr = WINED3D_OK;
1724 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1725 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1727 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1729 if (vertex_declaration) {
1730 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1733 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1735 if (WINED3D_OK != hr) {
1736 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1737 IWineD3DVertexShader_Release(*ppVertexShader);
1738 return WINED3DERR_INVALIDCALL;
1744 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1746 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1747 HRESULT hr = WINED3D_OK;
1749 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1750 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1751 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1752 if (WINED3D_OK == hr) {
1753 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1755 WARN("(%p) : Failed to create pixel shader\n", This);
1761 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1763 IWineD3DPaletteImpl *object;
1765 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1767 /* Create the new object */
1768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1770 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1771 return E_OUTOFMEMORY;
1774 object->lpVtbl = &IWineD3DPalette_Vtbl;
1776 object->Flags = Flags;
1777 object->parent = Parent;
1778 object->wineD3DDevice = This;
1779 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1781 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1784 HeapFree( GetProcessHeap(), 0, object);
1785 return E_OUTOFMEMORY;
1788 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1790 IWineD3DPalette_Release((IWineD3DPalette *) object);
1794 *Palette = (IWineD3DPalette *) object;
1799 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1801 IWineD3DSwapChainImpl *swapchain;
1804 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1805 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1807 /* TODO: Test if OpenGL is compiled in and loaded */
1809 /* Initialize the texture unit mapping to a 1:1 mapping */
1810 for(state = 0; state < MAX_SAMPLERS; state++) {
1811 This->texUnitMap[state] = state;
1813 This->oneToOneTexUnitMap = TRUE;
1815 /* Setup the implicit swapchain */
1816 TRACE("Creating implicit swapchain\n");
1817 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1818 WARN("Failed to create implicit swapchain\n");
1819 return WINED3DERR_INVALIDCALL;
1822 This->NumberOfSwapChains = 1;
1823 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1824 if(!This->swapchains) {
1825 ERR("Out of memory!\n");
1826 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1827 return E_OUTOFMEMORY;
1829 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1831 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1833 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1834 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1835 This->render_targets[0] = swapchain->backBuffer[0];
1836 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1839 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1840 This->render_targets[0] = swapchain->frontBuffer;
1841 This->lastActiveRenderTarget = swapchain->frontBuffer;
1843 IWineD3DSurface_AddRef(This->render_targets[0]);
1844 This->activeContext = swapchain->context[0];
1846 /* Depth Stencil support */
1847 This->stencilBufferTarget = This->depthStencilBuffer;
1848 if (NULL != This->stencilBufferTarget) {
1849 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1852 /* Set up some starting GL setup */
1855 * Initialize openGL extension related variables
1856 * with Default values
1859 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1860 /* Setup all the devices defaults */
1861 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1863 IWineD3DImpl_CheckGraphicsMemory();
1866 { /* Set a default viewport */
1870 vp.Width = pPresentationParameters->BackBufferWidth;
1871 vp.Height = pPresentationParameters->BackBufferHeight;
1874 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1877 /* Initialize the current view state */
1878 This->view_ident = 1;
1879 This->contexts[0]->last_was_rhw = 0;
1880 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1881 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1883 switch(wined3d_settings.offscreen_rendering_mode) {
1886 This->offscreenBuffer = GL_BACK;
1889 case ORM_BACKBUFFER:
1891 if(GL_LIMITS(aux_buffers) > 0) {
1892 TRACE("Using auxilliary buffer for offscreen rendering\n");
1893 This->offscreenBuffer = GL_AUX0;
1895 TRACE("Using back buffer for offscreen rendering\n");
1896 This->offscreenBuffer = GL_BACK;
1901 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1904 /* Clear the screen */
1905 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1906 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1909 This->d3d_initialized = TRUE;
1913 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1917 TRACE("(%p)\n", This);
1919 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1922 /* I don't think that the interface guarants that the device is destroyed from the same thread
1923 * it was created. Thus make sure a context is active for the glDelete* calls
1925 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1928 /* Delete the pbuffer context if there is any */
1929 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1931 /* Delete the mouse cursor texture */
1932 if(This->cursorTexture) {
1934 glDeleteTextures(1, &This->cursorTexture);
1936 This->cursorTexture = 0;
1939 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1940 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1943 /* Release the buffers (with sanity checks)*/
1944 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1945 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1946 if(This->depthStencilBuffer != This->stencilBufferTarget)
1947 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1949 This->stencilBufferTarget = NULL;
1951 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1952 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1953 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1955 TRACE("Setting rendertarget to NULL\n");
1956 This->render_targets[0] = NULL;
1958 if (This->depthStencilBuffer) {
1959 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1960 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1962 This->depthStencilBuffer = NULL;
1965 for(i=0; i < This->NumberOfSwapChains; i++) {
1966 TRACE("Releasing the implicit swapchain %d\n", i);
1967 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1968 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1972 HeapFree(GetProcessHeap(), 0, This->swapchains);
1973 This->swapchains = NULL;
1974 This->NumberOfSwapChains = 0;
1976 This->d3d_initialized = FALSE;
1980 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1982 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1984 /* Setup the window for fullscreen mode */
1985 if(fullscreen && !This->ddraw_fullscreen) {
1986 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1987 } else if(!fullscreen && This->ddraw_fullscreen) {
1988 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1991 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1992 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1993 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1996 This->ddraw_fullscreen = fullscreen;
1999 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2000 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2001 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2003 * There is no way to deactivate thread safety once it is enabled
2005 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2007 FIXME("No thread safety in wined3d yet\n");
2009 /*For now just store the flag(needed in case of ddraw) */
2010 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2015 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2019 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2022 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2024 /* Resize the screen even without a window:
2025 * The app could have unset it with SetCooperativeLevel, but not called
2026 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2027 * but we don't have any hwnd
2030 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2031 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2032 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2033 devmode.dmPelsWidth = pMode->Width;
2034 devmode.dmPelsHeight = pMode->Height;
2036 devmode.dmDisplayFrequency = pMode->RefreshRate;
2037 if (pMode->RefreshRate != 0) {
2038 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2041 /* Only change the mode if necessary */
2042 if( (This->ddraw_width == pMode->Width) &&
2043 (This->ddraw_height == pMode->Height) &&
2044 (This->ddraw_format == pMode->Format) &&
2045 (pMode->RefreshRate == 0) ) {
2049 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2050 if (ret != DISP_CHANGE_SUCCESSFUL) {
2051 if(devmode.dmDisplayFrequency != 0) {
2052 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2053 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2054 devmode.dmDisplayFrequency = 0;
2055 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2057 if(ret != DISP_CHANGE_SUCCESSFUL) {
2058 return WINED3DERR_NOTAVAILABLE;
2062 /* Store the new values */
2063 This->ddraw_width = pMode->Width;
2064 This->ddraw_height = pMode->Height;
2065 This->ddraw_format = pMode->Format;
2067 /* Only do this with a window of course */
2068 if(This->ddraw_window)
2069 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2071 /* And finally clip mouse to our screen */
2072 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2073 ClipCursor(&clip_rc);
2078 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2080 *ppD3D= This->wineD3D;
2081 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2082 IWineD3D_AddRef(*ppD3D);
2086 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2087 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2088 * into the video ram as possible and seeing how many fit
2089 * you can also get the correct initial value from nvidia and ATI's driver via X
2090 * texture memory is video memory + AGP memory
2091 *******************/
2092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2093 static BOOL showfixmes = TRUE;
2095 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2096 (wined3d_settings.emulated_textureram/(1024*1024)),
2097 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2100 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2101 (wined3d_settings.emulated_textureram/(1024*1024)),
2102 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2103 /* return simulated texture memory left */
2104 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2112 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2115 /* Update the current state block */
2116 This->updateStateBlock->changed.fvf = TRUE;
2117 This->updateStateBlock->set.fvf = TRUE;
2119 if(This->updateStateBlock->fvf == fvf) {
2120 TRACE("Application is setting the old fvf over, nothing to do\n");
2124 This->updateStateBlock->fvf = fvf;
2125 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2131 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2133 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2134 *pfvf = This->stateBlock->fvf;
2139 * Get / Set Stream Source
2141 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2143 IWineD3DVertexBuffer *oldSrc;
2145 if (StreamNumber >= MAX_STREAMS) {
2146 WARN("Stream out of range %d\n", StreamNumber);
2147 return WINED3DERR_INVALIDCALL;
2150 oldSrc = This->stateBlock->streamSource[StreamNumber];
2151 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2153 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2154 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2156 if(oldSrc == pStreamData &&
2157 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2158 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2159 TRACE("Application is setting the old values over, nothing to do\n");
2163 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2165 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2166 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2169 /* Handle recording of state blocks */
2170 if (This->isRecordingState) {
2171 TRACE("Recording... not performing anything\n");
2175 /* Need to do a getParent and pass the reffs up */
2176 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2177 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2178 so for now, just count internally */
2179 if (pStreamData != NULL) {
2180 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2181 InterlockedIncrement(&vbImpl->bindCount);
2183 if (oldSrc != NULL) {
2184 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2192 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2195 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2196 This->stateBlock->streamSource[StreamNumber],
2197 This->stateBlock->streamOffset[StreamNumber],
2198 This->stateBlock->streamStride[StreamNumber]);
2200 if (StreamNumber >= MAX_STREAMS) {
2201 WARN("Stream out of range %d\n", StreamNumber);
2202 return WINED3DERR_INVALIDCALL;
2204 *pStream = This->stateBlock->streamSource[StreamNumber];
2205 *pStride = This->stateBlock->streamStride[StreamNumber];
2207 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2210 if (*pStream != NULL) {
2211 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2216 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2218 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2219 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2221 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2222 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2224 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2225 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2226 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2228 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2229 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2236 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2239 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2240 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2242 TRACE("(%p) : returning %d\n", This, *Divider);
2248 * Get / Set & Multiply Transform
2250 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2253 /* Most of this routine, comments included copied from ddraw tree initially: */
2254 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2256 /* Handle recording of state blocks */
2257 if (This->isRecordingState) {
2258 TRACE("Recording... not performing anything\n");
2259 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2260 This->updateStateBlock->set.transform[d3dts] = TRUE;
2261 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2266 * If the new matrix is the same as the current one,
2267 * we cut off any further processing. this seems to be a reasonable
2268 * optimization because as was noticed, some apps (warcraft3 for example)
2269 * tend towards setting the same matrix repeatedly for some reason.
2271 * From here on we assume that the new matrix is different, wherever it matters.
2273 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2274 TRACE("The app is setting the same matrix over again\n");
2277 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2281 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2282 where ViewMat = Camera space, WorldMat = world space.
2284 In OpenGL, camera and world space is combined into GL_MODELVIEW
2285 matrix. The Projection matrix stay projection matrix.
2288 /* Capture the times we can just ignore the change for now */
2289 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2290 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2291 /* Handled by the state manager */
2294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2298 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2300 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2301 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2305 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2306 WINED3DMATRIX *mat = NULL;
2309 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2310 * below means it will be recorded in a state block change, but it
2311 * works regardless where it is recorded.
2312 * If this is found to be wrong, change to StateBlock.
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2315 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2317 if (State < HIGHEST_TRANSFORMSTATE)
2319 mat = &This->updateStateBlock->transforms[State];
2321 FIXME("Unhandled transform state!!\n");
2324 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2326 /* Apply change via set transform - will reapply to eg. lights this way */
2327 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2333 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2334 you can reference any indexes you want as long as that number max are enabled at any
2335 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2336 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2337 but when recording, just build a chain pretty much of commands to be replayed. */
2339 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2341 PLIGHTINFOEL *object = NULL;
2342 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2346 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2348 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2352 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2353 return WINED3DERR_INVALIDCALL;
2356 switch(pLight->Type) {
2357 case WINED3DLIGHT_POINT:
2358 case WINED3DLIGHT_SPOT:
2359 case WINED3DLIGHT_PARALLELPOINT:
2360 case WINED3DLIGHT_GLSPOT:
2361 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2364 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2365 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2366 return WINED3DERR_INVALIDCALL;
2370 case WINED3DLIGHT_DIRECTIONAL:
2371 /* Ignores attenuation */
2375 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2376 return WINED3DERR_INVALIDCALL;
2379 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2380 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2381 if(object->OriginalIndex == Index) break;
2386 TRACE("Adding new light\n");
2387 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2389 ERR("Out of memory error when allocating a light\n");
2390 return E_OUTOFMEMORY;
2392 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2393 object->glIndex = -1;
2394 object->OriginalIndex = Index;
2395 object->changed = TRUE;
2398 /* Initialize the object */
2399 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,
2400 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2401 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2402 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2403 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2404 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2405 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2407 /* Save away the information */
2408 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2410 switch (pLight->Type) {
2411 case WINED3DLIGHT_POINT:
2413 object->lightPosn[0] = pLight->Position.x;
2414 object->lightPosn[1] = pLight->Position.y;
2415 object->lightPosn[2] = pLight->Position.z;
2416 object->lightPosn[3] = 1.0f;
2417 object->cutoff = 180.0f;
2421 case WINED3DLIGHT_DIRECTIONAL:
2423 object->lightPosn[0] = -pLight->Direction.x;
2424 object->lightPosn[1] = -pLight->Direction.y;
2425 object->lightPosn[2] = -pLight->Direction.z;
2426 object->lightPosn[3] = 0.0;
2427 object->exponent = 0.0f;
2428 object->cutoff = 180.0f;
2431 case WINED3DLIGHT_SPOT:
2433 object->lightPosn[0] = pLight->Position.x;
2434 object->lightPosn[1] = pLight->Position.y;
2435 object->lightPosn[2] = pLight->Position.z;
2436 object->lightPosn[3] = 1.0;
2439 object->lightDirn[0] = pLight->Direction.x;
2440 object->lightDirn[1] = pLight->Direction.y;
2441 object->lightDirn[2] = pLight->Direction.z;
2442 object->lightDirn[3] = 1.0;
2445 * opengl-ish and d3d-ish spot lights use too different models for the
2446 * light "intensity" as a function of the angle towards the main light direction,
2447 * so we only can approximate very roughly.
2448 * however spot lights are rather rarely used in games (if ever used at all).
2449 * furthermore if still used, probably nobody pays attention to such details.
2451 if (pLight->Falloff == 0) {
2454 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2456 if (rho < 0.0001) rho = 0.0001f;
2457 object->exponent = -0.3/log(cos(rho/2));
2458 if (object->exponent > 128.0) {
2459 object->exponent = 128.0;
2461 object->cutoff = pLight->Phi*90/M_PI;
2467 FIXME("Unrecognized light type %d\n", pLight->Type);
2470 /* Update the live definitions if the light is currently assigned a glIndex */
2471 if (object->glIndex != -1 && !This->isRecordingState) {
2472 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2477 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2478 PLIGHTINFOEL *lightInfo = NULL;
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2480 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2482 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2484 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2485 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2486 if(lightInfo->OriginalIndex == Index) break;
2490 if (lightInfo == NULL) {
2491 TRACE("Light information requested but light not defined\n");
2492 return WINED3DERR_INVALIDCALL;
2495 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2500 * Get / Set Light Enable
2501 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2503 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2504 PLIGHTINFOEL *lightInfo = NULL;
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2508 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2510 /* Tests show true = 128...not clear why */
2511 Enable = Enable? 128: 0;
2513 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2514 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2515 if(lightInfo->OriginalIndex == Index) break;
2518 TRACE("Found light: %p\n", lightInfo);
2520 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2521 if (lightInfo == NULL) {
2523 TRACE("Light enabled requested but light not defined, so defining one!\n");
2524 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2526 /* Search for it again! Should be fairly quick as near head of list */
2527 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2528 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2529 if(lightInfo->OriginalIndex == Index) break;
2532 if (lightInfo == NULL) {
2533 FIXME("Adding default lights has failed dismally\n");
2534 return WINED3DERR_INVALIDCALL;
2538 lightInfo->enabledChanged = TRUE;
2540 if(lightInfo->glIndex != -1) {
2541 if(!This->isRecordingState) {
2542 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2545 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2546 lightInfo->glIndex = -1;
2548 TRACE("Light already disabled, nothing to do\n");
2551 if (lightInfo->glIndex != -1) {
2553 TRACE("Nothing to do as light was enabled\n");
2556 /* Find a free gl light */
2557 for(i = 0; i < This->maxConcurrentLights; i++) {
2558 if(This->stateBlock->activeLights[i] == NULL) {
2559 This->stateBlock->activeLights[i] = lightInfo;
2560 lightInfo->glIndex = i;
2564 if(lightInfo->glIndex == -1) {
2565 ERR("Too many concurrently active lights\n");
2566 return WINED3DERR_INVALIDCALL;
2569 /* i == lightInfo->glIndex */
2570 if(!This->isRecordingState) {
2571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2579 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2581 PLIGHTINFOEL *lightInfo = NULL;
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2584 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2585 TRACE("(%p) : for idx(%d)\n", This, Index);
2587 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2588 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2589 if(lightInfo->OriginalIndex == Index) break;
2593 if (lightInfo == NULL) {
2594 TRACE("Light enabled state requested but light not defined\n");
2595 return WINED3DERR_INVALIDCALL;
2597 /* true is 128 according to SetLightEnable */
2598 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2603 * Get / Set Clip Planes
2605 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2609 /* Validate Index */
2610 if (Index >= GL_LIMITS(clipplanes)) {
2611 TRACE("Application has requested clipplane this device doesn't support\n");
2612 return WINED3DERR_INVALIDCALL;
2615 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2616 This->updateStateBlock->set.clipplane[Index] = TRUE;
2618 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2619 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2620 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2621 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2622 TRACE("Application is setting old values over, nothing to do\n");
2626 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2627 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2628 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2629 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2631 /* Handle recording of state blocks */
2632 if (This->isRecordingState) {
2633 TRACE("Recording... not performing anything\n");
2637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2642 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2644 TRACE("(%p) : for idx %d\n", This, Index);
2646 /* Validate Index */
2647 if (Index >= GL_LIMITS(clipplanes)) {
2648 TRACE("Application has requested clipplane this device doesn't support\n");
2649 return WINED3DERR_INVALIDCALL;
2652 pPlane[0] = This->stateBlock->clipplane[Index][0];
2653 pPlane[1] = This->stateBlock->clipplane[Index][1];
2654 pPlane[2] = This->stateBlock->clipplane[Index][2];
2655 pPlane[3] = This->stateBlock->clipplane[Index][3];
2660 * Get / Set Clip Plane Status
2661 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2663 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2665 FIXME("(%p) : stub\n", This);
2666 if (NULL == pClipStatus) {
2667 return WINED3DERR_INVALIDCALL;
2669 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2670 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2674 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2676 FIXME("(%p) : stub\n", This);
2677 if (NULL == pClipStatus) {
2678 return WINED3DERR_INVALIDCALL;
2680 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2681 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2686 * Get / Set Material
2688 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 This->updateStateBlock->changed.material = TRUE;
2692 This->updateStateBlock->set.material = TRUE;
2693 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2695 /* Handle recording of state blocks */
2696 if (This->isRecordingState) {
2697 TRACE("Recording... not performing anything\n");
2702 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2703 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2704 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2705 pMaterial->Ambient.b, pMaterial->Ambient.a);
2706 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2707 pMaterial->Specular.b, pMaterial->Specular.a);
2708 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2709 pMaterial->Emissive.b, pMaterial->Emissive.a);
2710 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2712 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2713 checkGLcall("glMaterialfv(GL_AMBIENT)");
2714 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2715 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2717 /* Only change material color if specular is enabled, otherwise it is set to black */
2718 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2719 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2720 checkGLcall("glMaterialfv(GL_SPECULAR");
2722 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2723 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2724 checkGLcall("glMaterialfv(GL_SPECULAR");
2726 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2727 checkGLcall("glMaterialfv(GL_EMISSION)");
2728 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2729 checkGLcall("glMaterialf(GL_SHININESS");
2735 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2738 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2739 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2740 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2741 pMaterial->Ambient.b, pMaterial->Ambient.a);
2742 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2743 pMaterial->Specular.b, pMaterial->Specular.a);
2744 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2745 pMaterial->Emissive.b, pMaterial->Emissive.a);
2746 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2754 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2756 IWineD3DIndexBuffer *oldIdxs;
2758 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2759 oldIdxs = This->updateStateBlock->pIndexData;
2761 This->updateStateBlock->changed.indices = TRUE;
2762 This->updateStateBlock->set.indices = TRUE;
2763 This->updateStateBlock->pIndexData = pIndexData;
2765 /* Handle recording of state blocks */
2766 if (This->isRecordingState) {
2767 TRACE("Recording... not performing anything\n");
2771 if(oldIdxs != pIndexData) {
2772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2777 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData, UINT* pBaseVertexIndex) {
2778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2780 *ppIndexData = This->stateBlock->pIndexData;
2782 /* up ref count on ppindexdata */
2784 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2785 *pBaseVertexIndex = This->stateBlock->baseVertexIndex;
2786 TRACE("(%p) index data set to %p + %u\n", This, ppIndexData, This->stateBlock->baseVertexIndex);
2788 TRACE("(%p) No index data set\n", This);
2790 TRACE("Returning %p %d\n", *ppIndexData, *pBaseVertexIndex);
2795 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2796 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2798 TRACE("(%p)->(%d)\n", This, BaseIndex);
2800 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2801 TRACE("Application is setting the old value over, nothing to do\n");
2805 This->updateStateBlock->baseVertexIndex = BaseIndex;
2807 if (This->isRecordingState) {
2808 TRACE("Recording... not performing anything\n");
2811 /* The base vertex index affects the stream sources */
2812 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2817 * Get / Set Viewports
2819 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2822 TRACE("(%p)\n", This);
2823 This->updateStateBlock->changed.viewport = TRUE;
2824 This->updateStateBlock->set.viewport = TRUE;
2825 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2827 /* Handle recording of state blocks */
2828 if (This->isRecordingState) {
2829 TRACE("Recording... not performing anything\n");
2833 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2834 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2841 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2843 TRACE("(%p)\n", This);
2844 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2849 * Get / Set Render States
2850 * TODO: Verify against dx9 definitions
2852 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2855 DWORD oldValue = This->stateBlock->renderState[State];
2857 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2859 This->updateStateBlock->changed.renderState[State] = TRUE;
2860 This->updateStateBlock->set.renderState[State] = TRUE;
2861 This->updateStateBlock->renderState[State] = Value;
2863 /* Handle recording of state blocks */
2864 if (This->isRecordingState) {
2865 TRACE("Recording... not performing anything\n");
2869 /* Compared here and not before the assignment to allow proper stateblock recording */
2870 if(Value == oldValue) {
2871 TRACE("Application is setting the old value over, nothing to do\n");
2873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2879 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2882 *pValue = This->stateBlock->renderState[State];
2887 * Get / Set Sampler States
2888 * TODO: Verify against dx9 definitions
2891 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2893 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2896 * SetSampler is designed to allow for more than the standard up to 8 textures
2897 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2898 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2900 * http://developer.nvidia.com/object/General_FAQ.html#t6
2902 * There are two new settings for GForce
2904 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2905 * and the texture one:
2906 * GL_MAX_TEXTURE_COORDS_ARB.
2907 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2910 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2911 debug_d3dsamplerstate(Type), Type, Value);
2912 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2913 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2914 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2916 /* Handle recording of state blocks */
2917 if (This->isRecordingState) {
2918 TRACE("Recording... not performing anything\n");
2922 if(oldValue == Value) {
2923 TRACE("Application is setting the old value over, nothing to do\n");
2927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2932 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 *Value = This->stateBlock->samplerState[Sampler][Type];
2935 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2940 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 This->updateStateBlock->set.scissorRect = TRUE;
2944 This->updateStateBlock->changed.scissorRect = TRUE;
2945 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2946 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2949 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2951 if(This->isRecordingState) {
2952 TRACE("Recording... not performing anything\n");
2956 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2961 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2965 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2969 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2971 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2973 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2975 This->updateStateBlock->vertexDecl = pDecl;
2976 This->updateStateBlock->changed.vertexDecl = TRUE;
2977 This->updateStateBlock->set.vertexDecl = TRUE;
2979 if (This->isRecordingState) {
2980 TRACE("Recording... not performing anything\n");
2982 } else if(pDecl == oldDecl) {
2983 /* Checked after the assignment to allow proper stateblock recording */
2984 TRACE("Application is setting the old declaration over, nothing to do\n");
2988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2992 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2997 *ppDecl = This->stateBlock->vertexDecl;
2998 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3002 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3006 This->updateStateBlock->vertexShader = pShader;
3007 This->updateStateBlock->changed.vertexShader = TRUE;
3008 This->updateStateBlock->set.vertexShader = TRUE;
3010 if (This->isRecordingState) {
3011 TRACE("Recording... not performing anything\n");
3013 } else if(oldShader == pShader) {
3014 /* Checked here to allow proper stateblock recording */
3015 TRACE("App is setting the old shader over, nothing to do\n");
3019 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3026 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 if (NULL == ppShader) {
3030 return WINED3DERR_INVALIDCALL;
3032 *ppShader = This->stateBlock->vertexShader;
3033 if( NULL != *ppShader)
3034 IWineD3DVertexShader_AddRef(*ppShader);
3036 TRACE("(%p) : returning %p\n", This, *ppShader);
3040 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3041 IWineD3DDevice *iface,
3043 CONST BOOL *srcData,
3046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3047 int i, cnt = min(count, MAX_CONST_B - start);
3049 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3050 iface, srcData, start, count);
3052 if (srcData == NULL || cnt < 0)
3053 return WINED3DERR_INVALIDCALL;
3055 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3056 for (i = 0; i < cnt; i++)
3057 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3059 for (i = start; i < cnt + start; ++i) {
3060 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3061 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3069 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3070 IWineD3DDevice *iface,
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3076 int cnt = min(count, MAX_CONST_B - start);
3078 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3079 iface, dstData, start, count);
3081 if (dstData == NULL || cnt < 0)
3082 return WINED3DERR_INVALIDCALL;
3084 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3088 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3089 IWineD3DDevice *iface,
3094 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3095 int i, cnt = min(count, MAX_CONST_I - start);
3097 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3098 iface, srcData, start, count);
3100 if (srcData == NULL || cnt < 0)
3101 return WINED3DERR_INVALIDCALL;
3103 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3104 for (i = 0; i < cnt; i++)
3105 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3106 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3108 for (i = start; i < cnt + start; ++i) {
3109 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3110 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3118 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3119 IWineD3DDevice *iface,
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 int cnt = min(count, MAX_CONST_I - start);
3127 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3128 iface, dstData, start, count);
3130 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3131 return WINED3DERR_INVALIDCALL;
3133 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3137 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3138 IWineD3DDevice *iface,
3140 CONST float *srcData,
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3147 iface, srcData, start, count);
3149 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3150 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3151 return WINED3DERR_INVALIDCALL;
3153 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3155 for (i = 0; i < count; i++)
3156 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3157 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3160 for (i = start; i < count + start; ++i) {
3161 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3162 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3163 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3164 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3165 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3167 ptr->idx[ptr->count++] = i;
3168 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3170 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3178 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3179 IWineD3DDevice *iface,
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3185 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3187 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3188 iface, dstData, start, count);
3190 if (dstData == NULL || cnt < 0)
3191 return WINED3DERR_INVALIDCALL;
3193 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3197 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3199 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3204 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3206 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3207 * it is never called.
3210 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3211 * that would be really messy and require shader recompilation
3212 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3213 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3214 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3215 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3217 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3218 if(This->oneToOneTexUnitMap) {
3219 TRACE("Not touching 1:1 map\n");
3222 TRACE("Restoring 1:1 texture unit mapping\n");
3223 /* Restore a 1:1 mapping */
3224 for(i = 0; i < MAX_SAMPLERS; i++) {
3225 if(This->texUnitMap[i] != i) {
3226 This->texUnitMap[i] = i;
3227 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3228 markTextureStagesDirty(This, i);
3231 This->oneToOneTexUnitMap = TRUE;
3234 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3235 * First, see if we can succeed at all
3238 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3239 if(This->stateBlock->textures[i] == NULL) tex++;
3242 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3243 FIXME("Too many bound textures to support the combiner settings\n");
3247 /* Now work out the mapping */
3249 This->oneToOneTexUnitMap = FALSE;
3250 WARN("Non 1:1 mapping UNTESTED!\n");
3251 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3252 /* Skip NULL textures */
3253 if (!This->stateBlock->textures[i]) {
3254 /* Map to -1, so the check below doesn't fail if a non-NULL
3255 * texture is set on this stage */
3256 TRACE("Mapping texture stage %d to -1\n", i);
3257 This->texUnitMap[i] = -1;
3262 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3263 if(This->texUnitMap[i] != tex) {
3264 This->texUnitMap[i] = tex;
3265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3266 markTextureStagesDirty(This, i);
3274 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3276 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3277 This->updateStateBlock->pixelShader = pShader;
3278 This->updateStateBlock->changed.pixelShader = TRUE;
3279 This->updateStateBlock->set.pixelShader = TRUE;
3281 /* Handle recording of state blocks */
3282 if (This->isRecordingState) {
3283 TRACE("Recording... not performing anything\n");
3286 if (This->isRecordingState) {
3287 TRACE("Recording... not performing anything\n");
3291 if(pShader == oldShader) {
3292 TRACE("App is setting the old pixel shader over, nothing to do\n");
3296 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3299 /* Rebuild the texture unit mapping if nvrc's are supported */
3300 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3301 IWineD3DDeviceImpl_FindTexUnitMap(This);
3307 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3310 if (NULL == ppShader) {
3311 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3312 return WINED3DERR_INVALIDCALL;
3315 *ppShader = This->stateBlock->pixelShader;
3316 if (NULL != *ppShader) {
3317 IWineD3DPixelShader_AddRef(*ppShader);
3319 TRACE("(%p) : returning %p\n", This, *ppShader);
3323 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3324 IWineD3DDevice *iface,
3326 CONST BOOL *srcData,
3329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3330 int i, cnt = min(count, MAX_CONST_B - start);
3332 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3333 iface, srcData, start, count);
3335 if (srcData == NULL || cnt < 0)
3336 return WINED3DERR_INVALIDCALL;
3338 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3339 for (i = 0; i < cnt; i++)
3340 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3342 for (i = start; i < cnt + start; ++i) {
3343 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3344 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3352 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3353 IWineD3DDevice *iface,
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 int cnt = min(count, MAX_CONST_B - start);
3361 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3362 iface, dstData, start, count);
3364 if (dstData == NULL || cnt < 0)
3365 return WINED3DERR_INVALIDCALL;
3367 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3371 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3372 IWineD3DDevice *iface,
3377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3378 int i, cnt = min(count, MAX_CONST_I - start);
3380 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3381 iface, srcData, start, count);
3383 if (srcData == NULL || cnt < 0)
3384 return WINED3DERR_INVALIDCALL;
3386 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3387 for (i = 0; i < cnt; i++)
3388 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3389 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3391 for (i = start; i < cnt + start; ++i) {
3392 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3393 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3401 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3402 IWineD3DDevice *iface,
3407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3408 int cnt = min(count, MAX_CONST_I - start);
3410 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3411 iface, dstData, start, count);
3413 if (dstData == NULL || cnt < 0)
3414 return WINED3DERR_INVALIDCALL;
3416 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3420 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3421 IWineD3DDevice *iface,
3423 CONST float *srcData,
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3429 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3430 iface, srcData, start, count);
3432 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3433 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3434 return WINED3DERR_INVALIDCALL;
3436 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3438 for (i = 0; i < count; i++)
3439 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3440 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3443 for (i = start; i < count + start; ++i) {
3444 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3445 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3446 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3447 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3448 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3450 ptr->idx[ptr->count++] = i;
3451 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3453 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3461 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3462 IWineD3DDevice *iface,
3467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3468 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3470 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3471 iface, dstData, start, count);
3473 if (dstData == NULL || cnt < 0)
3474 return WINED3DERR_INVALIDCALL;
3476 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3480 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3482 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3483 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3485 DWORD DestFVF = dest->fvf;
3487 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3491 if (lpStrideData->u.s.normal.lpData) {
3492 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3495 if (lpStrideData->u.s.position.lpData == NULL) {
3496 ERR("Source has no position mask\n");
3497 return WINED3DERR_INVALIDCALL;
3500 /* We might access VBOs from this code, so hold the lock */
3503 if (dest->resource.allocatedMemory == NULL) {
3504 /* This may happen if we do direct locking into a vbo. Unlikely,
3505 * but theoretically possible(ddraw processvertices test)
3507 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3508 if(!dest->resource.allocatedMemory) {
3510 ERR("Out of memory\n");
3511 return E_OUTOFMEMORY;
3515 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3516 checkGLcall("glBindBufferARB");
3517 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3519 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3521 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3522 checkGLcall("glUnmapBufferARB");
3526 /* Get a pointer into the destination vbo(create one if none exists) and
3527 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3529 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3534 unsigned char extrabytes = 0;
3535 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3536 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3537 * this may write 4 extra bytes beyond the area that should be written
3539 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3540 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3541 if(!dest_conv_addr) {
3542 ERR("Out of memory\n");
3543 /* Continue without storing converted vertices */
3545 dest_conv = dest_conv_addr;
3549 * a) WINED3DRS_CLIPPING is enabled
3550 * b) WINED3DVOP_CLIP is passed
3552 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3553 static BOOL warned = FALSE;
3555 * The clipping code is not quite correct. Some things need
3556 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3557 * so disable clipping for now.
3558 * (The graphics in Half-Life are broken, and my processvertices
3559 * test crashes with IDirect3DDevice3)
3565 FIXME("Clipping is broken and disabled for now\n");
3567 } else doClip = FALSE;
3568 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3570 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3573 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3574 WINED3DTS_PROJECTION,
3576 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3577 WINED3DTS_WORLDMATRIX(0),
3580 TRACE("View mat:\n");
3581 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);
3582 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);
3583 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);
3584 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);
3586 TRACE("Proj mat:\n");
3587 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);
3588 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);
3589 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);
3590 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);
3592 TRACE("World mat:\n");
3593 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);
3594 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);
3595 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);
3596 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);
3598 /* Get the viewport */
3599 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3600 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3601 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3603 multiply_matrix(&mat,&view_mat,&world_mat);
3604 multiply_matrix(&mat,&proj_mat,&mat);
3606 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3608 for (i = 0; i < dwCount; i+= 1) {
3609 unsigned int tex_index;
3611 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3612 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3613 /* The position first */
3615 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3617 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3619 /* Multiplication with world, view and projection matrix */
3620 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);
3621 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);
3622 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);
3623 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);
3625 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3627 /* WARNING: The following things are taken from d3d7 and were not yet checked
3628 * against d3d8 or d3d9!
3631 /* Clipping conditions: From
3632 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3634 * A vertex is clipped if it does not match the following requirements
3638 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3640 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3641 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3646 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3647 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3650 /* "Normal" viewport transformation (not clipped)
3651 * 1) The values are divided by rhw
3652 * 2) The y axis is negative, so multiply it with -1
3653 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3654 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3655 * 4) Multiply x with Width/2 and add Width/2
3656 * 5) The same for the height
3657 * 6) Add the viewpoint X and Y to the 2D coordinates and
3658 * The minimum Z value to z
3659 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3661 * Well, basically it's simply a linear transformation into viewport
3673 z *= vp.MaxZ - vp.MinZ;
3675 x += vp.Width / 2 + vp.X;
3676 y += vp.Height / 2 + vp.Y;
3681 /* That vertex got clipped
3682 * Contrary to OpenGL it is not dropped completely, it just
3683 * undergoes a different calculation.
3685 TRACE("Vertex got clipped\n");
3692 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3693 * outside of the main vertex buffer memory. That needs some more
3698 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3701 ( (float *) dest_ptr)[0] = x;
3702 ( (float *) dest_ptr)[1] = y;
3703 ( (float *) dest_ptr)[2] = z;
3704 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3706 dest_ptr += 3 * sizeof(float);
3708 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3709 dest_ptr += sizeof(float);
3714 ( (float *) dest_conv)[0] = x * w;
3715 ( (float *) dest_conv)[1] = y * w;
3716 ( (float *) dest_conv)[2] = z * w;
3717 ( (float *) dest_conv)[3] = w;
3719 dest_conv += 3 * sizeof(float);
3721 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3722 dest_conv += sizeof(float);
3726 if (DestFVF & WINED3DFVF_PSIZE) {
3727 dest_ptr += sizeof(DWORD);
3728 if(dest_conv) dest_conv += sizeof(DWORD);
3730 if (DestFVF & WINED3DFVF_NORMAL) {
3732 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3733 /* AFAIK this should go into the lighting information */
3734 FIXME("Didn't expect the destination to have a normal\n");
3735 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3737 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3741 if (DestFVF & WINED3DFVF_DIFFUSE) {
3743 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3745 static BOOL warned = FALSE;
3748 ERR("No diffuse color in source, but destination has one\n");
3752 *( (DWORD *) dest_ptr) = 0xffffffff;
3753 dest_ptr += sizeof(DWORD);
3756 *( (DWORD *) dest_conv) = 0xffffffff;
3757 dest_conv += sizeof(DWORD);
3761 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3763 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3764 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3765 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3766 dest_conv += sizeof(DWORD);
3771 if (DestFVF & WINED3DFVF_SPECULAR) {
3772 /* What's the color value in the feedback buffer? */
3774 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3776 static BOOL warned = FALSE;
3779 ERR("No specular color in source, but destination has one\n");
3783 *( (DWORD *) dest_ptr) = 0xFF000000;
3784 dest_ptr += sizeof(DWORD);
3787 *( (DWORD *) dest_conv) = 0xFF000000;
3788 dest_conv += sizeof(DWORD);
3792 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3794 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3795 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3796 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3797 dest_conv += sizeof(DWORD);
3802 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3804 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3805 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3807 ERR("No source texture, but destination requests one\n");
3808 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3809 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3812 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3814 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3821 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3822 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3823 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3824 dwCount * get_flexible_vertex_size(DestFVF),
3826 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3827 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3834 #undef copy_and_next
3836 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3838 WineDirect3DVertexStridedData strided;
3839 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3840 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3843 ERR("Output vertex declaration not implemented yet\n");
3846 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3847 * and this call is quite performance critical, so don't call needlessly
3849 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3851 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3855 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3856 * control the streamIsUP flag, thus restore it afterwards.
3858 This->stateBlock->streamIsUP = FALSE;
3859 memset(&strided, 0, sizeof(strided));
3860 if(This->stateBlock->vertexDecl) {
3861 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3863 primitiveConvertToStridedData(iface, &strided, &vbo);
3865 This->stateBlock->streamIsUP = streamWasUP;
3867 if(vbo || SrcStartIndex) {
3869 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3870 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3872 * Also get the start index in, but only loop over all elements if there's something to add at all.
3874 #define FIXSRC(type) \
3875 if(strided.u.s.type.VBO) { \
3876 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3877 strided.u.s.type.VBO = 0; \
3878 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3880 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3884 if(strided.u.s.type.lpData) { \
3885 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3888 FIXSRC(blendWeights);
3889 FIXSRC(blendMatrixIndices);
3894 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3895 FIXSRC(texCoords[i]);
3908 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3912 * Get / Set Texture Stage States
3913 * TODO: Verify against dx9 definitions
3915 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3917 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3919 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3921 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3923 if (Stage >= MAX_TEXTURES) {
3924 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3928 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3929 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3930 This->updateStateBlock->textureState[Stage][Type] = Value;
3932 if (This->isRecordingState) {
3933 TRACE("Recording... not performing anything\n");
3937 /* Checked after the assignments to allow proper stateblock recording */
3938 if(oldValue == Value) {
3939 TRACE("App is setting the old value over, nothing to do\n");
3943 if(Stage > This->stateBlock->lowest_disabled_stage &&
3944 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3945 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3946 * Changes in other states are important on disabled stages too
3951 if(Type == WINED3DTSS_COLOROP) {
3954 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3955 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3956 * they have to be disabled
3958 * The current stage is dirtified below.
3960 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3961 TRACE("Additionally dirtifying stage %d\n", i);
3962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3964 This->stateBlock->lowest_disabled_stage = Stage;
3965 TRACE("New lowest disabled: %d\n", Stage);
3966 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3967 /* Previously disabled stage enabled. Stages above it may need enabling
3968 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3969 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3971 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3974 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3975 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3978 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3981 This->stateBlock->lowest_disabled_stage = i;
3982 TRACE("New lowest disabled: %d\n", i);
3984 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3985 /* TODO: Built a stage -> texture unit mapping for register combiners */
3989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
3991 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
3992 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
3993 * will call FindTexUnitMap too.
3995 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3996 IWineD3DDeviceImpl_FindTexUnitMap(This);
4001 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4003 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4004 *pValue = This->updateStateBlock->textureState[Stage][Type];
4011 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4014 IWineD3DBaseTexture *oldTexture;
4016 oldTexture = This->updateStateBlock->textures[Stage];
4017 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4019 #if 0 /* TODO: check so vertex textures */
4020 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4021 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4026 if(pTexture != NULL) {
4027 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4029 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4030 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4031 return WINED3DERR_INVALIDCALL;
4033 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4036 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4037 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4039 This->updateStateBlock->set.textures[Stage] = TRUE;
4040 This->updateStateBlock->changed.textures[Stage] = TRUE;
4041 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4042 This->updateStateBlock->textures[Stage] = pTexture;
4044 /* Handle recording of state blocks */
4045 if (This->isRecordingState) {
4046 TRACE("Recording... not performing anything\n");
4050 if(oldTexture == pTexture) {
4051 TRACE("App is setting the same texture again, nothing to do\n");
4055 /** NOTE: MSDN says that setTexture increases the reference count,
4056 * and the the application must set the texture back to null (or have a leaky application),
4057 * This means we should pass the refcount up to the parent
4058 *******************************/
4059 if (NULL != This->updateStateBlock->textures[Stage]) {
4060 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4061 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4063 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4064 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4065 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4066 * so the COLOROP and ALPHAOP have to be dirtified.
4068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4071 if(bindCount == 1) {
4072 new->baseTexture.sampler = Stage;
4074 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4078 if (NULL != oldTexture) {
4079 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4080 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4082 IWineD3DBaseTexture_Release(oldTexture);
4083 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4088 if(bindCount && old->baseTexture.sampler == Stage) {
4090 /* Have to do a search for the other sampler(s) where the texture is bound to
4091 * Shouldn't happen as long as apps bind a texture only to one stage
4093 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4094 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4095 if(This->updateStateBlock->textures[i] == oldTexture) {
4096 old->baseTexture.sampler = i;
4103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4105 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4106 * pixel shader is used
4108 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4109 IWineD3DDeviceImpl_FindTexUnitMap(This);
4115 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4117 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4119 *ppTexture=This->stateBlock->textures[Stage];
4121 IWineD3DBaseTexture_AddRef(*ppTexture);
4129 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4130 IWineD3DSurface **ppBackBuffer) {
4131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4132 IWineD3DSwapChain *swapChain;
4135 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4137 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4138 if (hr == WINED3D_OK) {
4139 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4140 IWineD3DSwapChain_Release(swapChain);
4142 *ppBackBuffer = NULL;
4147 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4149 WARN("(%p) : stub, calling idirect3d for now\n", This);
4150 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4153 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4155 IWineD3DSwapChain *swapChain;
4158 if(iSwapChain > 0) {
4159 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4160 if (hr == WINED3D_OK) {
4161 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4162 IWineD3DSwapChain_Release(swapChain);
4164 FIXME("(%p) Error getting display mode\n", This);
4167 /* Don't read the real display mode,
4168 but return the stored mode instead. X11 can't change the color
4169 depth, and some apps are pretty angry if they SetDisplayMode from
4170 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4172 Also don't relay to the swapchain because with ddraw it's possible
4173 that there isn't a swapchain at all */
4174 pMode->Width = This->ddraw_width;
4175 pMode->Height = This->ddraw_height;
4176 pMode->Format = This->ddraw_format;
4177 pMode->RefreshRate = 0;
4184 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4186 TRACE("(%p)->(%p)\n", This, hWnd);
4188 if(This->ddraw_fullscreen) {
4189 if(This->ddraw_window && This->ddraw_window != hWnd) {
4190 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4192 if(hWnd && This->ddraw_window != hWnd) {
4193 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4197 This->ddraw_window = hWnd;
4201 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4203 TRACE("(%p)->(%p)\n", This, hWnd);
4205 *hWnd = This->ddraw_window;
4210 * Stateblock related functions
4213 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4215 IWineD3DStateBlockImpl *object;
4216 HRESULT temp_result;
4219 TRACE("(%p)\n", This);
4221 if (This->isRecordingState) {
4222 return WINED3DERR_INVALIDCALL;
4225 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4226 if (NULL == object ) {
4227 FIXME("(%p)Error allocating memory for stateblock\n", This);
4228 return E_OUTOFMEMORY;
4230 TRACE("(%p) created object %p\n", This, object);
4231 object->wineD3DDevice= This;
4232 /** FIXME: object->parent = parent; **/
4233 object->parent = NULL;
4234 object->blockType = WINED3DSBT_ALL;
4236 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4238 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4239 list_init(&object->lightMap[i]);
4242 temp_result = allocate_shader_constants(object);
4243 if (WINED3D_OK != temp_result)
4246 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4247 This->updateStateBlock = object;
4248 This->isRecordingState = TRUE;
4250 TRACE("(%p) recording stateblock %p\n",This , object);
4254 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4257 if (!This->isRecordingState) {
4258 FIXME("(%p) not recording! returning error\n", This);
4259 *ppStateBlock = NULL;
4260 return WINED3DERR_INVALIDCALL;
4263 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4264 This->isRecordingState = FALSE;
4265 This->updateStateBlock = This->stateBlock;
4266 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4267 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4268 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4273 * Scene related functions
4275 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4276 /* At the moment we have no need for any functionality at the beginning
4278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4279 TRACE("(%p)\n", This);
4282 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4283 return WINED3DERR_INVALIDCALL;
4285 This->inScene = TRUE;
4289 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4290 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4291 TRACE("(%p)\n", This);
4293 if(!This->inScene) {
4294 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4295 return WINED3DERR_INVALIDCALL;
4299 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4300 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4302 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4304 checkGLcall("glFlush");
4307 This->inScene = FALSE;
4311 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4312 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4313 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4315 IWineD3DSwapChain *swapChain = NULL;
4317 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4319 TRACE("(%p) Presenting the frame\n", This);
4321 for(i = 0 ; i < swapchains ; i ++) {
4323 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4324 TRACE("presentinng chain %d, %p\n", i, swapChain);
4325 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4326 IWineD3DSwapChain_Release(swapChain);
4332 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4333 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4337 GLbitfield glMask = 0;
4339 CONST WINED3DRECT* curRect;
4341 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4342 Count, pRects, Flags, Color, Z, Stencil);
4344 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4345 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4346 /* TODO: What about depth stencil buffers without stencil bits? */
4347 return WINED3DERR_INVALIDCALL;
4351 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4352 * and not the last active one.
4355 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4356 apply_fbo_state(iface);
4359 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4361 glEnable(GL_SCISSOR_TEST);
4362 checkGLcall("glEnable GL_SCISSOR_TEST");
4363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4366 if (Count > 0 && pRects) {
4372 /* Only set the values up once, as they are not changing */
4373 if (Flags & WINED3DCLEAR_STENCIL) {
4374 glClearStencil(Stencil);
4375 checkGLcall("glClearStencil");
4376 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4377 glStencilMask(0xFFFFFFFF);
4380 if (Flags & WINED3DCLEAR_ZBUFFER) {
4381 glDepthMask(GL_TRUE);
4383 checkGLcall("glClearDepth");
4384 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4388 if (Flags & WINED3DCLEAR_TARGET) {
4389 TRACE("Clearing screen with glClear to color %x\n", Color);
4390 glClearColor(D3DCOLOR_R(Color),
4394 checkGLcall("glClearColor");
4396 /* Clear ALL colors! */
4397 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4398 glMask = glMask | GL_COLOR_BUFFER_BIT;
4402 /* In drawable flag is set below */
4404 glScissor(This->stateBlock->viewport.X,
4405 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4406 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4407 This->stateBlock->viewport.Width,
4408 This->stateBlock->viewport.Height);
4409 checkGLcall("glScissor");
4411 checkGLcall("glClear");
4413 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4414 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4416 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4417 curRect[0].x2 < target->currentDesc.Width ||
4418 curRect[0].y2 < target->currentDesc.Height) {
4419 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4420 blt_to_drawable(This, target);
4424 /* Now process each rect in turn */
4425 for (i = 0; i < Count; i++) {
4426 /* Note gl uses lower left, width/height */
4427 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4428 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4429 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4430 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4432 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4433 * The rectangle is not cleared, no error is returned, but further rectanlges are
4434 * still cleared if they are valid
4436 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4437 TRACE("Rectangle with negative dimensions, ignoring\n");
4441 if(This->render_offscreen) {
4442 glScissor(curRect[i].x1, curRect[i].y1,
4443 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4445 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4446 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4448 checkGLcall("glScissor");
4451 checkGLcall("glClear");
4455 /* Restore the old values (why..?) */
4456 if (Flags & WINED3DCLEAR_STENCIL) {
4457 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4459 if (Flags & WINED3DCLEAR_TARGET) {
4460 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4461 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4462 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4463 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4464 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4469 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4470 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4472 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4473 target->Flags |= SFLAG_INTEXTURE;
4474 target->Flags &= ~SFLAG_INSYSMEM;
4476 target->Flags |= SFLAG_INDRAWABLE;
4477 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4485 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4486 UINT PrimitiveCount) {
4488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4491 debug_d3dprimitivetype(PrimitiveType),
4492 StartVertex, PrimitiveCount);
4494 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4495 if(This->stateBlock->streamIsUP) {
4496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4497 This->stateBlock->streamIsUP = FALSE;
4500 if(This->stateBlock->loadBaseVertexIndex != 0) {
4501 This->stateBlock->loadBaseVertexIndex = 0;
4502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4504 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4505 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4506 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4510 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4511 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4512 WINED3DPRIMITIVETYPE PrimitiveType,
4513 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4517 IWineD3DIndexBuffer *pIB;
4518 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4521 pIB = This->stateBlock->pIndexData;
4523 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4524 * without an index buffer set. (The first time at least...)
4525 * D3D8 simply dies, but I doubt it can do much harm to return
4526 * D3DERR_INVALIDCALL there as well. */
4527 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4528 return WINED3DERR_INVALIDCALL;
4531 if(This->stateBlock->streamIsUP) {
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4533 This->stateBlock->streamIsUP = FALSE;
4535 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4537 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4538 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4539 minIndex, NumVertices, startIndex, primCount);
4541 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4542 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4548 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4549 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4553 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4554 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4559 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4560 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4561 UINT VertexStreamZeroStride) {
4562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4564 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4565 debug_d3dprimitivetype(PrimitiveType),
4566 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4568 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4569 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4570 This->stateBlock->streamOffset[0] = 0;
4571 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4572 This->stateBlock->streamIsUP = TRUE;
4573 This->stateBlock->loadBaseVertexIndex = 0;
4575 /* TODO: Only mark dirty if drawing from a different UP address */
4576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4578 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4579 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4581 /* MSDN specifies stream zero settings must be set to NULL */
4582 This->stateBlock->streamStride[0] = 0;
4583 This->stateBlock->streamSource[0] = NULL;
4585 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4586 * the new stream sources or use UP drawing again
4591 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4592 UINT MinVertexIndex, UINT NumVertices,
4593 UINT PrimitiveCount, CONST void* pIndexData,
4594 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4595 UINT VertexStreamZeroStride) {
4597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4599 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4600 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4601 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4602 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4604 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4610 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4611 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4612 This->stateBlock->streamIsUP = TRUE;
4613 This->stateBlock->streamOffset[0] = 0;
4614 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4616 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4617 This->stateBlock->baseVertexIndex = 0;
4618 This->stateBlock->loadBaseVertexIndex = 0;
4619 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4623 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4625 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4626 This->stateBlock->streamSource[0] = NULL;
4627 This->stateBlock->streamStride[0] = 0;
4628 This->stateBlock->pIndexData = NULL;
4629 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4630 * SetStreamSource to specify a vertex buffer
4636 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4639 /* Mark the state dirty until we have nicer tracking
4640 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4645 This->stateBlock->baseVertexIndex = 0;
4646 This->up_strided = DrawPrimStrideData;
4647 This->stateBlock->streamIsUP = TRUE;
4648 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4649 This->up_strided = NULL;
4652 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4653 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 HRESULT hr = WINED3D_OK;
4656 WINED3DRESOURCETYPE sourceType;
4657 WINED3DRESOURCETYPE destinationType;
4660 /* TODO: think about moving the code into IWineD3DBaseTexture */
4662 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4664 /* verify that the source and destination textures aren't NULL */
4665 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4666 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4667 This, pSourceTexture, pDestinationTexture);
4668 hr = WINED3DERR_INVALIDCALL;
4671 if (pSourceTexture == pDestinationTexture) {
4672 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4673 This, pSourceTexture, pDestinationTexture);
4674 hr = WINED3DERR_INVALIDCALL;
4676 /* Verify that the source and destination textures are the same type */
4677 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4678 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4680 if (sourceType != destinationType) {
4681 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4683 hr = WINED3DERR_INVALIDCALL;
4686 /* check that both textures have the identical numbers of levels */
4687 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4688 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4689 hr = WINED3DERR_INVALIDCALL;
4692 if (WINED3D_OK == hr) {
4694 /* Make sure that the destination texture is loaded */
4695 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4697 /* Update every surface level of the texture */
4698 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4700 switch (sourceType) {
4701 case WINED3DRTYPE_TEXTURE:
4703 IWineD3DSurface *srcSurface;
4704 IWineD3DSurface *destSurface;
4706 for (i = 0 ; i < levels ; ++i) {
4707 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4708 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4709 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4710 IWineD3DSurface_Release(srcSurface);
4711 IWineD3DSurface_Release(destSurface);
4712 if (WINED3D_OK != hr) {
4713 WARN("(%p) : Call to update surface failed\n", This);
4719 case WINED3DRTYPE_CUBETEXTURE:
4721 IWineD3DSurface *srcSurface;
4722 IWineD3DSurface *destSurface;
4723 WINED3DCUBEMAP_FACES faceType;
4725 for (i = 0 ; i < levels ; ++i) {
4726 /* Update each cube face */
4727 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4728 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4729 if (WINED3D_OK != hr) {
4730 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4732 TRACE("Got srcSurface %p\n", srcSurface);
4734 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4735 if (WINED3D_OK != hr) {
4736 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4738 TRACE("Got desrSurface %p\n", destSurface);
4740 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4741 IWineD3DSurface_Release(srcSurface);
4742 IWineD3DSurface_Release(destSurface);
4743 if (WINED3D_OK != hr) {
4744 WARN("(%p) : Call to update surface failed\n", This);
4751 #if 0 /* TODO: Add support for volume textures */
4752 case WINED3DRTYPE_VOLUMETEXTURE:
4754 IWineD3DVolume srcVolume = NULL;
4755 IWineD3DSurface destVolume = NULL;
4757 for (i = 0 ; i < levels ; ++i) {
4758 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4759 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4760 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4761 IWineD3DVolume_Release(srcSurface);
4762 IWineD3DVolume_Release(destSurface);
4763 if (WINED3D_OK != hr) {
4764 WARN("(%p) : Call to update volume failed\n", This);
4772 FIXME("(%p) : Unsupported source and destination type\n", This);
4773 hr = WINED3DERR_INVALIDCALL;
4780 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4781 IWineD3DSwapChain *swapChain;
4783 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4784 if(hr == WINED3D_OK) {
4785 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4786 IWineD3DSwapChain_Release(swapChain);
4791 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4793 /* return a sensible default */
4795 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4796 FIXME("(%p) : stub\n", This);
4800 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4803 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4804 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4805 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4806 return WINED3DERR_INVALIDCALL;
4808 for (j = 0; j < 256; ++j) {
4809 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4810 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4811 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4812 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4814 TRACE("(%p) : returning\n", This);
4818 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4821 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4822 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4823 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4824 return WINED3DERR_INVALIDCALL;
4826 for (j = 0; j < 256; ++j) {
4827 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4828 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4829 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4830 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4832 TRACE("(%p) : returning\n", This);
4836 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4838 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4839 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4840 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4841 return WINED3DERR_INVALIDCALL;
4843 /*TODO: stateblocks */
4844 This->currentPalette = PaletteNumber;
4845 TRACE("(%p) : returning\n", This);
4849 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4851 if (PaletteNumber == NULL) {
4852 WARN("(%p) : returning Invalid Call\n", This);
4853 return WINED3DERR_INVALIDCALL;
4855 /*TODO: stateblocks */
4856 *PaletteNumber = This->currentPalette;
4857 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4861 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4863 static BOOL showFixmes = TRUE;
4865 FIXME("(%p) : stub\n", This);
4869 This->softwareVertexProcessing = bSoftware;
4874 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4876 static BOOL showFixmes = TRUE;
4878 FIXME("(%p) : stub\n", This);
4881 return This->softwareVertexProcessing;
4885 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4887 IWineD3DSwapChain *swapChain;
4890 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4892 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4893 if(hr == WINED3D_OK){
4894 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4895 IWineD3DSwapChain_Release(swapChain);
4897 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4903 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4905 static BOOL showfixmes = TRUE;
4906 if(nSegments != 0.0f) {
4908 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4915 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4917 static BOOL showfixmes = TRUE;
4919 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4925 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4927 /** TODO: remove casts to IWineD3DSurfaceImpl
4928 * NOTE: move code to surface to accomplish this
4929 ****************************************/
4930 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4931 int srcWidth, srcHeight;
4932 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4933 WINED3DFORMAT destFormat, srcFormat;
4935 int srcLeft, destLeft, destTop;
4936 WINED3DPOOL srcPool, destPool;
4938 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4939 glDescriptor *glDescription = NULL;
4941 WINED3DSURFACE_DESC winedesc;
4943 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4944 memset(&winedesc, 0, sizeof(winedesc));
4945 winedesc.Width = &srcSurfaceWidth;
4946 winedesc.Height = &srcSurfaceHeight;
4947 winedesc.Pool = &srcPool;
4948 winedesc.Format = &srcFormat;
4950 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4952 winedesc.Width = &destSurfaceWidth;
4953 winedesc.Height = &destSurfaceHeight;
4954 winedesc.Pool = &destPool;
4955 winedesc.Format = &destFormat;
4956 winedesc.Size = &destSize;
4958 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4960 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4961 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4962 return WINED3DERR_INVALIDCALL;
4965 if (destFormat == WINED3DFMT_UNKNOWN) {
4966 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4967 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4969 /* Get the update surface description */
4970 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4975 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4977 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4978 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4979 checkGLcall("glActiveTextureARB");
4982 /* Make sure the surface is loaded and up to date */
4983 IWineD3DSurface_PreLoad(pDestinationSurface);
4985 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
4987 /* this needs to be done in lines if the sourceRect != the sourceWidth */
4988 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
4989 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
4990 srcLeft = pSourceRect ? pSourceRect->left : 0;
4991 destLeft = pDestPoint ? pDestPoint->x : 0;
4992 destTop = pDestPoint ? pDestPoint->y : 0;
4995 /* This function doesn't support compressed textures
4996 the pitch is just bytesPerPixel * width */
4997 if(srcWidth != srcSurfaceWidth || srcLeft ){
4998 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
4999 offset += srcLeft * pSrcSurface->bytesPerPixel;
5000 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5002 /* TODO DXT formats */
5004 if(pSourceRect != NULL && pSourceRect->top != 0){
5005 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5007 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5009 ,glDescription->level
5014 ,glDescription->glFormat
5015 ,glDescription->glType
5016 ,IWineD3DSurface_GetData(pSourceSurface)
5020 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5022 /* need to lock the surface to get the data */
5023 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5026 /* TODO: Cube and volume support */
5028 /* not a whole row so we have to do it a line at a time */
5031 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5032 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5034 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5036 glTexSubImage2D(glDescription->target
5037 ,glDescription->level
5042 ,glDescription->glFormat
5043 ,glDescription->glType
5044 ,data /* could be quicker using */
5049 } else { /* Full width, so just write out the whole texture */
5051 if (WINED3DFMT_DXT1 == destFormat ||
5052 WINED3DFMT_DXT2 == destFormat ||
5053 WINED3DFMT_DXT3 == destFormat ||
5054 WINED3DFMT_DXT4 == destFormat ||
5055 WINED3DFMT_DXT5 == destFormat) {
5056 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5057 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5058 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5059 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5060 } if (destFormat != srcFormat) {
5061 FIXME("Updating mixed format compressed texture is not curretly support\n");
5063 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5064 glDescription->level,
5065 glDescription->glFormatInternal,
5070 IWineD3DSurface_GetData(pSourceSurface));
5073 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5078 glTexSubImage2D(glDescription->target
5079 ,glDescription->level
5084 ,glDescription->glFormat
5085 ,glDescription->glType
5086 ,IWineD3DSurface_GetData(pSourceSurface)
5090 checkGLcall("glTexSubImage2D");
5094 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5095 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5101 /* Implementation details at http://developer.nvidia.com/attach/6494
5103 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5104 hmm.. no longer supported use
5105 OpenGL evaluators or tessellate surfaces within your application.
5108 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5109 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5111 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5112 FIXME("(%p) : Stub\n", This);
5117 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5118 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5121 FIXME("(%p) : Stub\n", This);
5125 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5127 TRACE("(%p) Handle(%d)\n", This, Handle);
5128 FIXME("(%p) : Stub\n", This);
5132 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5134 IWineD3DSwapChain *swapchain;
5136 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5137 if (SUCCEEDED(hr)) {
5138 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5145 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5149 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5150 checkGLcall("glGenFramebuffersEXT()");
5152 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5153 checkGLcall("glBindFramebuffer()");
5156 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5157 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5158 GLenum texttarget, target;
5161 texttarget = surface_impl->glDescription.target;
5162 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5163 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5165 IWineD3DSurface_PreLoad(surface);
5167 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5168 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5169 glBindTexture(target, old_binding);
5171 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5173 checkGLcall("attach_surface_fbo");
5176 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5178 IWineD3DSwapChain *swapchain;
5180 swapchain = get_swapchain(surface);
5184 TRACE("Surface %p is onscreen\n", surface);
5186 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5187 buffer = surface_get_gl_buffer(surface, swapchain);
5188 glDrawBuffer(buffer);
5189 checkGLcall("glDrawBuffer()");
5191 TRACE("Surface %p is offscreen\n", surface);
5192 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5193 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5197 glEnable(GL_SCISSOR_TEST);
5199 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5201 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5202 rect->x2 - rect->x1, rect->y2 - rect->y1);
5204 checkGLcall("glScissor");
5206 glDisable(GL_SCISSOR_TEST);
5208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5210 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5213 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5214 glClear(GL_COLOR_BUFFER_BIT);
5215 checkGLcall("glClear");
5217 if (This->render_offscreen) {
5218 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5220 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5221 checkGLcall("glBindFramebuffer()");
5224 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5225 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5226 glDrawBuffer(GL_BACK);
5227 checkGLcall("glDrawBuffer()");
5231 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5233 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5235 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5237 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5238 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5239 return WINED3DERR_INVALIDCALL;
5242 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5243 color_fill_fbo(iface, pSurface, pRect, color);
5246 /* Just forward this to the DirectDraw blitting engine */
5247 memset(&BltFx, 0, sizeof(BltFx));
5248 BltFx.dwSize = sizeof(BltFx);
5249 BltFx.u5.dwFillColor = color;
5250 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5254 /* rendertarget and deptth stencil functions */
5255 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5258 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5259 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5260 return WINED3DERR_INVALIDCALL;
5263 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5264 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5265 /* Note inc ref on returned surface */
5266 if(*ppRenderTarget != NULL)
5267 IWineD3DSurface_AddRef(*ppRenderTarget);
5271 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5273 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5274 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5275 IWineD3DSwapChainImpl *Swapchain;
5278 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5280 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5281 if(hr != WINED3D_OK) {
5282 ERR("Can't get the swapchain\n");
5286 /* Make sure to release the swapchain */
5287 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5289 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5290 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5291 return WINED3DERR_INVALIDCALL;
5293 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5294 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5295 return WINED3DERR_INVALIDCALL;
5298 if(Swapchain->frontBuffer != Front) {
5299 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5301 if(Swapchain->frontBuffer)
5302 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5303 Swapchain->frontBuffer = Front;
5305 if(Swapchain->frontBuffer) {
5306 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5310 if(Back && !Swapchain->backBuffer) {
5311 /* We need memory for the back buffer array - only one back buffer this way */
5312 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5313 if(!Swapchain->backBuffer) {
5314 ERR("Out of memory\n");
5315 return E_OUTOFMEMORY;
5319 if(Swapchain->backBuffer[0] != Back) {
5320 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5322 /* What to do about the context here in the case of multithreading? Not sure.
5323 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5326 if(!Swapchain->backBuffer[0]) {
5327 /* GL was told to draw to the front buffer at creation,
5330 glDrawBuffer(GL_BACK);
5331 checkGLcall("glDrawBuffer(GL_BACK)");
5332 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5333 Swapchain->presentParms.BackBufferCount = 1;
5335 /* That makes problems - disable for now */
5336 /* glDrawBuffer(GL_FRONT); */
5337 checkGLcall("glDrawBuffer(GL_FRONT)");
5338 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5339 Swapchain->presentParms.BackBufferCount = 0;
5343 if(Swapchain->backBuffer[0])
5344 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5345 Swapchain->backBuffer[0] = Back;
5347 if(Swapchain->backBuffer[0]) {
5348 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5350 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5358 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5360 *ppZStencilSurface = This->depthStencilBuffer;
5361 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5363 if(*ppZStencilSurface != NULL) {
5364 /* Note inc ref on returned surface */
5365 IWineD3DSurface_AddRef(*ppZStencilSurface);
5370 /* TODO: Handle stencil attachments */
5371 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5373 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5375 TRACE("Set depth stencil to %p\n", depth_stencil);
5377 if (depth_stencil_impl) {
5378 if (depth_stencil_impl->current_renderbuffer) {
5379 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5380 checkGLcall("glFramebufferRenderbufferEXT()");
5382 GLenum texttarget, target;
5383 GLint old_binding = 0;
5385 texttarget = depth_stencil_impl->glDescription.target;
5386 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5387 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5389 IWineD3DSurface_PreLoad(depth_stencil);
5391 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5392 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5393 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5394 glBindTexture(target, old_binding);
5396 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5397 checkGLcall("glFramebufferTexture2DEXT()");
5400 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5401 checkGLcall("glFramebufferTexture2DEXT()");
5405 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5407 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5409 TRACE("Set render target %u to %p\n", idx, render_target);
5412 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5413 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5415 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5416 checkGLcall("glFramebufferTexture2DEXT()");
5418 This->draw_buffers[idx] = GL_NONE;
5422 static void check_fbo_status(IWineD3DDevice *iface) {
5423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5426 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5427 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5428 TRACE("FBO complete\n");
5430 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5432 /* Dump the FBO attachments */
5433 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5434 IWineD3DSurfaceImpl *attachment;
5437 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5438 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5440 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5441 attachment->pow2Width, attachment->pow2Height);
5444 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5446 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5447 attachment->pow2Width, attachment->pow2Height);
5453 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5455 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5456 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5458 if (!ds_impl) return FALSE;
5460 if (ds_impl->current_renderbuffer) {
5461 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5462 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5465 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5466 rt_impl->pow2Height != ds_impl->pow2Height);
5469 void apply_fbo_state(IWineD3DDevice *iface) {
5470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5473 if (This->render_offscreen) {
5474 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5476 /* Apply render targets */
5477 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5478 IWineD3DSurface *render_target = This->render_targets[i];
5479 if (This->fbo_color_attachments[i] != render_target) {
5480 set_render_target_fbo(iface, i, render_target);
5481 This->fbo_color_attachments[i] = render_target;
5485 /* Apply depth targets */
5486 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5487 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5488 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5490 if (This->stencilBufferTarget) {
5491 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5493 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5494 This->fbo_depth_attachment = This->stencilBufferTarget;
5497 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5498 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5499 checkGLcall("glDrawBuffers()");
5501 glDrawBuffer(This->draw_buffers[0]);
5502 checkGLcall("glDrawBuffer()");
5505 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5508 check_fbo_status(iface);
5511 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5512 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5514 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5515 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5518 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5519 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5520 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5521 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5523 glDisable(GL_SCISSOR_TEST);
5524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5527 case WINED3DTEXF_LINEAR:
5528 gl_filter = GL_LINEAR;
5532 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5533 case WINED3DTEXF_NONE:
5534 case WINED3DTEXF_POINT:
5535 gl_filter = GL_NEAREST;
5539 /* Attach src surface to src fbo */
5540 src_swapchain = get_swapchain(src_surface);
5541 if (src_swapchain) {
5544 TRACE("Source surface %p is onscreen\n", src_surface);
5546 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5547 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5548 glReadBuffer(buffer);
5549 checkGLcall("glReadBuffer()");
5551 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5552 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5554 TRACE("Source surface %p is offscreen\n", src_surface);
5555 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5556 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5557 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5558 checkGLcall("glReadBuffer()");
5561 /* Attach dst surface to dst fbo */
5562 dst_swapchain = get_swapchain(dst_surface);
5563 if (dst_swapchain) {
5566 TRACE("Destination surface %p is onscreen\n", dst_surface);
5568 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5569 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5570 glDrawBuffer(buffer);
5571 checkGLcall("glDrawBuffer()");
5573 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5574 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5576 TRACE("Destination surface %p is offscreen\n", dst_surface);
5577 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5578 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5579 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5580 checkGLcall("glDrawBuffer()");
5584 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5585 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5586 checkGLcall("glBlitFramebuffer()");
5588 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5589 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5590 checkGLcall("glBlitFramebuffer()");
5593 if (This->render_offscreen) {
5594 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5596 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5597 checkGLcall("glBindFramebuffer()");
5600 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5601 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5602 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5603 glDrawBuffer(GL_BACK);
5604 checkGLcall("glDrawBuffer()");
5608 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5610 WINED3DVIEWPORT viewport;
5612 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5614 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5615 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5616 return WINED3DERR_INVALIDCALL;
5619 /* MSDN says that null disables the render target
5620 but a device must always be associated with a render target
5621 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5623 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5626 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5627 FIXME("Trying to set render target 0 to NULL\n");
5628 return WINED3DERR_INVALIDCALL;
5630 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5631 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);
5632 return WINED3DERR_INVALIDCALL;
5635 /* If we are trying to set what we already have, don't bother */
5636 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5637 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5640 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5641 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5642 This->render_targets[RenderTargetIndex] = pRenderTarget;
5644 /* Render target 0 is special */
5645 if(RenderTargetIndex == 0) {
5646 /* Finally, reset the viewport as the MSDN states. */
5647 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5648 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5651 viewport.MaxZ = 1.0f;
5652 viewport.MinZ = 0.0f;
5653 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5654 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5655 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5659 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5661 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5662 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5664 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5669 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5671 HRESULT hr = WINED3D_OK;
5672 IWineD3DSurface *tmp;
5674 TRACE("(%p) Swapping z-buffer\n",This);
5676 if (pNewZStencil == This->stencilBufferTarget) {
5677 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5679 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5680 * depending on the renter target implementation being used.
5681 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5682 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5683 * stencil buffer and incure an extra memory overhead
5684 ******************************************************/
5686 tmp = This->stencilBufferTarget;
5687 This->stencilBufferTarget = pNewZStencil;
5688 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5689 /* should we be calling the parent or the wined3d surface? */
5690 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5691 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5694 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5695 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5705 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5706 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5708 /* TODO: the use of Impl is deprecated. */
5709 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5710 WINED3DLOCKED_RECT lockedRect;
5712 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5714 /* some basic validation checks */
5715 if(This->cursorTexture) {
5717 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5718 glDeleteTextures(1, &This->cursorTexture);
5720 This->cursorTexture = 0;
5723 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5724 This->haveHardwareCursor = TRUE;
5726 This->haveHardwareCursor = FALSE;
5729 WINED3DLOCKED_RECT rect;
5731 /* MSDN: Cursor must be A8R8G8B8 */
5732 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5733 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5734 return WINED3DERR_INVALIDCALL;
5737 /* MSDN: Cursor must be smaller than the display mode */
5738 if(pSur->currentDesc.Width > This->ddraw_width ||
5739 pSur->currentDesc.Height > This->ddraw_height) {
5740 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);
5741 return WINED3DERR_INVALIDCALL;
5744 if (!This->haveHardwareCursor) {
5745 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5747 /* Do not store the surface's pointer because the application may
5748 * release it after setting the cursor image. Windows doesn't
5749 * addref the set surface, so we can't do this either without
5750 * creating circular refcount dependencies. Copy out the gl texture
5753 This->cursorWidth = pSur->currentDesc.Width;
5754 This->cursorHeight = pSur->currentDesc.Height;
5755 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5757 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5758 char *mem, *bits = (char *)rect.pBits;
5759 GLint intfmt = tableEntry->glInternal;
5760 GLint format = tableEntry->glFormat;
5761 GLint type = tableEntry->glType;
5762 INT height = This->cursorHeight;
5763 INT width = This->cursorWidth;
5764 INT bpp = tableEntry->bpp;
5767 /* Reformat the texture memory (pitch and width can be
5769 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5770 for(i = 0; i < height; i++)
5771 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5772 IWineD3DSurface_UnlockRect(pCursorBitmap);
5775 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5776 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5777 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5780 /* Make sure that a proper texture unit is selected */
5781 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5782 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5783 checkGLcall("glActiveTextureARB");
5785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5786 /* Create a new cursor texture */
5787 glGenTextures(1, &This->cursorTexture);
5788 checkGLcall("glGenTextures");
5789 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5790 checkGLcall("glBindTexture");
5791 /* Copy the bitmap memory into the cursor texture */
5792 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5793 HeapFree(GetProcessHeap(), 0, mem);
5794 checkGLcall("glTexImage2D");
5796 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5797 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5798 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5805 FIXME("A cursor texture was not returned.\n");
5806 This->cursorTexture = 0;
5811 /* Draw a hardware cursor */
5812 ICONINFO cursorInfo;
5814 /* Create and clear maskBits because it is not needed for
5815 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5817 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5818 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5819 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5820 WINED3DLOCK_NO_DIRTY_UPDATE |
5821 WINED3DLOCK_READONLY
5823 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5824 pSur->currentDesc.Height);
5826 cursorInfo.fIcon = FALSE;
5827 cursorInfo.xHotspot = XHotSpot;
5828 cursorInfo.yHotspot = YHotSpot;
5829 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5830 pSur->currentDesc.Height, 1,
5832 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5833 pSur->currentDesc.Height, 1,
5834 32, lockedRect.pBits);
5835 IWineD3DSurface_UnlockRect(pCursorBitmap);
5836 /* Create our cursor and clean up. */
5837 cursor = CreateIconIndirect(&cursorInfo);
5839 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5840 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5841 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5842 This->hardwareCursor = cursor;
5843 HeapFree(GetProcessHeap(), 0, maskBits);
5847 This->xHotSpot = XHotSpot;
5848 This->yHotSpot = YHotSpot;
5852 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5854 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5856 This->xScreenSpace = XScreenSpace;
5857 This->yScreenSpace = YScreenSpace;
5863 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5865 BOOL oldVisible = This->bCursorVisible;
5868 TRACE("(%p) : visible(%d)\n", This, bShow);
5871 * When ShowCursor is first called it should make the cursor appear at the OS's last
5872 * known cursor position. Because of this, some applications just repetitively call
5873 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5876 This->xScreenSpace = pt.x;
5877 This->yScreenSpace = pt.y;
5879 if (This->haveHardwareCursor) {
5880 This->bCursorVisible = bShow;
5882 SetCursor(This->hardwareCursor);
5888 if (This->cursorTexture)
5889 This->bCursorVisible = bShow;
5895 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5897 TRACE("(%p) : state (%u)\n", This, This->state);
5898 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5899 switch (This->state) {
5902 case WINED3DERR_DEVICELOST:
5904 ResourceList *resourceList = This->resources;
5905 while (NULL != resourceList) {
5906 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5907 return WINED3DERR_DEVICENOTRESET;
5908 resourceList = resourceList->next;
5910 return WINED3DERR_DEVICELOST;
5912 case WINED3DERR_DRIVERINTERNALERROR:
5913 return WINED3DERR_DRIVERINTERNALERROR;
5917 return WINED3DERR_DRIVERINTERNALERROR;
5921 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5923 /** FIXME: Resource tracking needs to be done,
5924 * The closes we can do to this is set the priorities of all managed textures low
5925 * and then reset them.
5926 ***********************************************************/
5927 FIXME("(%p) : stub\n", This);
5931 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5932 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5934 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5935 if(surface->Flags & SFLAG_DIBSECTION) {
5936 /* Release the DC */
5937 SelectObject(surface->hDC, surface->dib.holdbitmap);
5938 DeleteDC(surface->hDC);
5939 /* Release the DIB section */
5940 DeleteObject(surface->dib.DIBsection);
5941 surface->dib.bitmap_data = NULL;
5942 surface->resource.allocatedMemory = NULL;
5943 surface->Flags &= ~SFLAG_DIBSECTION;
5945 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5946 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5947 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5948 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5949 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5951 surface->pow2Width = surface->pow2Height = 1;
5952 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5953 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5955 if(surface->glDescription.textureName) {
5957 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5958 glDeleteTextures(1, &surface->glDescription.textureName);
5960 surface->glDescription.textureName = 0;
5961 surface->Flags &= ~SFLAG_CLIENT;
5963 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5964 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5965 surface->Flags |= SFLAG_NONPOW2;
5967 surface->Flags &= ~SFLAG_NONPOW2;
5969 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5970 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5973 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5975 IWineD3DSwapChainImpl *swapchain;
5977 BOOL DisplayModeChanged = FALSE;
5978 WINED3DDISPLAYMODE mode;
5979 TRACE("(%p)\n", This);
5981 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5983 ERR("Failed to get the first implicit swapchain\n");
5987 /* Is it necessary to recreate the gl context? Actually every setting can be changed
5988 * on an existing gl context, so there's no real need for recreation.
5990 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
5992 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
5994 TRACE("New params:\n");
5995 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
5996 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
5997 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
5998 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
5999 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6000 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6001 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6002 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6003 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6004 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6005 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6006 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6007 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6009 /* No special treatment of these parameters. Just store them */
6010 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6011 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6012 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6013 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6015 /* What to do about these? */
6016 if(pPresentationParameters->BackBufferCount != 0 &&
6017 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6018 ERR("Cannot change the back buffer count yet\n");
6020 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6021 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6022 ERR("Cannot change the back buffer format yet\n");
6024 if(pPresentationParameters->hDeviceWindow != NULL &&
6025 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6026 ERR("Cannot change the device window yet\n");
6028 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6029 ERR("What do do about a changed auto depth stencil parameter?\n");
6032 if(pPresentationParameters->Windowed) {
6033 mode.Width = swapchain->orig_width;
6034 mode.Height = swapchain->orig_height;
6035 mode.RefreshRate = 0;
6036 mode.Format = swapchain->presentParms.BackBufferFormat;
6038 mode.Width = pPresentationParameters->BackBufferWidth;
6039 mode.Height = pPresentationParameters->BackBufferHeight;
6040 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6041 mode.Format = swapchain->presentParms.BackBufferFormat;
6044 /* Should Width == 800 && Height == 0 set 800x600? */
6045 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6046 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6047 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6054 vp.Width = pPresentationParameters->BackBufferWidth;
6055 vp.Height = pPresentationParameters->BackBufferHeight;
6059 if(!pPresentationParameters->Windowed) {
6060 DisplayModeChanged = TRUE;
6062 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6063 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6065 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6066 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6067 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6070 /* Now set the new viewport */
6071 IWineD3DDevice_SetViewport(iface, &vp);
6074 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6075 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6076 DisplayModeChanged) {
6078 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6079 if(!pPresentationParameters->Windowed) {
6080 IWineD3DDevice_SetFullscreen(iface, TRUE);
6083 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6085 /* Switching out of fullscreen mode? First set the original res, then change the window */
6086 if(pPresentationParameters->Windowed) {
6087 IWineD3DDevice_SetFullscreen(iface, FALSE);
6089 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6092 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6096 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6098 /** FIXME: always true at the moment **/
6099 if(!bEnableDialogs) {
6100 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6106 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6108 TRACE("(%p) : pParameters %p\n", This, pParameters);
6110 *pParameters = This->createParms;
6114 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6115 IWineD3DSwapChain *swapchain;
6116 HRESULT hrc = WINED3D_OK;
6118 TRACE("Relaying to swapchain\n");
6120 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6121 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6122 IWineD3DSwapChain_Release(swapchain);
6127 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6128 IWineD3DSwapChain *swapchain;
6129 HRESULT hrc = WINED3D_OK;
6131 TRACE("Relaying to swapchain\n");
6133 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6134 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6135 IWineD3DSwapChain_Release(swapchain);
6141 /** ********************************************************
6142 * Notification functions
6143 ** ********************************************************/
6144 /** This function must be called in the release of a resource when ref == 0,
6145 * the contents of resource must still be correct,
6146 * any handels to other resource held by the caller must be closed
6147 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6148 *****************************************************/
6149 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6151 ResourceList* resourceList;
6153 TRACE("(%p) : resource %p\n", This, resource);
6154 /* add a new texture to the frot of the linked list */
6155 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6156 resourceList->resource = resource;
6158 /* Get the old head */
6159 resourceList->next = This->resources;
6161 This->resources = resourceList;
6162 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6167 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6169 ResourceList* resourceList = NULL;
6170 ResourceList* previousResourceList = NULL;
6172 TRACE("(%p) : resource %p\n", This, resource);
6174 resourceList = This->resources;
6176 while (resourceList != NULL) {
6177 if(resourceList->resource == resource) break;
6178 previousResourceList = resourceList;
6179 resourceList = resourceList->next;
6182 if (resourceList == NULL) {
6183 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6186 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6188 /* make sure we don't leave a hole in the list */
6189 if (previousResourceList != NULL) {
6190 previousResourceList->next = resourceList->next;
6192 This->resources = resourceList->next;
6199 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6203 TRACE("(%p) : resource %p\n", This, resource);
6204 switch(IWineD3DResource_GetType(resource)){
6205 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6206 case WINED3DRTYPE_SURFACE: {
6209 /* Cleanup any FBO attachments */
6210 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6211 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6212 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6213 set_render_target_fbo(iface, i, NULL);
6214 This->fbo_color_attachments[i] = NULL;
6217 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6218 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6219 set_depth_stencil_fbo(iface, NULL);
6220 This->fbo_depth_attachment = NULL;
6226 case WINED3DRTYPE_TEXTURE:
6227 case WINED3DRTYPE_CUBETEXTURE:
6228 case WINED3DRTYPE_VOLUMETEXTURE:
6229 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6230 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6231 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6232 This->stateBlock->textures[counter] = NULL;
6234 if (This->updateStateBlock != This->stateBlock ){
6235 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6236 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6237 This->updateStateBlock->textures[counter] = NULL;
6242 case WINED3DRTYPE_VOLUME:
6243 /* TODO: nothing really? */
6245 case WINED3DRTYPE_VERTEXBUFFER:
6246 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6249 TRACE("Cleaning up stream pointers\n");
6251 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6252 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6253 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6255 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6256 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6257 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6258 This->updateStateBlock->streamSource[streamNumber] = 0;
6259 /* Set changed flag? */
6262 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) */
6263 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6264 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6265 This->stateBlock->streamSource[streamNumber] = 0;
6268 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6269 else { /* This shouldn't happen */
6270 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6277 case WINED3DRTYPE_INDEXBUFFER:
6278 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6279 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6280 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6281 This->updateStateBlock->pIndexData = NULL;
6284 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6285 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6286 This->stateBlock->pIndexData = NULL;
6292 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6297 /* Remove the resoruce from the resourceStore */
6298 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6300 TRACE("Resource released\n");
6304 /**********************************************************
6305 * IWineD3DDevice VTbl follows
6306 **********************************************************/
6308 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6310 /*** IUnknown methods ***/
6311 IWineD3DDeviceImpl_QueryInterface,
6312 IWineD3DDeviceImpl_AddRef,
6313 IWineD3DDeviceImpl_Release,
6314 /*** IWineD3DDevice methods ***/
6315 IWineD3DDeviceImpl_GetParent,
6316 /*** Creation methods**/
6317 IWineD3DDeviceImpl_CreateVertexBuffer,
6318 IWineD3DDeviceImpl_CreateIndexBuffer,
6319 IWineD3DDeviceImpl_CreateStateBlock,
6320 IWineD3DDeviceImpl_CreateSurface,
6321 IWineD3DDeviceImpl_CreateTexture,
6322 IWineD3DDeviceImpl_CreateVolumeTexture,
6323 IWineD3DDeviceImpl_CreateVolume,
6324 IWineD3DDeviceImpl_CreateCubeTexture,
6325 IWineD3DDeviceImpl_CreateQuery,
6326 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6327 IWineD3DDeviceImpl_CreateVertexDeclaration,
6328 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6329 IWineD3DDeviceImpl_CreateVertexShader,
6330 IWineD3DDeviceImpl_CreatePixelShader,
6331 IWineD3DDeviceImpl_CreatePalette,
6332 /*** Odd functions **/
6333 IWineD3DDeviceImpl_Init3D,
6334 IWineD3DDeviceImpl_Uninit3D,
6335 IWineD3DDeviceImpl_SetFullscreen,
6336 IWineD3DDeviceImpl_SetMultithreaded,
6337 IWineD3DDeviceImpl_EvictManagedResources,
6338 IWineD3DDeviceImpl_GetAvailableTextureMem,
6339 IWineD3DDeviceImpl_GetBackBuffer,
6340 IWineD3DDeviceImpl_GetCreationParameters,
6341 IWineD3DDeviceImpl_GetDeviceCaps,
6342 IWineD3DDeviceImpl_GetDirect3D,
6343 IWineD3DDeviceImpl_GetDisplayMode,
6344 IWineD3DDeviceImpl_SetDisplayMode,
6345 IWineD3DDeviceImpl_GetHWND,
6346 IWineD3DDeviceImpl_SetHWND,
6347 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6348 IWineD3DDeviceImpl_GetRasterStatus,
6349 IWineD3DDeviceImpl_GetSwapChain,
6350 IWineD3DDeviceImpl_Reset,
6351 IWineD3DDeviceImpl_SetDialogBoxMode,
6352 IWineD3DDeviceImpl_SetCursorProperties,
6353 IWineD3DDeviceImpl_SetCursorPosition,
6354 IWineD3DDeviceImpl_ShowCursor,
6355 IWineD3DDeviceImpl_TestCooperativeLevel,
6356 /*** Getters and setters **/
6357 IWineD3DDeviceImpl_SetClipPlane,
6358 IWineD3DDeviceImpl_GetClipPlane,
6359 IWineD3DDeviceImpl_SetClipStatus,
6360 IWineD3DDeviceImpl_GetClipStatus,
6361 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6362 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6363 IWineD3DDeviceImpl_SetDepthStencilSurface,
6364 IWineD3DDeviceImpl_GetDepthStencilSurface,
6365 IWineD3DDeviceImpl_SetFVF,
6366 IWineD3DDeviceImpl_GetFVF,
6367 IWineD3DDeviceImpl_SetGammaRamp,
6368 IWineD3DDeviceImpl_GetGammaRamp,
6369 IWineD3DDeviceImpl_SetIndices,
6370 IWineD3DDeviceImpl_GetIndices,
6371 IWineD3DDeviceImpl_SetBaseVertexIndex,
6372 IWineD3DDeviceImpl_SetLight,
6373 IWineD3DDeviceImpl_GetLight,
6374 IWineD3DDeviceImpl_SetLightEnable,
6375 IWineD3DDeviceImpl_GetLightEnable,
6376 IWineD3DDeviceImpl_SetMaterial,
6377 IWineD3DDeviceImpl_GetMaterial,
6378 IWineD3DDeviceImpl_SetNPatchMode,
6379 IWineD3DDeviceImpl_GetNPatchMode,
6380 IWineD3DDeviceImpl_SetPaletteEntries,
6381 IWineD3DDeviceImpl_GetPaletteEntries,
6382 IWineD3DDeviceImpl_SetPixelShader,
6383 IWineD3DDeviceImpl_GetPixelShader,
6384 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6385 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6386 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6387 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6388 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6389 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6390 IWineD3DDeviceImpl_SetRenderState,
6391 IWineD3DDeviceImpl_GetRenderState,
6392 IWineD3DDeviceImpl_SetRenderTarget,
6393 IWineD3DDeviceImpl_GetRenderTarget,
6394 IWineD3DDeviceImpl_SetFrontBackBuffers,
6395 IWineD3DDeviceImpl_SetSamplerState,
6396 IWineD3DDeviceImpl_GetSamplerState,
6397 IWineD3DDeviceImpl_SetScissorRect,
6398 IWineD3DDeviceImpl_GetScissorRect,
6399 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6400 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6401 IWineD3DDeviceImpl_SetStreamSource,
6402 IWineD3DDeviceImpl_GetStreamSource,
6403 IWineD3DDeviceImpl_SetStreamSourceFreq,
6404 IWineD3DDeviceImpl_GetStreamSourceFreq,
6405 IWineD3DDeviceImpl_SetTexture,
6406 IWineD3DDeviceImpl_GetTexture,
6407 IWineD3DDeviceImpl_SetTextureStageState,
6408 IWineD3DDeviceImpl_GetTextureStageState,
6409 IWineD3DDeviceImpl_SetTransform,
6410 IWineD3DDeviceImpl_GetTransform,
6411 IWineD3DDeviceImpl_SetVertexDeclaration,
6412 IWineD3DDeviceImpl_GetVertexDeclaration,
6413 IWineD3DDeviceImpl_SetVertexShader,
6414 IWineD3DDeviceImpl_GetVertexShader,
6415 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6416 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6417 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6418 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6419 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6420 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6421 IWineD3DDeviceImpl_SetViewport,
6422 IWineD3DDeviceImpl_GetViewport,
6423 IWineD3DDeviceImpl_MultiplyTransform,
6424 IWineD3DDeviceImpl_ValidateDevice,
6425 IWineD3DDeviceImpl_ProcessVertices,
6426 /*** State block ***/
6427 IWineD3DDeviceImpl_BeginStateBlock,
6428 IWineD3DDeviceImpl_EndStateBlock,
6429 /*** Scene management ***/
6430 IWineD3DDeviceImpl_BeginScene,
6431 IWineD3DDeviceImpl_EndScene,
6432 IWineD3DDeviceImpl_Present,
6433 IWineD3DDeviceImpl_Clear,
6435 IWineD3DDeviceImpl_DrawPrimitive,
6436 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6437 IWineD3DDeviceImpl_DrawPrimitiveUP,
6438 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6439 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6440 IWineD3DDeviceImpl_DrawRectPatch,
6441 IWineD3DDeviceImpl_DrawTriPatch,
6442 IWineD3DDeviceImpl_DeletePatch,
6443 IWineD3DDeviceImpl_ColorFill,
6444 IWineD3DDeviceImpl_UpdateTexture,
6445 IWineD3DDeviceImpl_UpdateSurface,
6446 IWineD3DDeviceImpl_GetFrontBufferData,
6447 /*** object tracking ***/
6448 IWineD3DDeviceImpl_ResourceReleased
6452 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6453 WINED3DRS_ALPHABLENDENABLE ,
6454 WINED3DRS_ALPHAFUNC ,
6455 WINED3DRS_ALPHAREF ,
6456 WINED3DRS_ALPHATESTENABLE ,
6458 WINED3DRS_COLORWRITEENABLE ,
6459 WINED3DRS_DESTBLEND ,
6460 WINED3DRS_DITHERENABLE ,
6461 WINED3DRS_FILLMODE ,
6462 WINED3DRS_FOGDENSITY ,
6464 WINED3DRS_FOGSTART ,
6465 WINED3DRS_LASTPIXEL ,
6466 WINED3DRS_SHADEMODE ,
6467 WINED3DRS_SRCBLEND ,
6468 WINED3DRS_STENCILENABLE ,
6469 WINED3DRS_STENCILFAIL ,
6470 WINED3DRS_STENCILFUNC ,
6471 WINED3DRS_STENCILMASK ,
6472 WINED3DRS_STENCILPASS ,
6473 WINED3DRS_STENCILREF ,
6474 WINED3DRS_STENCILWRITEMASK ,
6475 WINED3DRS_STENCILZFAIL ,
6476 WINED3DRS_TEXTUREFACTOR ,
6487 WINED3DRS_ZWRITEENABLE
6490 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6491 WINED3DTSS_ADDRESSW ,
6492 WINED3DTSS_ALPHAARG0 ,
6493 WINED3DTSS_ALPHAARG1 ,
6494 WINED3DTSS_ALPHAARG2 ,
6495 WINED3DTSS_ALPHAOP ,
6496 WINED3DTSS_BUMPENVLOFFSET ,
6497 WINED3DTSS_BUMPENVLSCALE ,
6498 WINED3DTSS_BUMPENVMAT00 ,
6499 WINED3DTSS_BUMPENVMAT01 ,
6500 WINED3DTSS_BUMPENVMAT10 ,
6501 WINED3DTSS_BUMPENVMAT11 ,
6502 WINED3DTSS_COLORARG0 ,
6503 WINED3DTSS_COLORARG1 ,
6504 WINED3DTSS_COLORARG2 ,
6505 WINED3DTSS_COLOROP ,
6506 WINED3DTSS_RESULTARG ,
6507 WINED3DTSS_TEXCOORDINDEX ,
6508 WINED3DTSS_TEXTURETRANSFORMFLAGS
6511 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6512 WINED3DSAMP_ADDRESSU ,
6513 WINED3DSAMP_ADDRESSV ,
6514 WINED3DSAMP_ADDRESSW ,
6515 WINED3DSAMP_BORDERCOLOR ,
6516 WINED3DSAMP_MAGFILTER ,
6517 WINED3DSAMP_MINFILTER ,
6518 WINED3DSAMP_MIPFILTER ,
6519 WINED3DSAMP_MIPMAPLODBIAS ,
6520 WINED3DSAMP_MAXMIPLEVEL ,
6521 WINED3DSAMP_MAXANISOTROPY ,
6522 WINED3DSAMP_SRGBTEXTURE ,
6523 WINED3DSAMP_ELEMENTINDEX
6526 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6528 WINED3DRS_AMBIENTMATERIALSOURCE ,
6529 WINED3DRS_CLIPPING ,
6530 WINED3DRS_CLIPPLANEENABLE ,
6531 WINED3DRS_COLORVERTEX ,
6532 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6533 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6534 WINED3DRS_FOGDENSITY ,
6536 WINED3DRS_FOGSTART ,
6537 WINED3DRS_FOGTABLEMODE ,
6538 WINED3DRS_FOGVERTEXMODE ,
6539 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6540 WINED3DRS_LIGHTING ,
6541 WINED3DRS_LOCALVIEWER ,
6542 WINED3DRS_MULTISAMPLEANTIALIAS ,
6543 WINED3DRS_MULTISAMPLEMASK ,
6544 WINED3DRS_NORMALIZENORMALS ,
6545 WINED3DRS_PATCHEDGESTYLE ,
6546 WINED3DRS_POINTSCALE_A ,
6547 WINED3DRS_POINTSCALE_B ,
6548 WINED3DRS_POINTSCALE_C ,
6549 WINED3DRS_POINTSCALEENABLE ,
6550 WINED3DRS_POINTSIZE ,
6551 WINED3DRS_POINTSIZE_MAX ,
6552 WINED3DRS_POINTSIZE_MIN ,
6553 WINED3DRS_POINTSPRITEENABLE ,
6554 WINED3DRS_RANGEFOGENABLE ,
6555 WINED3DRS_SPECULARMATERIALSOURCE ,
6556 WINED3DRS_TWEENFACTOR ,
6557 WINED3DRS_VERTEXBLEND
6560 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6561 WINED3DTSS_TEXCOORDINDEX ,
6562 WINED3DTSS_TEXTURETRANSFORMFLAGS
6565 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6566 WINED3DSAMP_DMAPOFFSET
6569 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6570 DWORD rep = StateTable[state].representative;
6574 WineD3DContext *context;
6577 for(i = 0; i < This->numContexts; i++) {
6578 context = This->contexts[i];
6579 if(isStateDirty(context, rep)) continue;
6581 context->dirtyArray[context->numDirtyEntries++] = rep;
6584 context->isStateDirty[idx] |= (1 << shift);