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; \
141 _basetexture.is_srgb = FALSE; \
142 _basetexture.srgb_mode_change_count = 0; \
143 _basetexture.is_srgb = FALSE; \
144 _basetexture.srgb_mode_change_count = 0; \
147 /**********************************************************
148 * Global variable / Constants follow
149 **********************************************************/
150 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
152 /**********************************************************
153 * IUnknown parts follows
154 **********************************************************/
156 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
161 if (IsEqualGUID(riid, &IID_IUnknown)
162 || IsEqualGUID(riid, &IID_IWineD3DBase)
163 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
164 IUnknown_AddRef(iface);
169 return E_NOINTERFACE;
172 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
174 ULONG refCount = InterlockedIncrement(&This->ref);
176 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
180 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
182 ULONG refCount = InterlockedDecrement(&This->ref);
184 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
188 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
191 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
194 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
197 HeapFree(GetProcessHeap(), 0, This->render_targets);
198 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
199 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
201 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
203 /* TODO: Clean up all the surfaces and textures! */
204 /* NOTE: You must release the parent if the object was created via a callback
205 ** ***************************/
207 /* Release the update stateblock */
208 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
209 if(This->updateStateBlock != This->stateBlock)
210 FIXME("(%p) Something's still holding the Update stateblock\n",This);
212 This->updateStateBlock = NULL;
213 { /* because were not doing proper internal refcounts releasing the primary state block
214 causes recursion with the extra checks in ResourceReleased, to avoid this we have
215 to set this->stateBlock = NULL; first */
216 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
217 This->stateBlock = NULL;
219 /* Release the stateblock */
220 if(IWineD3DStateBlock_Release(stateBlock) > 0){
221 FIXME("(%p) Something's still holding the Update stateblock\n",This);
225 if (This->resources != NULL ) {
226 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
227 dumpResources(This->resources);
230 if(This->contexts) ERR("Context array not freed!\n");
231 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
232 This->haveHardwareCursor = FALSE;
234 IWineD3D_Release(This->wineD3D);
235 This->wineD3D = NULL;
236 HeapFree(GetProcessHeap(), 0, This);
237 TRACE("Freed device %p\n", This);
243 /**********************************************************
244 * IWineD3DDevice implementation follows
245 **********************************************************/
246 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
248 *pParent = This->parent;
249 IUnknown_AddRef(This->parent);
253 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
254 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
255 GLenum error, glUsage;
256 DWORD vboUsage = object->resource.usage;
257 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
258 WARN("Creating a vbo failed once, not trying again\n");
262 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
265 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
266 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
268 /* Make sure that the gl error is cleared. Do not use checkGLcall
269 * here because checkGLcall just prints a fixme and continues. However,
270 * if an error during VBO creation occurs we can fall back to non-vbo operation
271 * with full functionality(but performance loss)
273 while(glGetError() != GL_NO_ERROR);
275 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
276 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
277 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
278 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
279 * to check if the rhw and color values are in the correct format.
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(object->vbo == 0 || error != GL_NO_ERROR) {
285 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
289 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
296 /* Don't use static, because dx apps tend to update the buffer
297 * quite often even if they specify 0 usage. Because we always keep the local copy
298 * we never read from the vbo and can create a write only opengl buffer.
300 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
301 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
302 case WINED3DUSAGE_DYNAMIC:
303 TRACE("Gl usage = GL_STREAM_DRAW\n");
304 glUsage = GL_STREAM_DRAW_ARB;
306 case WINED3DUSAGE_WRITEONLY:
308 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
309 glUsage = GL_DYNAMIC_DRAW_ARB;
313 /* Reserve memory for the buffer. The amount of data won't change
314 * so we are safe with calling glBufferData once with a NULL ptr and
315 * calling glBufferSubData on updates
317 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
318 error = glGetError();
319 if(error != GL_NO_ERROR) {
320 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
328 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
329 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
330 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
332 object->Flags |= VBFLAG_VBOCREATEFAIL;
337 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
338 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DVertexBufferImpl *object;
342 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
343 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
347 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
348 *ppVertexBuffer = NULL;
349 return WINED3DERR_INVALIDCALL;
352 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
354 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
355 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
357 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
358 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
362 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
363 * drawStridedFast (half-life 2).
365 * Basically converting the vertices in the buffer is quite expensive, and observations
366 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
367 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
369 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
370 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
371 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
372 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
374 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
375 * more. In this call we can convert dx7 buffers too.
377 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
378 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
379 (dxVersion > 7 || !conv) ) {
385 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
386 GLenum error, glUsage;
387 TRACE("Creating VBO for Index Buffer %p\n", object);
389 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
390 * restored on the next draw
392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
395 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
396 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
400 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
401 error = glGetError();
402 if(error != GL_NO_ERROR || object->vbo == 0) {
403 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
407 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
408 error = glGetError();
409 if(error != GL_NO_ERROR) {
410 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
414 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
415 * copy no readback will be needed
417 glUsage = GL_STATIC_DRAW_ARB;
418 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
419 error = glGetError();
420 if(error != GL_NO_ERROR) {
421 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
425 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
429 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
430 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
435 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
436 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
437 HANDLE *sharedHandle, IUnknown *parent) {
438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
439 IWineD3DIndexBufferImpl *object;
440 TRACE("(%p) Creating index buffer\n", This);
442 /* Allocate the storage for the device */
443 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
445 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
446 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
449 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
450 CreateIndexBufferVBO(This, object);
453 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
454 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
455 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
460 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
463 IWineD3DStateBlockImpl *object;
467 D3DCREATEOBJECTINSTANCE(object, StateBlock)
468 object->blockType = Type;
470 for(i = 0; i < LIGHTMAP_SIZE; i++) {
471 list_init(&object->lightMap[i]);
474 /* Special case - Used during initialization to produce a placeholder stateblock
475 so other functions called can update a state block */
476 if (Type == WINED3DSBT_INIT) {
477 /* Don't bother increasing the reference count otherwise a device will never
478 be freed due to circular dependencies */
482 temp_result = allocate_shader_constants(object);
483 if (WINED3D_OK != temp_result)
486 /* Otherwise, might as well set the whole state block to the appropriate values */
487 if (This->stateBlock != NULL)
488 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
490 memset(object->streamFreq, 1, sizeof(object->streamFreq));
492 /* Reset the ref and type after kludging it */
493 object->wineD3DDevice = This;
495 object->blockType = Type;
497 TRACE("Updating changed flags appropriate for type %d\n", Type);
499 if (Type == WINED3DSBT_ALL) {
501 TRACE("ALL => Pretend everything has changed\n");
502 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
504 /* Lights are not part of the changed / set structure */
505 for(j = 0; j < LIGHTMAP_SIZE; j++) {
507 LIST_FOR_EACH(e, &object->lightMap[j]) {
508 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
509 light->changed = TRUE;
510 light->enabledChanged = TRUE;
513 } else if (Type == WINED3DSBT_PIXELSTATE) {
515 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
516 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
518 object->changed.pixelShader = TRUE;
520 /* Pixel Shader Constants */
521 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
522 object->changed.pixelShaderConstantsF[i] = TRUE;
523 for (i = 0; i < MAX_CONST_B; ++i)
524 object->changed.pixelShaderConstantsB[i] = TRUE;
525 for (i = 0; i < MAX_CONST_I; ++i)
526 object->changed.pixelShaderConstantsI[i] = TRUE;
528 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
529 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
531 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
532 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
533 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
536 for (j = 0 ; j < 16; j++) {
537 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
539 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
543 } else if (Type == WINED3DSBT_VERTEXSTATE) {
545 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
546 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
548 object->changed.vertexShader = TRUE;
550 /* Vertex Shader Constants */
551 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
552 object->changed.vertexShaderConstantsF[i] = TRUE;
553 for (i = 0; i < MAX_CONST_B; ++i)
554 object->changed.vertexShaderConstantsB[i] = TRUE;
555 for (i = 0; i < MAX_CONST_I; ++i)
556 object->changed.vertexShaderConstantsI[i] = TRUE;
558 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
559 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
561 for (j = 0; j < GL_LIMITS(texture_stages); j++) {
562 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
563 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
566 for (j = 0 ; j < 16; j++){
567 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
568 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
572 for(j = 0; j < LIGHTMAP_SIZE; j++) {
574 LIST_FOR_EACH(e, &object->lightMap[j]) {
575 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
576 light->changed = TRUE;
577 light->enabledChanged = TRUE;
581 FIXME("Unrecognized state block type %d\n", Type);
584 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
588 /* ************************************
590 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
593 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
595 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.
597 ******************************** */
599 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) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
602 unsigned int pow2Width, pow2Height;
603 unsigned int Size = 1;
604 const PixelFormatDesc *tableEntry = getFormatDescEntry(Format);
605 TRACE("(%p) Create surface\n",This);
607 /** FIXME: Check ranges on the inputs are valid
610 * [in] Quality level. The valid range is between zero and one less than the level
611 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
612 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
613 * values of paired render targets, depth stencil surfaces, and the MultiSample type
615 *******************************/
620 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
622 * If this flag is set, the contents of the depth stencil buffer will be
623 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
624 * with a different depth surface.
626 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
627 ***************************/
629 if(MultisampleQuality < 0) {
630 FIXME("Invalid multisample level %d\n", MultisampleQuality);
631 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
634 if(MultisampleQuality > 0) {
635 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
636 MultisampleQuality=0;
639 /** FIXME: Check that the format is supported
641 *******************************/
643 /* Non-power2 support */
644 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
648 /* Find the nearest pow2 match */
649 pow2Width = pow2Height = 1;
650 while (pow2Width < Width) pow2Width <<= 1;
651 while (pow2Height < Height) pow2Height <<= 1;
654 if (pow2Width > Width || pow2Height > Height) {
655 /** TODO: add support for non power two compressed textures (OpenGL 2 provices support for * non-power-two textures gratis) **/
656 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
657 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
658 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
659 This, Width, Height);
660 return WINED3DERR_NOTAVAILABLE;
664 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
665 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
667 *********************************/
668 if (WINED3DFMT_UNKNOWN == Format) {
670 } else if (Format == WINED3DFMT_DXT1) {
671 /* DXT1 is half byte per pixel */
672 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
674 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
675 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
676 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
678 /* The pitch is a multiple of 4 bytes */
679 Size = ((Width * tableEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
683 /** Create and initialise the surface resource **/
684 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
685 /* "Standalone" surface */
686 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
688 object->currentDesc.Width = Width;
689 object->currentDesc.Height = Height;
690 object->currentDesc.MultiSampleType = MultiSample;
691 object->currentDesc.MultiSampleQuality = MultisampleQuality;
693 /* Setup some glformat defaults */
694 object->glDescription.glFormat = tableEntry->glFormat;
695 object->glDescription.glFormatInternal = tableEntry->glInternal;
696 object->glDescription.glType = tableEntry->glType;
698 object->glDescription.textureName = 0;
699 object->glDescription.level = Level;
700 object->glDescription.target = GL_TEXTURE_2D;
703 object->pow2Width = pow2Width;
704 object->pow2Height = pow2Height;
707 object->Flags = SFLAG_DYNLOCK;
708 object->Flags |= (pow2Width != Width || pow2Height != Height) ? SFLAG_NONPOW2 : 0;
709 object->Flags |= Discard ? SFLAG_DISCARD : 0;
710 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
711 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
714 if (WINED3DFMT_UNKNOWN != Format) {
715 object->bytesPerPixel = tableEntry->bpp;
717 object->bytesPerPixel = 0;
720 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
722 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
724 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
725 * this function is too deep to need to care about things like this.
726 * Levels need to be checked too, and possibly Type since they all affect what can be done.
727 * ****************************************/
729 case WINED3DPOOL_SCRATCH:
731 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
732 "which are mutually exclusive, setting lockable to TRUE\n");
735 case WINED3DPOOL_SYSTEMMEM:
736 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
737 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
738 case WINED3DPOOL_MANAGED:
739 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
740 "Usage of DYNAMIC which are mutually exclusive, not doing "
741 "anything just telling you.\n");
743 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
744 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
745 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
746 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
749 FIXME("(%p) Unknown pool %d\n", This, Pool);
753 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
754 FIXME("Trying to create a render target that isn't in the default pool\n");
757 /* mark the texture as dirty so that it gets loaded first time around*/
758 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
759 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
760 This, Width, Height, Format, debug_d3dformat(Format),
761 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
763 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
764 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
765 This->ddraw_primary = (IWineD3DSurface *) object;
767 /* Look at the implementation and set the correct Vtable */
770 /* Nothing to do, it's set already */
774 object->lpVtbl = &IWineGDISurface_Vtbl;
778 /* To be sure to catch this */
779 ERR("Unknown requested surface implementation %d!\n", Impl);
780 IWineD3DSurface_Release((IWineD3DSurface *) object);
781 return WINED3DERR_INVALIDCALL;
784 list_init(&object->renderbuffers);
786 /* Call the private setup routine */
787 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
791 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
792 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
793 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
794 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
797 IWineD3DTextureImpl *object;
802 unsigned int pow2Width;
803 unsigned int pow2Height;
806 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
807 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
808 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
810 /* TODO: It should only be possible to create textures for formats
811 that are reported as supported */
812 if (WINED3DFMT_UNKNOWN >= Format) {
813 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
814 return WINED3DERR_INVALIDCALL;
817 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
818 D3DINITIALIZEBASETEXTURE(object->baseTexture);
819 object->width = Width;
820 object->height = Height;
822 /** Non-power2 support **/
823 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
827 /* Find the nearest pow2 match */
828 pow2Width = pow2Height = 1;
829 while (pow2Width < Width) pow2Width <<= 1;
830 while (pow2Height < Height) pow2Height <<= 1;
833 /** FIXME: add support for real non-power-two if it's provided by the video card **/
834 /* Precalculated scaling for 'faked' non power of two texture coords */
835 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
836 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
837 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
839 /* Calculate levels for mip mapping */
841 TRACE("calculating levels %d\n", object->baseTexture.levels);
842 object->baseTexture.levels++;
845 while (tmpW > 1 || tmpH > 1) {
846 tmpW = max(1, tmpW >> 1);
847 tmpH = max(1, tmpH >> 1);
848 object->baseTexture.levels++;
850 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
853 /* Generate all the surfaces */
856 for (i = 0; i < object->baseTexture.levels; i++)
858 /* use the callback to create the texture surface */
859 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
860 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
861 FIXME("Failed to create surface %p\n", object);
863 object->surfaces[i] = NULL;
864 IWineD3DTexture_Release((IWineD3DTexture *)object);
870 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
871 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
872 /* calculate the next mipmap level */
873 tmpW = max(1, tmpW >> 1);
874 tmpH = max(1, tmpH >> 1);
877 TRACE("(%p) : Created texture %p\n", This, object);
881 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
882 UINT Width, UINT Height, UINT Depth,
883 UINT Levels, DWORD Usage,
884 WINED3DFORMAT Format, WINED3DPOOL Pool,
885 IWineD3DVolumeTexture **ppVolumeTexture,
886 HANDLE *pSharedHandle, IUnknown *parent,
887 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
890 IWineD3DVolumeTextureImpl *object;
896 /* TODO: It should only be possible to create textures for formats
897 that are reported as supported */
898 if (WINED3DFMT_UNKNOWN >= Format) {
899 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
900 return WINED3DERR_INVALIDCALL;
903 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
904 D3DINITIALIZEBASETEXTURE(object->baseTexture);
906 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
907 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
909 object->width = Width;
910 object->height = Height;
911 object->depth = Depth;
913 /* Calculate levels for mip mapping */
915 object->baseTexture.levels++;
919 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
920 tmpW = max(1, tmpW >> 1);
921 tmpH = max(1, tmpH >> 1);
922 tmpD = max(1, tmpD >> 1);
923 object->baseTexture.levels++;
925 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
928 /* Generate all the surfaces */
933 for (i = 0; i < object->baseTexture.levels; i++)
936 /* Create the volume */
937 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
938 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
941 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
942 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
943 *ppVolumeTexture = NULL;
947 /* Set its container to this object */
948 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
950 /* calcualte the next mipmap level */
951 tmpW = max(1, tmpW >> 1);
952 tmpH = max(1, tmpH >> 1);
953 tmpD = max(1, tmpD >> 1);
956 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
957 TRACE("(%p) : Created volume texture %p\n", This, object);
961 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
962 UINT Width, UINT Height, UINT Depth,
964 WINED3DFORMAT Format, WINED3DPOOL Pool,
965 IWineD3DVolume** ppVolume,
966 HANDLE* pSharedHandle, IUnknown *parent) {
968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
969 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
970 const PixelFormatDesc *formatDesc = getFormatDescEntry(Format);
972 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
974 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
975 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
977 object->currentDesc.Width = Width;
978 object->currentDesc.Height = Height;
979 object->currentDesc.Depth = Depth;
980 object->bytesPerPixel = formatDesc->bpp;
982 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
983 object->lockable = TRUE;
984 object->locked = FALSE;
985 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
986 object->dirty = TRUE;
988 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
992 UINT Levels, DWORD Usage,
993 WINED3DFORMAT Format, WINED3DPOOL Pool,
994 IWineD3DCubeTexture **ppCubeTexture,
995 HANDLE *pSharedHandle, IUnknown *parent,
996 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
999 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1003 unsigned int pow2EdgeLength = EdgeLength;
1005 /* TODO: It should only be possible to create textures for formats
1006 that are reported as supported */
1007 if (WINED3DFMT_UNKNOWN >= Format) {
1008 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1009 return WINED3DERR_INVALIDCALL;
1012 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1013 WARN("(%p) : Tried to create not supported cube texture\n", This);
1014 return WINED3DERR_INVALIDCALL;
1017 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1018 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1020 TRACE("(%p) Create Cube Texture\n", This);
1022 /** Non-power2 support **/
1024 /* Find the nearest pow2 match */
1026 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1028 object->edgeLength = EdgeLength;
1029 /* TODO: support for native non-power 2 */
1030 /* Precalculated scaling for 'faked' non power of two texture coords */
1031 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1033 /* Calculate levels for mip mapping */
1035 object->baseTexture.levels++;
1038 tmpW = max(1, tmpW >> 1);
1039 object->baseTexture.levels++;
1041 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1044 /* Generate all the surfaces */
1046 for (i = 0; i < object->baseTexture.levels; i++) {
1048 /* Create the 6 faces */
1049 for (j = 0; j < 6; j++) {
1051 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1052 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1054 if(hr!= WINED3D_OK) {
1058 for (l = 0; l < j; l++) {
1059 IWineD3DSurface_Release(object->surfaces[j][i]);
1061 for (k = 0; k < i; k++) {
1062 for (l = 0; l < 6; l++) {
1063 IWineD3DSurface_Release(object->surfaces[l][j]);
1067 FIXME("(%p) Failed to create surface\n",object);
1068 HeapFree(GetProcessHeap(),0,object);
1069 *ppCubeTexture = NULL;
1072 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1073 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1075 tmpW = max(1, tmpW >> 1);
1078 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1079 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1083 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1085 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1086 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1088 /* Just a check to see if we support this type of query */
1090 case WINED3DQUERYTYPE_OCCLUSION:
1091 TRACE("(%p) occlusion query\n", This);
1092 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1095 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1098 case WINED3DQUERYTYPE_EVENT:
1099 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1100 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1101 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1103 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1108 case WINED3DQUERYTYPE_VCACHE:
1109 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1110 case WINED3DQUERYTYPE_VERTEXSTATS:
1111 case WINED3DQUERYTYPE_TIMESTAMP:
1112 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1113 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1114 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1115 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1116 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1117 case WINED3DQUERYTYPE_PIXELTIMINGS:
1118 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1119 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1121 FIXME("(%p) Unhandled query type %d\n", This, Type);
1123 if(NULL == ppQuery || hr != WINED3D_OK) {
1127 D3DCREATEOBJECTINSTANCE(object, Query)
1128 object->type = Type;
1129 /* allocated the 'extended' data based on the type of query requested */
1131 case WINED3DQUERYTYPE_OCCLUSION:
1132 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1133 TRACE("(%p) Allocating data for an occlusion query\n", This);
1134 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1135 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1138 case WINED3DQUERYTYPE_EVENT:
1139 /* TODO: GL_APPLE_fence */
1140 if(GL_SUPPORT(APPLE_FENCE)) {
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1142 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1143 checkGLcall("glGenFencesAPPLE");
1144 } else if(GL_SUPPORT(NV_FENCE)) {
1145 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1146 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1147 checkGLcall("glGenFencesNV");
1151 case WINED3DQUERYTYPE_VCACHE:
1152 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1153 case WINED3DQUERYTYPE_VERTEXSTATS:
1154 case WINED3DQUERYTYPE_TIMESTAMP:
1155 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1156 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1157 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1158 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1159 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1160 case WINED3DQUERYTYPE_PIXELTIMINGS:
1161 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1162 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1164 object->extendedData = 0;
1165 FIXME("(%p) Unhandled query type %d\n",This , Type);
1167 TRACE("(%p) : Created Query %p\n", This, object);
1171 /*****************************************************************************
1172 * IWineD3DDeviceImpl_SetupFullscreenWindow
1174 * Helper function that modifies a HWND's Style and ExStyle for proper
1178 * iface: Pointer to the IWineD3DDevice interface
1179 * window: Window to setup
1181 *****************************************************************************/
1182 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1185 LONG style, exStyle;
1186 /* Don't do anything if an original style is stored.
1187 * That shouldn't happen
1189 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1190 if (This->style || This->exStyle) {
1191 ERR("(%p): Want to change the window parameters of HWND %p, but "
1192 "another style is stored for restoration afterwards\n", This, window);
1195 /* Get the parameters and save them */
1196 style = GetWindowLongW(window, GWL_STYLE);
1197 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1198 This->style = style;
1199 This->exStyle = exStyle;
1201 /* Filter out window decorations */
1202 style &= ~WS_CAPTION;
1203 style &= ~WS_THICKFRAME;
1204 exStyle &= ~WS_EX_WINDOWEDGE;
1205 exStyle &= ~WS_EX_CLIENTEDGE;
1207 /* Make sure the window is managed, otherwise we won't get keyboard input */
1208 style |= WS_POPUP | WS_SYSMENU;
1210 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1211 This->style, This->exStyle, style, exStyle);
1213 SetWindowLongW(window, GWL_STYLE, style);
1214 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1216 /* Inform the window about the update. */
1217 SetWindowPos(window, HWND_TOP, 0, 0,
1218 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1219 ShowWindow(window, SW_NORMAL);
1222 /*****************************************************************************
1223 * IWineD3DDeviceImpl_RestoreWindow
1225 * Helper function that restores a windows' properties when taking it out
1226 * of fullscreen mode
1229 * iface: Pointer to the IWineD3DDevice interface
1230 * window: Window to setup
1232 *****************************************************************************/
1233 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1236 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1237 * switch, do nothing
1239 if (!This->style && !This->exStyle) return;
1241 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1242 This, window, This->style, This->exStyle);
1244 SetWindowLongW(window, GWL_STYLE, This->style);
1245 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1247 /* Delete the old values */
1251 /* Inform the window about the update */
1252 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1253 0, 0, 0, 0, /* Pos, Size, ignored */
1254 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1257 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1258 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1260 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1261 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1265 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1266 HRESULT hr = WINED3D_OK;
1267 IUnknown *bufferParent;
1270 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1272 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1273 * does a device hold a reference to a swap chain giving them a lifetime of the device
1274 * or does the swap chain notify the device of its destruction.
1275 *******************************/
1277 /* Check the params */
1278 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1279 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1280 return WINED3DERR_INVALIDCALL;
1281 } else if (pPresentationParameters->BackBufferCount > 1) {
1282 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");
1285 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1287 /*********************
1288 * Lookup the window Handle and the relating X window handle
1289 ********************/
1291 /* Setup hwnd we are using, plus which display this equates to */
1292 object->win_handle = pPresentationParameters->hDeviceWindow;
1293 if (!object->win_handle) {
1294 object->win_handle = This->createParms.hFocusWindow;
1297 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1298 if ( !( object->win = (Window)GetPropA(object->win_handle, "__wine_x11_whole_window") ) ) {
1299 ERR("Can't get drawable (window), HWND:%p doesn't have the property __wine_x11_whole_window\n", object->win_handle);
1300 return WINED3DERR_NOTAVAILABLE;
1302 hDc = GetDC(object->win_handle);
1303 display = get_display(hDc);
1304 ReleaseDC(object->win_handle, hDc);
1305 TRACE("Using a display of %p %p\n", display, hDc);
1307 if (NULL == display || NULL == hDc) {
1308 WARN("Failed to get a display and HDc for Window %p\n", object->win_handle);
1309 return WINED3DERR_NOTAVAILABLE;
1312 if (object->win == 0) {
1313 WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
1314 return WINED3DERR_NOTAVAILABLE;
1317 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1318 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1319 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1321 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1322 * then the corresponding dimension of the client area of the hDeviceWindow
1323 * (or the focus window, if hDeviceWindow is NULL) is taken.
1324 **********************/
1326 if (pPresentationParameters->Windowed &&
1327 ((pPresentationParameters->BackBufferWidth == 0) ||
1328 (pPresentationParameters->BackBufferHeight == 0))) {
1331 GetClientRect(object->win_handle, &Rect);
1333 if (pPresentationParameters->BackBufferWidth == 0) {
1334 pPresentationParameters->BackBufferWidth = Rect.right;
1335 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1337 if (pPresentationParameters->BackBufferHeight == 0) {
1338 pPresentationParameters->BackBufferHeight = Rect.bottom;
1339 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1343 /* Put the correct figures in the presentation parameters */
1344 TRACE("Copying across presentation parameters\n");
1345 object->presentParms = *pPresentationParameters;
1347 TRACE("calling rendertarget CB\n");
1348 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1350 object->presentParms.BackBufferWidth,
1351 object->presentParms.BackBufferHeight,
1352 object->presentParms.BackBufferFormat,
1353 object->presentParms.MultiSampleType,
1354 object->presentParms.MultiSampleQuality,
1355 TRUE /* Lockable */,
1356 &object->frontBuffer,
1357 NULL /* pShared (always null)*/);
1358 if (object->frontBuffer != NULL) {
1359 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1361 ERR("Failed to create the front buffer\n");
1366 * Create an opengl context for the display visual
1367 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1368 * use different properties after that point in time. FIXME: How to handle when requested format
1369 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1370 * it chooses is identical to the one already being used!
1371 **********************************/
1372 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1374 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1375 if(!object->context)
1376 return E_OUTOFMEMORY;
1377 object->num_contexts = 1;
1380 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, display, object->win);
1383 if (!object->context[0]) {
1384 ERR("Failed to create a new context\n");
1385 hr = WINED3DERR_NOTAVAILABLE;
1388 TRACE("Context created (HWND=%p, glContext=%p, Window=%ld)\n",
1389 object->win_handle, object->context[0]->glCtx, object->win);
1392 /*********************
1393 * Windowed / Fullscreen
1394 *******************/
1397 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1398 * so we should really check to see if there is a fullscreen swapchain already
1399 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1400 **************************************/
1402 if (!pPresentationParameters->Windowed) {
1409 /* Get info on the current display setup */
1411 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1414 /* Change the display settings */
1415 memset(&devmode, 0, sizeof(DEVMODEW));
1416 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1417 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1418 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1419 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1420 MultiByteToWideChar(CP_ACP, 0, "Gamers CG", -1, devmode.dmDeviceName, CCHDEVICENAME);
1421 ChangeDisplaySettingsExW(devmode.dmDeviceName, &devmode, object->win_handle, CDS_FULLSCREEN, NULL);
1423 /* For GetDisplayMode */
1424 This->ddraw_width = devmode.dmPelsWidth;
1425 This->ddraw_height = devmode.dmPelsHeight;
1426 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1428 IWineD3DDevice_SetFullscreen(iface, TRUE);
1430 /* And finally clip mouse to our screen */
1431 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1432 ClipCursor(&clip_rc);
1435 /*********************
1436 * Create the back, front and stencil buffers
1437 *******************/
1438 if(object->presentParms.BackBufferCount > 0) {
1441 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1442 if(!object->backBuffer) {
1443 ERR("Out of memory\n");
1448 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1449 TRACE("calling rendertarget CB\n");
1450 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1452 object->presentParms.BackBufferWidth,
1453 object->presentParms.BackBufferHeight,
1454 object->presentParms.BackBufferFormat,
1455 object->presentParms.MultiSampleType,
1456 object->presentParms.MultiSampleQuality,
1457 TRUE /* Lockable */,
1458 &object->backBuffer[i],
1459 NULL /* pShared (always null)*/);
1460 if(hr == WINED3D_OK && object->backBuffer[i]) {
1461 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1463 ERR("Cannot create new back buffer\n");
1467 glDrawBuffer(GL_BACK);
1468 checkGLcall("glDrawBuffer(GL_BACK)");
1472 object->backBuffer = NULL;
1474 /* Single buffering - draw to front buffer */
1476 glDrawBuffer(GL_FRONT);
1477 checkGLcall("glDrawBuffer(GL_FRONT)");
1481 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1482 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1483 TRACE("Creating depth stencil buffer\n");
1484 if (This->depthStencilBuffer == NULL ) {
1485 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1487 object->presentParms.BackBufferWidth,
1488 object->presentParms.BackBufferHeight,
1489 object->presentParms.AutoDepthStencilFormat,
1490 object->presentParms.MultiSampleType,
1491 object->presentParms.MultiSampleQuality,
1492 FALSE /* FIXME: Discard */,
1493 &This->depthStencilBuffer,
1494 NULL /* pShared (always null)*/ );
1495 if (This->depthStencilBuffer != NULL)
1496 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1499 /** TODO: A check on width, height and multisample types
1500 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1501 ****************************/
1502 object->wantsDepthStencilBuffer = TRUE;
1504 object->wantsDepthStencilBuffer = FALSE;
1507 TRACE("Created swapchain %p\n", object);
1508 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1512 if (object->backBuffer) {
1514 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1515 if(object->backBuffer[i]) {
1516 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1517 IUnknown_Release(bufferParent); /* once for the get parent */
1518 if (IUnknown_Release(bufferParent) > 0) {
1519 FIXME("(%p) Something's still holding the back buffer\n",This);
1523 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1524 object->backBuffer = NULL;
1526 if(object->context[0])
1527 DestroyContext(This, object->context[0]);
1528 if(object->frontBuffer) {
1529 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1530 IUnknown_Release(bufferParent); /* once for the get parent */
1531 if (IUnknown_Release(bufferParent) > 0) {
1532 FIXME("(%p) Something's still holding the front buffer\n",This);
1535 HeapFree(GetProcessHeap(), 0, object);
1539 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1540 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1542 TRACE("(%p)\n", This);
1544 return This->NumberOfSwapChains;
1547 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1549 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1551 if(iSwapChain < This->NumberOfSwapChains) {
1552 *pSwapChain = This->swapchains[iSwapChain];
1553 IWineD3DSwapChain_AddRef(*pSwapChain);
1554 TRACE("(%p) returning %p\n", This, *pSwapChain);
1557 TRACE("Swapchain out of range\n");
1559 return WINED3DERR_INVALIDCALL;
1564 * Vertex Declaration
1566 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1567 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1569 IWineD3DVertexDeclarationImpl *object = NULL;
1570 HRESULT hr = WINED3D_OK;
1572 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1573 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1575 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1577 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1582 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1584 unsigned int idx, idx2;
1585 unsigned int offset;
1586 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1587 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1588 BOOL has_blend_idx = has_blend &&
1589 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1590 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1591 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1592 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1593 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1594 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1595 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1597 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1598 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1600 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1601 WINED3DVERTEXELEMENT *elements = NULL;
1604 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1605 if (has_blend_idx) num_blends--;
1607 /* Compute declaration size */
1608 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1609 has_psize + has_diffuse + has_specular + num_textures + 1;
1611 /* convert the declaration */
1612 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1616 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1619 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1620 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1621 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1624 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1625 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1627 elements[idx].UsageIndex = 0;
1630 if (has_blend && (num_blends > 0)) {
1631 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1632 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1634 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1635 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1636 elements[idx].UsageIndex = 0;
1639 if (has_blend_idx) {
1640 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1641 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1642 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1643 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1644 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1646 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1647 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1648 elements[idx].UsageIndex = 0;
1652 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1653 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1654 elements[idx].UsageIndex = 0;
1658 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1659 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1660 elements[idx].UsageIndex = 0;
1664 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1665 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1666 elements[idx].UsageIndex = 0;
1670 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1671 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1672 elements[idx].UsageIndex = 1;
1675 for (idx2 = 0; idx2 < num_textures; idx2++) {
1676 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1677 switch (numcoords) {
1678 case WINED3DFVF_TEXTUREFORMAT1:
1679 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1681 case WINED3DFVF_TEXTUREFORMAT2:
1682 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1684 case WINED3DFVF_TEXTUREFORMAT3:
1685 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1687 case WINED3DFVF_TEXTUREFORMAT4:
1688 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1691 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1692 elements[idx].UsageIndex = idx2;
1696 /* Now compute offsets, and initialize the rest of the fields */
1697 for (idx = 0, offset = 0; idx < size-1; idx++) {
1698 elements[idx].Stream = 0;
1699 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1700 elements[idx].Offset = offset;
1701 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1704 *ppVertexElements = elements;
1708 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1709 WINED3DVERTEXELEMENT* elements = NULL;
1713 size = ConvertFvfToDeclaration(Fvf, &elements);
1714 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1716 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1717 HeapFree(GetProcessHeap(), 0, elements);
1718 if (hr != S_OK) return hr;
1723 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1724 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1726 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1727 HRESULT hr = WINED3D_OK;
1728 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1729 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1731 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1733 if (vertex_declaration) {
1734 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1737 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1739 if (WINED3D_OK != hr) {
1740 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1741 IWineD3DVertexShader_Release(*ppVertexShader);
1742 return WINED3DERR_INVALIDCALL;
1748 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1750 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1751 HRESULT hr = WINED3D_OK;
1753 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1754 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1755 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1756 if (WINED3D_OK == hr) {
1757 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1759 WARN("(%p) : Failed to create pixel shader\n", This);
1765 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1767 IWineD3DPaletteImpl *object;
1769 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1771 /* Create the new object */
1772 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1774 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1775 return E_OUTOFMEMORY;
1778 object->lpVtbl = &IWineD3DPalette_Vtbl;
1780 object->Flags = Flags;
1781 object->parent = Parent;
1782 object->wineD3DDevice = This;
1783 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1785 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1788 HeapFree( GetProcessHeap(), 0, object);
1789 return E_OUTOFMEMORY;
1792 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1794 IWineD3DPalette_Release((IWineD3DPalette *) object);
1798 *Palette = (IWineD3DPalette *) object;
1803 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1805 IWineD3DSwapChainImpl *swapchain;
1808 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1809 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1811 /* TODO: Test if OpenGL is compiled in and loaded */
1813 /* Initialize the texture unit mapping to a 1:1 mapping */
1814 for(state = 0; state < MAX_SAMPLERS; state++) {
1815 This->texUnitMap[state] = state;
1817 This->oneToOneTexUnitMap = TRUE;
1819 /* Setup the implicit swapchain */
1820 TRACE("Creating implicit swapchain\n");
1821 if (FAILED(D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain)) || !swapchain) {
1822 WARN("Failed to create implicit swapchain\n");
1823 return WINED3DERR_INVALIDCALL;
1826 This->NumberOfSwapChains = 1;
1827 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1828 if(!This->swapchains) {
1829 ERR("Out of memory!\n");
1830 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1831 return E_OUTOFMEMORY;
1833 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1835 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1837 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1838 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1839 This->render_targets[0] = swapchain->backBuffer[0];
1840 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1843 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1844 This->render_targets[0] = swapchain->frontBuffer;
1845 This->lastActiveRenderTarget = swapchain->frontBuffer;
1847 IWineD3DSurface_AddRef(This->render_targets[0]);
1848 This->activeContext = swapchain->context[0];
1850 /* Depth Stencil support */
1851 This->stencilBufferTarget = This->depthStencilBuffer;
1852 if (NULL != This->stencilBufferTarget) {
1853 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1856 /* Set up some starting GL setup */
1859 * Initialize openGL extension related variables
1860 * with Default values
1863 ((IWineD3DImpl *) This->wineD3D)->isGLInfoValid = IWineD3DImpl_FillGLCaps(This->wineD3D, swapchain->context[0]->display);
1864 /* Setup all the devices defaults */
1865 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1867 IWineD3DImpl_CheckGraphicsMemory();
1870 { /* Set a default viewport */
1874 vp.Width = pPresentationParameters->BackBufferWidth;
1875 vp.Height = pPresentationParameters->BackBufferHeight;
1878 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1881 /* Initialize the current view state */
1882 This->view_ident = 1;
1883 This->contexts[0]->last_was_rhw = 0;
1884 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1885 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1887 switch(wined3d_settings.offscreen_rendering_mode) {
1890 This->offscreenBuffer = GL_BACK;
1893 case ORM_BACKBUFFER:
1895 if(GL_LIMITS(aux_buffers) > 0) {
1896 TRACE("Using auxilliary buffer for offscreen rendering\n");
1897 This->offscreenBuffer = GL_AUX0;
1899 TRACE("Using back buffer for offscreen rendering\n");
1900 This->offscreenBuffer = GL_BACK;
1905 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1908 /* Clear the screen */
1909 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1910 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1913 This->d3d_initialized = TRUE;
1917 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1921 TRACE("(%p)\n", This);
1923 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1926 /* I don't think that the interface guarants that the device is destroyed from the same thread
1927 * it was created. Thus make sure a context is active for the glDelete* calls
1929 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1932 /* Delete the pbuffer context if there is any */
1933 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1935 /* Delete the mouse cursor texture */
1936 if(This->cursorTexture) {
1938 glDeleteTextures(1, &This->cursorTexture);
1940 This->cursorTexture = 0;
1943 for(sampler = 0; sampler < GL_LIMITS(sampler_stages); ++sampler) {
1944 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1947 /* Release the buffers (with sanity checks)*/
1948 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1949 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1950 if(This->depthStencilBuffer != This->stencilBufferTarget)
1951 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1953 This->stencilBufferTarget = NULL;
1955 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1956 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1957 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1959 TRACE("Setting rendertarget to NULL\n");
1960 This->render_targets[0] = NULL;
1962 if (This->depthStencilBuffer) {
1963 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1964 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1966 This->depthStencilBuffer = NULL;
1969 for(i=0; i < This->NumberOfSwapChains; i++) {
1970 TRACE("Releasing the implicit swapchain %d\n", i);
1971 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1972 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1976 HeapFree(GetProcessHeap(), 0, This->swapchains);
1977 This->swapchains = NULL;
1978 This->NumberOfSwapChains = 0;
1980 This->d3d_initialized = FALSE;
1984 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1986 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1988 /* Setup the window for fullscreen mode */
1989 if(fullscreen && !This->ddraw_fullscreen) {
1990 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1991 } else if(!fullscreen && This->ddraw_fullscreen) {
1992 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1995 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1996 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1997 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2000 This->ddraw_fullscreen = fullscreen;
2003 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2004 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2005 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2007 * There is no way to deactivate thread safety once it is enabled
2009 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2011 FIXME("No thread safety in wined3d yet\n");
2013 /*For now just store the flag(needed in case of ddraw) */
2014 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2019 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2023 const PixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format);
2026 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2028 /* Resize the screen even without a window:
2029 * The app could have unset it with SetCooperativeLevel, but not called
2030 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2031 * but we don't have any hwnd
2034 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2035 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2036 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2037 devmode.dmPelsWidth = pMode->Width;
2038 devmode.dmPelsHeight = pMode->Height;
2040 devmode.dmDisplayFrequency = pMode->RefreshRate;
2041 if (pMode->RefreshRate != 0) {
2042 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2045 /* Only change the mode if necessary */
2046 if( (This->ddraw_width == pMode->Width) &&
2047 (This->ddraw_height == pMode->Height) &&
2048 (This->ddraw_format == pMode->Format) &&
2049 (pMode->RefreshRate == 0) ) {
2053 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2054 if (ret != DISP_CHANGE_SUCCESSFUL) {
2055 if(devmode.dmDisplayFrequency != 0) {
2056 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2057 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2058 devmode.dmDisplayFrequency = 0;
2059 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2061 if(ret != DISP_CHANGE_SUCCESSFUL) {
2062 return WINED3DERR_NOTAVAILABLE;
2066 /* Store the new values */
2067 This->ddraw_width = pMode->Width;
2068 This->ddraw_height = pMode->Height;
2069 This->ddraw_format = pMode->Format;
2071 /* Only do this with a window of course */
2072 if(This->ddraw_window)
2073 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2075 /* And finally clip mouse to our screen */
2076 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2077 ClipCursor(&clip_rc);
2082 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2084 *ppD3D= This->wineD3D;
2085 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2086 IWineD3D_AddRef(*ppD3D);
2090 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2091 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2092 * into the video ram as possible and seeing how many fit
2093 * you can also get the correct initial value from nvidia and ATI's driver via X
2094 * texture memory is video memory + AGP memory
2095 *******************/
2096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2097 static BOOL showfixmes = TRUE;
2099 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2100 (wined3d_settings.emulated_textureram/(1024*1024)),
2101 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2104 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2105 (wined3d_settings.emulated_textureram/(1024*1024)),
2106 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2107 /* return simulated texture memory left */
2108 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2116 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2119 /* Update the current state block */
2120 This->updateStateBlock->changed.fvf = TRUE;
2121 This->updateStateBlock->set.fvf = TRUE;
2123 if(This->updateStateBlock->fvf == fvf) {
2124 TRACE("Application is setting the old fvf over, nothing to do\n");
2128 This->updateStateBlock->fvf = fvf;
2129 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2135 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2137 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2138 *pfvf = This->stateBlock->fvf;
2143 * Get / Set Stream Source
2145 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2147 IWineD3DVertexBuffer *oldSrc;
2149 if (StreamNumber >= MAX_STREAMS) {
2150 WARN("Stream out of range %d\n", StreamNumber);
2151 return WINED3DERR_INVALIDCALL;
2154 oldSrc = This->stateBlock->streamSource[StreamNumber];
2155 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2157 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2158 This->updateStateBlock->set.streamSource[StreamNumber] = TRUE;
2160 if(oldSrc == pStreamData &&
2161 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2162 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2163 TRACE("Application is setting the old values over, nothing to do\n");
2167 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2169 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2170 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2173 /* Handle recording of state blocks */
2174 if (This->isRecordingState) {
2175 TRACE("Recording... not performing anything\n");
2179 /* Need to do a getParent and pass the reffs up */
2180 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2181 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2182 so for now, just count internally */
2183 if (pStreamData != NULL) {
2184 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2185 InterlockedIncrement(&vbImpl->bindCount);
2187 if (oldSrc != NULL) {
2188 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2196 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2199 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2200 This->stateBlock->streamSource[StreamNumber],
2201 This->stateBlock->streamOffset[StreamNumber],
2202 This->stateBlock->streamStride[StreamNumber]);
2204 if (StreamNumber >= MAX_STREAMS) {
2205 WARN("Stream out of range %d\n", StreamNumber);
2206 return WINED3DERR_INVALIDCALL;
2208 *pStream = This->stateBlock->streamSource[StreamNumber];
2209 *pStride = This->stateBlock->streamStride[StreamNumber];
2211 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2214 if (*pStream != NULL) {
2215 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2220 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2222 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2223 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2225 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2226 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2228 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2229 This->updateStateBlock->set.streamFreq[StreamNumber] = TRUE;
2230 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2232 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2233 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2240 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2243 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2244 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2246 TRACE("(%p) : returning %d\n", This, *Divider);
2252 * Get / Set & Multiply Transform
2254 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2257 /* Most of this routine, comments included copied from ddraw tree initially: */
2258 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2260 /* Handle recording of state blocks */
2261 if (This->isRecordingState) {
2262 TRACE("Recording... not performing anything\n");
2263 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2264 This->updateStateBlock->set.transform[d3dts] = TRUE;
2265 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2270 * If the new matrix is the same as the current one,
2271 * we cut off any further processing. this seems to be a reasonable
2272 * optimization because as was noticed, some apps (warcraft3 for example)
2273 * tend towards setting the same matrix repeatedly for some reason.
2275 * From here on we assume that the new matrix is different, wherever it matters.
2277 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2278 TRACE("The app is setting the same matrix over again\n");
2281 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2285 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2286 where ViewMat = Camera space, WorldMat = world space.
2288 In OpenGL, camera and world space is combined into GL_MODELVIEW
2289 matrix. The Projection matrix stay projection matrix.
2292 /* Capture the times we can just ignore the change for now */
2293 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2294 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2295 /* Handled by the state manager */
2298 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2302 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2304 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2305 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2309 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2310 WINED3DMATRIX *mat = NULL;
2313 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2314 * below means it will be recorded in a state block change, but it
2315 * works regardless where it is recorded.
2316 * If this is found to be wrong, change to StateBlock.
2318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2319 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2321 if (State < HIGHEST_TRANSFORMSTATE)
2323 mat = &This->updateStateBlock->transforms[State];
2325 FIXME("Unhandled transform state!!\n");
2328 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2330 /* Apply change via set transform - will reapply to eg. lights this way */
2331 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2337 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2338 you can reference any indexes you want as long as that number max are enabled at any
2339 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2340 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2341 but when recording, just build a chain pretty much of commands to be replayed. */
2343 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2345 PLIGHTINFOEL *object = NULL;
2346 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2350 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2352 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2356 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2357 return WINED3DERR_INVALIDCALL;
2360 switch(pLight->Type) {
2361 case WINED3DLIGHT_POINT:
2362 case WINED3DLIGHT_SPOT:
2363 case WINED3DLIGHT_PARALLELPOINT:
2364 case WINED3DLIGHT_GLSPOT:
2365 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2368 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2369 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2370 return WINED3DERR_INVALIDCALL;
2374 case WINED3DLIGHT_DIRECTIONAL:
2375 /* Ignores attenuation */
2379 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2380 return WINED3DERR_INVALIDCALL;
2383 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2384 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2385 if(object->OriginalIndex == Index) break;
2390 TRACE("Adding new light\n");
2391 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2393 ERR("Out of memory error when allocating a light\n");
2394 return E_OUTOFMEMORY;
2396 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2397 object->glIndex = -1;
2398 object->OriginalIndex = Index;
2399 object->changed = TRUE;
2402 /* Initialize the object */
2403 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,
2404 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2405 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2406 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2407 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2408 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2409 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2411 /* Save away the information */
2412 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2414 switch (pLight->Type) {
2415 case WINED3DLIGHT_POINT:
2417 object->lightPosn[0] = pLight->Position.x;
2418 object->lightPosn[1] = pLight->Position.y;
2419 object->lightPosn[2] = pLight->Position.z;
2420 object->lightPosn[3] = 1.0f;
2421 object->cutoff = 180.0f;
2425 case WINED3DLIGHT_DIRECTIONAL:
2427 object->lightPosn[0] = -pLight->Direction.x;
2428 object->lightPosn[1] = -pLight->Direction.y;
2429 object->lightPosn[2] = -pLight->Direction.z;
2430 object->lightPosn[3] = 0.0;
2431 object->exponent = 0.0f;
2432 object->cutoff = 180.0f;
2435 case WINED3DLIGHT_SPOT:
2437 object->lightPosn[0] = pLight->Position.x;
2438 object->lightPosn[1] = pLight->Position.y;
2439 object->lightPosn[2] = pLight->Position.z;
2440 object->lightPosn[3] = 1.0;
2443 object->lightDirn[0] = pLight->Direction.x;
2444 object->lightDirn[1] = pLight->Direction.y;
2445 object->lightDirn[2] = pLight->Direction.z;
2446 object->lightDirn[3] = 1.0;
2449 * opengl-ish and d3d-ish spot lights use too different models for the
2450 * light "intensity" as a function of the angle towards the main light direction,
2451 * so we only can approximate very roughly.
2452 * however spot lights are rather rarely used in games (if ever used at all).
2453 * furthermore if still used, probably nobody pays attention to such details.
2455 if (pLight->Falloff == 0) {
2458 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2460 if (rho < 0.0001) rho = 0.0001f;
2461 object->exponent = -0.3/log(cos(rho/2));
2462 if (object->exponent > 128.0) {
2463 object->exponent = 128.0;
2465 object->cutoff = pLight->Phi*90/M_PI;
2471 FIXME("Unrecognized light type %d\n", pLight->Type);
2474 /* Update the live definitions if the light is currently assigned a glIndex */
2475 if (object->glIndex != -1 && !This->isRecordingState) {
2476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2481 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2482 PLIGHTINFOEL *lightInfo = NULL;
2483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2484 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2486 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2488 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2489 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2490 if(lightInfo->OriginalIndex == Index) break;
2494 if (lightInfo == NULL) {
2495 TRACE("Light information requested but light not defined\n");
2496 return WINED3DERR_INVALIDCALL;
2499 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2504 * Get / Set Light Enable
2505 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2507 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2508 PLIGHTINFOEL *lightInfo = NULL;
2509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2510 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2512 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2514 /* Tests show true = 128...not clear why */
2515 Enable = Enable? 128: 0;
2517 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2518 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2519 if(lightInfo->OriginalIndex == Index) break;
2522 TRACE("Found light: %p\n", lightInfo);
2524 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2525 if (lightInfo == NULL) {
2527 TRACE("Light enabled requested but light not defined, so defining one!\n");
2528 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2530 /* Search for it again! Should be fairly quick as near head of list */
2531 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2532 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2533 if(lightInfo->OriginalIndex == Index) break;
2536 if (lightInfo == NULL) {
2537 FIXME("Adding default lights has failed dismally\n");
2538 return WINED3DERR_INVALIDCALL;
2542 lightInfo->enabledChanged = TRUE;
2544 if(lightInfo->glIndex != -1) {
2545 if(!This->isRecordingState) {
2546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2549 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2550 lightInfo->glIndex = -1;
2552 TRACE("Light already disabled, nothing to do\n");
2555 if (lightInfo->glIndex != -1) {
2557 TRACE("Nothing to do as light was enabled\n");
2560 /* Find a free gl light */
2561 for(i = 0; i < This->maxConcurrentLights; i++) {
2562 if(This->stateBlock->activeLights[i] == NULL) {
2563 This->stateBlock->activeLights[i] = lightInfo;
2564 lightInfo->glIndex = i;
2568 if(lightInfo->glIndex == -1) {
2569 ERR("Too many concurrently active lights\n");
2570 return WINED3DERR_INVALIDCALL;
2573 /* i == lightInfo->glIndex */
2574 if(!This->isRecordingState) {
2575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2583 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2585 PLIGHTINFOEL *lightInfo = NULL;
2586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2589 TRACE("(%p) : for idx(%d)\n", This, Index);
2591 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2592 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2593 if(lightInfo->OriginalIndex == Index) break;
2597 if (lightInfo == NULL) {
2598 TRACE("Light enabled state requested but light not defined\n");
2599 return WINED3DERR_INVALIDCALL;
2601 /* true is 128 according to SetLightEnable */
2602 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2607 * Get / Set Clip Planes
2609 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2613 /* Validate Index */
2614 if (Index >= GL_LIMITS(clipplanes)) {
2615 TRACE("Application has requested clipplane this device doesn't support\n");
2616 return WINED3DERR_INVALIDCALL;
2619 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2620 This->updateStateBlock->set.clipplane[Index] = TRUE;
2622 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2623 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2624 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2625 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2626 TRACE("Application is setting old values over, nothing to do\n");
2630 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2631 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2632 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2633 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2635 /* Handle recording of state blocks */
2636 if (This->isRecordingState) {
2637 TRACE("Recording... not performing anything\n");
2641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2646 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2648 TRACE("(%p) : for idx %d\n", This, Index);
2650 /* Validate Index */
2651 if (Index >= GL_LIMITS(clipplanes)) {
2652 TRACE("Application has requested clipplane this device doesn't support\n");
2653 return WINED3DERR_INVALIDCALL;
2656 pPlane[0] = This->stateBlock->clipplane[Index][0];
2657 pPlane[1] = This->stateBlock->clipplane[Index][1];
2658 pPlane[2] = This->stateBlock->clipplane[Index][2];
2659 pPlane[3] = This->stateBlock->clipplane[Index][3];
2664 * Get / Set Clip Plane Status
2665 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2667 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 FIXME("(%p) : stub\n", This);
2670 if (NULL == pClipStatus) {
2671 return WINED3DERR_INVALIDCALL;
2673 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2674 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2678 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2680 FIXME("(%p) : stub\n", This);
2681 if (NULL == pClipStatus) {
2682 return WINED3DERR_INVALIDCALL;
2684 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2685 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2690 * Get / Set Material
2692 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2695 This->updateStateBlock->changed.material = TRUE;
2696 This->updateStateBlock->set.material = TRUE;
2697 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2699 /* Handle recording of state blocks */
2700 if (This->isRecordingState) {
2701 TRACE("Recording... not performing anything\n");
2706 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2707 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2708 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2709 pMaterial->Ambient.b, pMaterial->Ambient.a);
2710 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2711 pMaterial->Specular.b, pMaterial->Specular.a);
2712 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2713 pMaterial->Emissive.b, pMaterial->Emissive.a);
2714 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2716 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*) &This->updateStateBlock->material.Ambient);
2717 checkGLcall("glMaterialfv(GL_AMBIENT)");
2718 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*) &This->updateStateBlock->material.Diffuse);
2719 checkGLcall("glMaterialfv(GL_DIFFUSE)");
2721 /* Only change material color if specular is enabled, otherwise it is set to black */
2722 if (This->stateBlock->renderState[WINED3DRS_SPECULARENABLE]) {
2723 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*) &This->updateStateBlock->material.Specular);
2724 checkGLcall("glMaterialfv(GL_SPECULAR");
2726 float black[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2727 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, &black[0]);
2728 checkGLcall("glMaterialfv(GL_SPECULAR");
2730 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, (float*) &This->updateStateBlock->material.Emissive);
2731 checkGLcall("glMaterialfv(GL_EMISSION)");
2732 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, This->updateStateBlock->material.Power);
2733 checkGLcall("glMaterialf(GL_SHININESS");
2739 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2741 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2742 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2743 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2744 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2745 pMaterial->Ambient.b, pMaterial->Ambient.a);
2746 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2747 pMaterial->Specular.b, pMaterial->Specular.a);
2748 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2749 pMaterial->Emissive.b, pMaterial->Emissive.a);
2750 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2758 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2760 IWineD3DIndexBuffer *oldIdxs;
2762 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2763 oldIdxs = This->updateStateBlock->pIndexData;
2765 This->updateStateBlock->changed.indices = TRUE;
2766 This->updateStateBlock->set.indices = TRUE;
2767 This->updateStateBlock->pIndexData = pIndexData;
2769 /* Handle recording of state blocks */
2770 if (This->isRecordingState) {
2771 TRACE("Recording... not performing anything\n");
2775 if(oldIdxs != pIndexData) {
2776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2781 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 *ppIndexData = This->stateBlock->pIndexData;
2786 /* up ref count on ppindexdata */
2788 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2789 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2791 TRACE("(%p) No index data set\n", This);
2793 TRACE("Returning %p\n", *ppIndexData);
2798 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2799 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2801 TRACE("(%p)->(%d)\n", This, BaseIndex);
2803 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2804 TRACE("Application is setting the old value over, nothing to do\n");
2808 This->updateStateBlock->baseVertexIndex = BaseIndex;
2810 if (This->isRecordingState) {
2811 TRACE("Recording... not performing anything\n");
2814 /* The base vertex index affects the stream sources */
2815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2819 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2821 TRACE("(%p) : base_index %p\n", This, base_index);
2823 *base_index = This->stateBlock->baseVertexIndex;
2825 TRACE("Returning %u\n", *base_index);
2831 * Get / Set Viewports
2833 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2836 TRACE("(%p)\n", This);
2837 This->updateStateBlock->changed.viewport = TRUE;
2838 This->updateStateBlock->set.viewport = TRUE;
2839 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2841 /* Handle recording of state blocks */
2842 if (This->isRecordingState) {
2843 TRACE("Recording... not performing anything\n");
2847 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2848 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2855 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2857 TRACE("(%p)\n", This);
2858 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2863 * Get / Set Render States
2864 * TODO: Verify against dx9 definitions
2866 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 DWORD oldValue = This->stateBlock->renderState[State];
2871 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2873 This->updateStateBlock->changed.renderState[State] = TRUE;
2874 This->updateStateBlock->set.renderState[State] = TRUE;
2875 This->updateStateBlock->renderState[State] = Value;
2877 /* Handle recording of state blocks */
2878 if (This->isRecordingState) {
2879 TRACE("Recording... not performing anything\n");
2883 /* Compared here and not before the assignment to allow proper stateblock recording */
2884 if(Value == oldValue) {
2885 TRACE("Application is setting the old value over, nothing to do\n");
2887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2893 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2896 *pValue = This->stateBlock->renderState[State];
2901 * Get / Set Sampler States
2902 * TODO: Verify against dx9 definitions
2905 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2907 DWORD oldValue = This->stateBlock->samplerState[Sampler][Type];
2910 * SetSampler is designed to allow for more than the standard up to 8 textures
2911 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2912 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2914 * http://developer.nvidia.com/object/General_FAQ.html#t6
2916 * There are two new settings for GForce
2918 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2919 * and the texture one:
2920 * GL_MAX_TEXTURE_COORDS_ARB.
2921 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2924 TRACE("(%p) : Sampler=%d, Type=%s(%d), Value=%d\n", This, Sampler,
2925 debug_d3dsamplerstate(Type), Type, Value);
2926 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2927 This->updateStateBlock->set.samplerState[Sampler][Type] = Value;
2928 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2930 /* Handle recording of state blocks */
2931 if (This->isRecordingState) {
2932 TRACE("Recording... not performing anything\n");
2936 if(oldValue == Value) {
2937 TRACE("Application is setting the old value over, nothing to do\n");
2941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2946 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2948 *Value = This->stateBlock->samplerState[Sampler][Type];
2949 TRACE("(%p) : Sampler %d Type %u Returning %d\n", This, Sampler, Type, *Value);
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 This->updateStateBlock->set.scissorRect = TRUE;
2958 This->updateStateBlock->changed.scissorRect = TRUE;
2959 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2960 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2963 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2965 if(This->isRecordingState) {
2966 TRACE("Recording... not performing anything\n");
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2975 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2978 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2979 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2983 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2985 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2987 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2989 This->updateStateBlock->vertexDecl = pDecl;
2990 This->updateStateBlock->changed.vertexDecl = TRUE;
2991 This->updateStateBlock->set.vertexDecl = TRUE;
2993 if (This->isRecordingState) {
2994 TRACE("Recording... not performing anything\n");
2996 } else if(pDecl == oldDecl) {
2997 /* Checked after the assignment to allow proper stateblock recording */
2998 TRACE("Application is setting the old declaration over, nothing to do\n");
3002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3006 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3009 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3011 *ppDecl = This->stateBlock->vertexDecl;
3012 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3016 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3018 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3020 This->updateStateBlock->vertexShader = pShader;
3021 This->updateStateBlock->changed.vertexShader = TRUE;
3022 This->updateStateBlock->set.vertexShader = TRUE;
3024 if (This->isRecordingState) {
3025 TRACE("Recording... not performing anything\n");
3027 } else if(oldShader == pShader) {
3028 /* Checked here to allow proper stateblock recording */
3029 TRACE("App is setting the old shader over, nothing to do\n");
3033 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3040 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 if (NULL == ppShader) {
3044 return WINED3DERR_INVALIDCALL;
3046 *ppShader = This->stateBlock->vertexShader;
3047 if( NULL != *ppShader)
3048 IWineD3DVertexShader_AddRef(*ppShader);
3050 TRACE("(%p) : returning %p\n", This, *ppShader);
3054 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3055 IWineD3DDevice *iface,
3057 CONST BOOL *srcData,
3060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3061 int i, cnt = min(count, MAX_CONST_B - start);
3063 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3064 iface, srcData, start, count);
3066 if (srcData == NULL || cnt < 0)
3067 return WINED3DERR_INVALIDCALL;
3069 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3070 for (i = 0; i < cnt; i++)
3071 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3073 for (i = start; i < cnt + start; ++i) {
3074 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3075 This->updateStateBlock->set.vertexShaderConstantsB[i] = TRUE;
3078 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3083 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3084 IWineD3DDevice *iface,
3089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3090 int cnt = min(count, MAX_CONST_B - start);
3092 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3093 iface, dstData, start, count);
3095 if (dstData == NULL || cnt < 0)
3096 return WINED3DERR_INVALIDCALL;
3098 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3102 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3103 IWineD3DDevice *iface,
3108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 int i, cnt = min(count, MAX_CONST_I - start);
3111 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3112 iface, srcData, start, count);
3114 if (srcData == NULL || cnt < 0)
3115 return WINED3DERR_INVALIDCALL;
3117 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3118 for (i = 0; i < cnt; i++)
3119 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3120 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3122 for (i = start; i < cnt + start; ++i) {
3123 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3124 This->updateStateBlock->set.vertexShaderConstantsI[i] = TRUE;
3127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3132 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3133 IWineD3DDevice *iface,
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 int cnt = min(count, MAX_CONST_I - start);
3141 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3142 iface, dstData, start, count);
3144 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3145 return WINED3DERR_INVALIDCALL;
3147 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3151 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3152 IWineD3DDevice *iface,
3154 CONST float *srcData,
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3161 iface, srcData, start, count);
3163 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3164 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3165 return WINED3DERR_INVALIDCALL;
3167 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3169 for (i = 0; i < count; i++)
3170 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3171 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3174 for (i = start; i < count + start; ++i) {
3175 if (!This->updateStateBlock->set.vertexShaderConstantsF[i]) {
3176 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3177 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3178 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3179 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3181 ptr->idx[ptr->count++] = i;
3182 This->updateStateBlock->set.vertexShaderConstantsF[i] = TRUE;
3184 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3192 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3193 IWineD3DDevice *iface,
3198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3199 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3201 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3202 iface, dstData, start, count);
3204 if (dstData == NULL || cnt < 0)
3205 return WINED3DERR_INVALIDCALL;
3207 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3211 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3213 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3218 static void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3220 /* This code can assume that GL_NV_register_combiners are supported, otherwise
3221 * it is never called.
3224 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3225 * that would be really messy and require shader recompilation
3226 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3227 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3228 * -> Whith a 1:1 mapping oneToOneTexUnitMap is set to avoid checking MAX_SAMPLERS array
3229 * entries to make pixel shaders cheaper. MAX_SAMPLERS will be 128 in dx10
3231 if(This->stateBlock->pixelShader || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3232 if(This->oneToOneTexUnitMap) {
3233 TRACE("Not touching 1:1 map\n");
3236 TRACE("Restoring 1:1 texture unit mapping\n");
3237 /* Restore a 1:1 mapping */
3238 for(i = 0; i < MAX_SAMPLERS; i++) {
3239 if(This->texUnitMap[i] != i) {
3240 This->texUnitMap[i] = i;
3241 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3242 markTextureStagesDirty(This, i);
3245 This->oneToOneTexUnitMap = TRUE;
3248 /* No pixel shader, and we do not have enough texture units available. Try to skip NULL textures
3249 * First, see if we can succeed at all
3252 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3253 if(This->stateBlock->textures[i] == NULL) tex++;
3256 if(GL_LIMITS(textures) + tex < This->stateBlock->lowest_disabled_stage) {
3257 FIXME("Too many bound textures to support the combiner settings\n");
3261 /* Now work out the mapping */
3263 This->oneToOneTexUnitMap = FALSE;
3264 WARN("Non 1:1 mapping UNTESTED!\n");
3265 for(i = 0; i < This->stateBlock->lowest_disabled_stage; i++) {
3266 /* Skip NULL textures */
3267 if (!This->stateBlock->textures[i]) {
3268 /* Map to -1, so the check below doesn't fail if a non-NULL
3269 * texture is set on this stage */
3270 TRACE("Mapping texture stage %d to -1\n", i);
3271 This->texUnitMap[i] = -1;
3276 TRACE("Mapping texture stage %d to unit %d\n", i, tex);
3277 if(This->texUnitMap[i] != tex) {
3278 This->texUnitMap[i] = tex;
3279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3280 markTextureStagesDirty(This, i);
3288 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3290 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3291 This->updateStateBlock->pixelShader = pShader;
3292 This->updateStateBlock->changed.pixelShader = TRUE;
3293 This->updateStateBlock->set.pixelShader = TRUE;
3295 /* Handle recording of state blocks */
3296 if (This->isRecordingState) {
3297 TRACE("Recording... not performing anything\n");
3300 if (This->isRecordingState) {
3301 TRACE("Recording... not performing anything\n");
3305 if(pShader == oldShader) {
3306 TRACE("App is setting the old pixel shader over, nothing to do\n");
3310 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3313 /* Rebuild the texture unit mapping if nvrc's are supported */
3314 if(GL_SUPPORT(NV_REGISTER_COMBINERS)) {
3315 IWineD3DDeviceImpl_FindTexUnitMap(This);
3321 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3324 if (NULL == ppShader) {
3325 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3326 return WINED3DERR_INVALIDCALL;
3329 *ppShader = This->stateBlock->pixelShader;
3330 if (NULL != *ppShader) {
3331 IWineD3DPixelShader_AddRef(*ppShader);
3333 TRACE("(%p) : returning %p\n", This, *ppShader);
3337 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3338 IWineD3DDevice *iface,
3340 CONST BOOL *srcData,
3343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 int i, cnt = min(count, MAX_CONST_B - start);
3346 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3347 iface, srcData, start, count);
3349 if (srcData == NULL || cnt < 0)
3350 return WINED3DERR_INVALIDCALL;
3352 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3353 for (i = 0; i < cnt; i++)
3354 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3356 for (i = start; i < cnt + start; ++i) {
3357 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3358 This->updateStateBlock->set.pixelShaderConstantsB[i] = TRUE;
3361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3366 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3367 IWineD3DDevice *iface,
3372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3373 int cnt = min(count, MAX_CONST_B - start);
3375 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3376 iface, dstData, start, count);
3378 if (dstData == NULL || cnt < 0)
3379 return WINED3DERR_INVALIDCALL;
3381 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3385 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3386 IWineD3DDevice *iface,
3391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 int i, cnt = min(count, MAX_CONST_I - start);
3394 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3395 iface, srcData, start, count);
3397 if (srcData == NULL || cnt < 0)
3398 return WINED3DERR_INVALIDCALL;
3400 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3401 for (i = 0; i < cnt; i++)
3402 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3403 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3405 for (i = start; i < cnt + start; ++i) {
3406 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3407 This->updateStateBlock->set.pixelShaderConstantsI[i] = TRUE;
3410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3415 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3416 IWineD3DDevice *iface,
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 int cnt = min(count, MAX_CONST_I - start);
3424 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3425 iface, dstData, start, count);
3427 if (dstData == NULL || cnt < 0)
3428 return WINED3DERR_INVALIDCALL;
3430 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3434 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3435 IWineD3DDevice *iface,
3437 CONST float *srcData,
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3443 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3444 iface, srcData, start, count);
3446 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3447 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3448 return WINED3DERR_INVALIDCALL;
3450 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3452 for (i = 0; i < count; i++)
3453 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3454 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3457 for (i = start; i < count + start; ++i) {
3458 if (!This->updateStateBlock->set.pixelShaderConstantsF[i]) {
3459 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3460 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3461 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3462 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3464 ptr->idx[ptr->count++] = i;
3465 This->updateStateBlock->set.pixelShaderConstantsF[i] = TRUE;
3467 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3475 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3476 IWineD3DDevice *iface,
3481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3482 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3484 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3485 iface, dstData, start, count);
3487 if (dstData == NULL || cnt < 0)
3488 return WINED3DERR_INVALIDCALL;
3490 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3494 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3496 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3497 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3499 DWORD DestFVF = dest->fvf;
3501 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3505 if (lpStrideData->u.s.normal.lpData) {
3506 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3509 if (lpStrideData->u.s.position.lpData == NULL) {
3510 ERR("Source has no position mask\n");
3511 return WINED3DERR_INVALIDCALL;
3514 /* We might access VBOs from this code, so hold the lock */
3517 if (dest->resource.allocatedMemory == NULL) {
3518 /* This may happen if we do direct locking into a vbo. Unlikely,
3519 * but theoretically possible(ddraw processvertices test)
3521 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3522 if(!dest->resource.allocatedMemory) {
3524 ERR("Out of memory\n");
3525 return E_OUTOFMEMORY;
3529 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3530 checkGLcall("glBindBufferARB");
3531 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3533 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3535 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3536 checkGLcall("glUnmapBufferARB");
3540 /* Get a pointer into the destination vbo(create one if none exists) and
3541 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3543 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3548 unsigned char extrabytes = 0;
3549 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3550 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3551 * this may write 4 extra bytes beyond the area that should be written
3553 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3554 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3555 if(!dest_conv_addr) {
3556 ERR("Out of memory\n");
3557 /* Continue without storing converted vertices */
3559 dest_conv = dest_conv_addr;
3563 * a) WINED3DRS_CLIPPING is enabled
3564 * b) WINED3DVOP_CLIP is passed
3566 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3567 static BOOL warned = FALSE;
3569 * The clipping code is not quite correct. Some things need
3570 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3571 * so disable clipping for now.
3572 * (The graphics in Half-Life are broken, and my processvertices
3573 * test crashes with IDirect3DDevice3)
3579 FIXME("Clipping is broken and disabled for now\n");
3581 } else doClip = FALSE;
3582 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3584 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3587 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3588 WINED3DTS_PROJECTION,
3590 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3591 WINED3DTS_WORLDMATRIX(0),
3594 TRACE("View mat:\n");
3595 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);
3596 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);
3597 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);
3598 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);
3600 TRACE("Proj mat:\n");
3601 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);
3602 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);
3603 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);
3604 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);
3606 TRACE("World mat:\n");
3607 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);
3608 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);
3609 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);
3610 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);
3612 /* Get the viewport */
3613 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3614 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3615 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3617 multiply_matrix(&mat,&view_mat,&world_mat);
3618 multiply_matrix(&mat,&proj_mat,&mat);
3620 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3622 for (i = 0; i < dwCount; i+= 1) {
3623 unsigned int tex_index;
3625 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3626 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3627 /* The position first */
3629 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3631 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3633 /* Multiplication with world, view and projection matrix */
3634 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);
3635 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);
3636 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);
3637 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);
3639 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3641 /* WARNING: The following things are taken from d3d7 and were not yet checked
3642 * against d3d8 or d3d9!
3645 /* Clipping conditions: From
3646 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3648 * A vertex is clipped if it does not match the following requirements
3652 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3654 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3655 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3660 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3661 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3664 /* "Normal" viewport transformation (not clipped)
3665 * 1) The values are divided by rhw
3666 * 2) The y axis is negative, so multiply it with -1
3667 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3668 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3669 * 4) Multiply x with Width/2 and add Width/2
3670 * 5) The same for the height
3671 * 6) Add the viewpoint X and Y to the 2D coordinates and
3672 * The minimum Z value to z
3673 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3675 * Well, basically it's simply a linear transformation into viewport
3687 z *= vp.MaxZ - vp.MinZ;
3689 x += vp.Width / 2 + vp.X;
3690 y += vp.Height / 2 + vp.Y;
3695 /* That vertex got clipped
3696 * Contrary to OpenGL it is not dropped completely, it just
3697 * undergoes a different calculation.
3699 TRACE("Vertex got clipped\n");
3706 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3707 * outside of the main vertex buffer memory. That needs some more
3712 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3715 ( (float *) dest_ptr)[0] = x;
3716 ( (float *) dest_ptr)[1] = y;
3717 ( (float *) dest_ptr)[2] = z;
3718 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3720 dest_ptr += 3 * sizeof(float);
3722 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3723 dest_ptr += sizeof(float);
3728 ( (float *) dest_conv)[0] = x * w;
3729 ( (float *) dest_conv)[1] = y * w;
3730 ( (float *) dest_conv)[2] = z * w;
3731 ( (float *) dest_conv)[3] = w;
3733 dest_conv += 3 * sizeof(float);
3735 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3736 dest_conv += sizeof(float);
3740 if (DestFVF & WINED3DFVF_PSIZE) {
3741 dest_ptr += sizeof(DWORD);
3742 if(dest_conv) dest_conv += sizeof(DWORD);
3744 if (DestFVF & WINED3DFVF_NORMAL) {
3746 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3747 /* AFAIK this should go into the lighting information */
3748 FIXME("Didn't expect the destination to have a normal\n");
3749 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3751 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3755 if (DestFVF & WINED3DFVF_DIFFUSE) {
3757 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3759 static BOOL warned = FALSE;
3762 ERR("No diffuse color in source, but destination has one\n");
3766 *( (DWORD *) dest_ptr) = 0xffffffff;
3767 dest_ptr += sizeof(DWORD);
3770 *( (DWORD *) dest_conv) = 0xffffffff;
3771 dest_conv += sizeof(DWORD);
3775 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3777 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3778 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3779 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3780 dest_conv += sizeof(DWORD);
3785 if (DestFVF & WINED3DFVF_SPECULAR) {
3786 /* What's the color value in the feedback buffer? */
3788 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3790 static BOOL warned = FALSE;
3793 ERR("No specular color in source, but destination has one\n");
3797 *( (DWORD *) dest_ptr) = 0xFF000000;
3798 dest_ptr += sizeof(DWORD);
3801 *( (DWORD *) dest_conv) = 0xFF000000;
3802 dest_conv += sizeof(DWORD);
3806 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3808 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3809 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3810 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3811 dest_conv += sizeof(DWORD);
3816 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3818 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3819 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3821 ERR("No source texture, but destination requests one\n");
3822 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3823 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3826 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3828 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3835 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3836 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3837 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3838 dwCount * get_flexible_vertex_size(DestFVF),
3840 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3841 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3848 #undef copy_and_next
3850 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3852 WineDirect3DVertexStridedData strided;
3853 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3854 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3857 ERR("Output vertex declaration not implemented yet\n");
3860 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3861 * and this call is quite performance critical, so don't call needlessly
3863 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3865 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3869 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3870 * control the streamIsUP flag, thus restore it afterwards.
3872 This->stateBlock->streamIsUP = FALSE;
3873 memset(&strided, 0, sizeof(strided));
3874 if(This->stateBlock->vertexDecl) {
3875 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3877 primitiveConvertToStridedData(iface, &strided, &vbo);
3879 This->stateBlock->streamIsUP = streamWasUP;
3881 if(vbo || SrcStartIndex) {
3883 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3884 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3886 * Also get the start index in, but only loop over all elements if there's something to add at all.
3888 #define FIXSRC(type) \
3889 if(strided.u.s.type.VBO) { \
3890 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3891 strided.u.s.type.VBO = 0; \
3892 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3894 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3898 if(strided.u.s.type.lpData) { \
3899 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3902 FIXSRC(blendWeights);
3903 FIXSRC(blendMatrixIndices);
3908 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3909 FIXSRC(texCoords[i]);
3922 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3926 * Get / Set Texture Stage States
3927 * TODO: Verify against dx9 definitions
3929 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3931 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3933 /* FIXME: Handle 3d textures? What if TSS value set before set texture? Need to reapply all values? */
3935 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3937 if (Stage >= MAX_TEXTURES) {
3938 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3942 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3943 This->updateStateBlock->set.textureState[Stage][Type] = TRUE;
3944 This->updateStateBlock->textureState[Stage][Type] = Value;
3946 if (This->isRecordingState) {
3947 TRACE("Recording... not performing anything\n");
3951 /* Checked after the assignments to allow proper stateblock recording */
3952 if(oldValue == Value) {
3953 TRACE("App is setting the old value over, nothing to do\n");
3957 if(Stage > This->stateBlock->lowest_disabled_stage &&
3958 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
3959 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
3960 * Changes in other states are important on disabled stages too
3965 if(Type == WINED3DTSS_COLOROP) {
3968 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
3969 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
3970 * they have to be disabled
3972 * The current stage is dirtified below.
3974 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
3975 TRACE("Additionally dirtifying stage %d\n", i);
3976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3978 This->stateBlock->lowest_disabled_stage = Stage;
3979 TRACE("New lowest disabled: %d\n", Stage);
3980 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
3981 /* Previously disabled stage enabled. Stages above it may need enabling
3982 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
3983 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
3985 * Again stage Stage doesn't need to be dirtified here, it is handled below.
3988 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
3989 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
3992 TRACE("Additionally dirtifying stage %d due to enable\n", i);
3993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
3995 This->stateBlock->lowest_disabled_stage = i;
3996 TRACE("New lowest disabled: %d\n", i);
3998 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
3999 /* TODO: Built a stage -> texture unit mapping for register combiners */
4003 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4005 /* Rebuild the stage -> gl texture unit mapping if register combiners are supported
4006 * If there is a pixel shader there will be a 1:1 mapping, no need to touch it. SetPixelShader
4007 * will call FindTexUnitMap too.
4009 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4010 IWineD3DDeviceImpl_FindTexUnitMap(This);
4015 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4017 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4018 *pValue = This->updateStateBlock->textureState[Stage][Type];
4025 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4028 IWineD3DBaseTexture *oldTexture;
4030 oldTexture = This->updateStateBlock->textures[Stage];
4031 TRACE("(%p) : Stage(%d), Texture (%p)\n", This, Stage, pTexture);
4033 #if 0 /* TODO: check so vertex textures */
4034 if (Stage >= D3DVERTEXTEXTURESAMPLER && Stage <= D3DVERTEXTEXTURESAMPLER3){
4035 This->updateStateBlock->vertexTextures[Stage - D3DVERTEXTEXTURESAMPLER] = pTexture;
4040 if(pTexture != NULL) {
4041 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4043 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4044 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4045 return WINED3DERR_INVALIDCALL;
4047 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4050 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4051 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4053 This->updateStateBlock->set.textures[Stage] = TRUE;
4054 This->updateStateBlock->changed.textures[Stage] = TRUE;
4055 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4056 This->updateStateBlock->textures[Stage] = pTexture;
4058 /* Handle recording of state blocks */
4059 if (This->isRecordingState) {
4060 TRACE("Recording... not performing anything\n");
4064 if(oldTexture == pTexture) {
4065 TRACE("App is setting the same texture again, nothing to do\n");
4069 /** NOTE: MSDN says that setTexture increases the reference count,
4070 * and the the application must set the texture back to null (or have a leaky application),
4071 * This means we should pass the refcount up to the parent
4072 *******************************/
4073 if (NULL != This->updateStateBlock->textures[Stage]) {
4074 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4075 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4077 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4078 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4079 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4080 * so the COLOROP and ALPHAOP have to be dirtified.
4082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4083 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4085 if(bindCount == 1) {
4086 new->baseTexture.sampler = Stage;
4088 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4092 if (NULL != oldTexture) {
4093 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4094 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4096 IWineD3DBaseTexture_Release(oldTexture);
4097 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4102 if(bindCount && old->baseTexture.sampler == Stage) {
4104 /* Have to do a search for the other sampler(s) where the texture is bound to
4105 * Shouldn't happen as long as apps bind a texture only to one stage
4107 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4108 for(i = 0; i < GL_LIMITS(sampler_stages); i++) {
4109 if(This->updateStateBlock->textures[i] == oldTexture) {
4110 old->baseTexture.sampler = i;
4117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4119 /* Verify the texture unit mapping(and rebuild it if needed) if we use nvrcs and no
4120 * pixel shader is used
4122 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4123 IWineD3DDeviceImpl_FindTexUnitMap(This);
4129 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4131 TRACE("(%p) : (%d /* Stage */,%p /* ppTexture */)\n", This, Stage, ppTexture);
4133 *ppTexture=This->stateBlock->textures[Stage];
4135 IWineD3DBaseTexture_AddRef(*ppTexture);
4143 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4144 IWineD3DSurface **ppBackBuffer) {
4145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4146 IWineD3DSwapChain *swapChain;
4149 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4151 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4152 if (hr == WINED3D_OK) {
4153 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4154 IWineD3DSwapChain_Release(swapChain);
4156 *ppBackBuffer = NULL;
4161 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4163 WARN("(%p) : stub, calling idirect3d for now\n", This);
4164 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4167 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4169 IWineD3DSwapChain *swapChain;
4172 if(iSwapChain > 0) {
4173 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4174 if (hr == WINED3D_OK) {
4175 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4176 IWineD3DSwapChain_Release(swapChain);
4178 FIXME("(%p) Error getting display mode\n", This);
4181 /* Don't read the real display mode,
4182 but return the stored mode instead. X11 can't change the color
4183 depth, and some apps are pretty angry if they SetDisplayMode from
4184 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4186 Also don't relay to the swapchain because with ddraw it's possible
4187 that there isn't a swapchain at all */
4188 pMode->Width = This->ddraw_width;
4189 pMode->Height = This->ddraw_height;
4190 pMode->Format = This->ddraw_format;
4191 pMode->RefreshRate = 0;
4198 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4200 TRACE("(%p)->(%p)\n", This, hWnd);
4202 if(This->ddraw_fullscreen) {
4203 if(This->ddraw_window && This->ddraw_window != hWnd) {
4204 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4206 if(hWnd && This->ddraw_window != hWnd) {
4207 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4211 This->ddraw_window = hWnd;
4215 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4217 TRACE("(%p)->(%p)\n", This, hWnd);
4219 *hWnd = This->ddraw_window;
4224 * Stateblock related functions
4227 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4229 IWineD3DStateBlockImpl *object;
4230 HRESULT temp_result;
4233 TRACE("(%p)\n", This);
4235 if (This->isRecordingState) {
4236 return WINED3DERR_INVALIDCALL;
4239 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4240 if (NULL == object ) {
4241 FIXME("(%p)Error allocating memory for stateblock\n", This);
4242 return E_OUTOFMEMORY;
4244 TRACE("(%p) created object %p\n", This, object);
4245 object->wineD3DDevice= This;
4246 /** FIXME: object->parent = parent; **/
4247 object->parent = NULL;
4248 object->blockType = WINED3DSBT_ALL;
4250 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4252 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4253 list_init(&object->lightMap[i]);
4256 temp_result = allocate_shader_constants(object);
4257 if (WINED3D_OK != temp_result)
4260 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4261 This->updateStateBlock = object;
4262 This->isRecordingState = TRUE;
4264 TRACE("(%p) recording stateblock %p\n",This , object);
4268 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4271 if (!This->isRecordingState) {
4272 FIXME("(%p) not recording! returning error\n", This);
4273 *ppStateBlock = NULL;
4274 return WINED3DERR_INVALIDCALL;
4277 *ppStateBlock = (IWineD3DStateBlock*)This->updateStateBlock;
4278 This->isRecordingState = FALSE;
4279 This->updateStateBlock = This->stateBlock;
4280 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4281 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4282 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4287 * Scene related functions
4289 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4290 /* At the moment we have no need for any functionality at the beginning
4292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4293 TRACE("(%p)\n", This);
4296 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4297 return WINED3DERR_INVALIDCALL;
4299 This->inScene = TRUE;
4303 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4305 TRACE("(%p)\n", This);
4307 if(!This->inScene) {
4308 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4309 return WINED3DERR_INVALIDCALL;
4313 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4314 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4316 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4318 checkGLcall("glFlush");
4321 This->inScene = FALSE;
4325 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4326 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4327 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4329 IWineD3DSwapChain *swapChain = NULL;
4331 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4333 TRACE("(%p) Presenting the frame\n", This);
4335 for(i = 0 ; i < swapchains ; i ++) {
4337 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4338 TRACE("presentinng chain %d, %p\n", i, swapChain);
4339 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4340 IWineD3DSwapChain_Release(swapChain);
4346 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4347 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4349 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4351 GLbitfield glMask = 0;
4353 CONST WINED3DRECT* curRect;
4355 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4356 Count, pRects, Flags, Color, Z, Stencil);
4358 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4359 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4360 /* TODO: What about depth stencil buffers without stencil bits? */
4361 return WINED3DERR_INVALIDCALL;
4365 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4366 * and not the last active one.
4369 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4370 apply_fbo_state(iface);
4373 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
4375 glEnable(GL_SCISSOR_TEST);
4376 checkGLcall("glEnable GL_SCISSOR_TEST");
4377 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
4378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
4380 if (Count > 0 && pRects) {
4386 /* Only set the values up once, as they are not changing */
4387 if (Flags & WINED3DCLEAR_STENCIL) {
4388 glClearStencil(Stencil);
4389 checkGLcall("glClearStencil");
4390 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4391 glStencilMask(0xFFFFFFFF);
4394 if (Flags & WINED3DCLEAR_ZBUFFER) {
4395 glDepthMask(GL_TRUE);
4397 checkGLcall("glClearDepth");
4398 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4399 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4402 if (Flags & WINED3DCLEAR_TARGET) {
4403 TRACE("Clearing screen with glClear to color %x\n", Color);
4404 glClearColor(D3DCOLOR_R(Color),
4408 checkGLcall("glClearColor");
4410 /* Clear ALL colors! */
4411 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4412 glMask = glMask | GL_COLOR_BUFFER_BIT;
4416 /* In drawable flag is set below */
4418 glScissor(This->stateBlock->viewport.X,
4419 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4420 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4421 This->stateBlock->viewport.Width,
4422 This->stateBlock->viewport.Height);
4423 checkGLcall("glScissor");
4425 checkGLcall("glClear");
4427 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4428 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4430 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4431 curRect[0].x2 < target->currentDesc.Width ||
4432 curRect[0].y2 < target->currentDesc.Height) {
4433 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4434 blt_to_drawable(This, target);
4438 /* Now process each rect in turn */
4439 for (i = 0; i < Count; i++) {
4440 /* Note gl uses lower left, width/height */
4441 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4442 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4443 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4444 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4446 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4447 * The rectangle is not cleared, no error is returned, but further rectanlges are
4448 * still cleared if they are valid
4450 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4451 TRACE("Rectangle with negative dimensions, ignoring\n");
4455 if(This->render_offscreen) {
4456 glScissor(curRect[i].x1, curRect[i].y1,
4457 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4459 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4460 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4462 checkGLcall("glScissor");
4465 checkGLcall("glClear");
4469 /* Restore the old values (why..?) */
4470 if (Flags & WINED3DCLEAR_STENCIL) {
4471 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4473 if (Flags & WINED3DCLEAR_TARGET) {
4474 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4475 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4476 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4477 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4478 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4483 /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
4484 * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
4486 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4487 target->Flags |= SFLAG_INTEXTURE;
4488 target->Flags &= ~SFLAG_INSYSMEM;
4490 target->Flags |= SFLAG_INDRAWABLE;
4491 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4499 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4500 UINT PrimitiveCount) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4504 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4505 debug_d3dprimitivetype(PrimitiveType),
4506 StartVertex, PrimitiveCount);
4508 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4509 if(This->stateBlock->streamIsUP) {
4510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4511 This->stateBlock->streamIsUP = FALSE;
4514 if(This->stateBlock->loadBaseVertexIndex != 0) {
4515 This->stateBlock->loadBaseVertexIndex = 0;
4516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4518 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4519 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4520 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4524 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4525 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4526 WINED3DPRIMITIVETYPE PrimitiveType,
4527 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4531 IWineD3DIndexBuffer *pIB;
4532 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4535 pIB = This->stateBlock->pIndexData;
4537 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4538 * without an index buffer set. (The first time at least...)
4539 * D3D8 simply dies, but I doubt it can do much harm to return
4540 * D3DERR_INVALIDCALL there as well. */
4541 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4542 return WINED3DERR_INVALIDCALL;
4545 if(This->stateBlock->streamIsUP) {
4546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4547 This->stateBlock->streamIsUP = FALSE;
4549 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4551 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4552 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4553 minIndex, NumVertices, startIndex, primCount);
4555 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4556 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4562 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4563 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4567 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4568 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4573 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4574 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4575 UINT VertexStreamZeroStride) {
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4579 debug_d3dprimitivetype(PrimitiveType),
4580 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4582 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4583 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4584 This->stateBlock->streamOffset[0] = 0;
4585 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4586 This->stateBlock->streamIsUP = TRUE;
4587 This->stateBlock->loadBaseVertexIndex = 0;
4589 /* TODO: Only mark dirty if drawing from a different UP address */
4590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4592 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4593 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4595 /* MSDN specifies stream zero settings must be set to NULL */
4596 This->stateBlock->streamStride[0] = 0;
4597 This->stateBlock->streamSource[0] = NULL;
4599 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4600 * the new stream sources or use UP drawing again
4605 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4606 UINT MinVertexIndex, UINT NumVertices,
4607 UINT PrimitiveCount, CONST void* pIndexData,
4608 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4609 UINT VertexStreamZeroStride) {
4611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4613 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4614 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4615 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4616 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4618 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4624 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4625 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4626 This->stateBlock->streamIsUP = TRUE;
4627 This->stateBlock->streamOffset[0] = 0;
4628 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4630 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4631 This->stateBlock->baseVertexIndex = 0;
4632 This->stateBlock->loadBaseVertexIndex = 0;
4633 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4637 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4639 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4640 This->stateBlock->streamSource[0] = NULL;
4641 This->stateBlock->streamStride[0] = 0;
4642 This->stateBlock->pIndexData = NULL;
4643 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4644 * SetStreamSource to specify a vertex buffer
4650 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4653 /* Mark the state dirty until we have nicer tracking
4654 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4659 This->stateBlock->baseVertexIndex = 0;
4660 This->up_strided = DrawPrimStrideData;
4661 This->stateBlock->streamIsUP = TRUE;
4662 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4663 This->up_strided = NULL;
4666 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4667 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4669 HRESULT hr = WINED3D_OK;
4670 WINED3DRESOURCETYPE sourceType;
4671 WINED3DRESOURCETYPE destinationType;
4674 /* TODO: think about moving the code into IWineD3DBaseTexture */
4676 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4678 /* verify that the source and destination textures aren't NULL */
4679 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4680 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4681 This, pSourceTexture, pDestinationTexture);
4682 hr = WINED3DERR_INVALIDCALL;
4685 if (pSourceTexture == pDestinationTexture) {
4686 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4687 This, pSourceTexture, pDestinationTexture);
4688 hr = WINED3DERR_INVALIDCALL;
4690 /* Verify that the source and destination textures are the same type */
4691 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4692 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4694 if (sourceType != destinationType) {
4695 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4697 hr = WINED3DERR_INVALIDCALL;
4700 /* check that both textures have the identical numbers of levels */
4701 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4702 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4703 hr = WINED3DERR_INVALIDCALL;
4706 if (WINED3D_OK == hr) {
4708 /* Make sure that the destination texture is loaded */
4709 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4711 /* Update every surface level of the texture */
4712 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4714 switch (sourceType) {
4715 case WINED3DRTYPE_TEXTURE:
4717 IWineD3DSurface *srcSurface;
4718 IWineD3DSurface *destSurface;
4720 for (i = 0 ; i < levels ; ++i) {
4721 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4722 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4723 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4724 IWineD3DSurface_Release(srcSurface);
4725 IWineD3DSurface_Release(destSurface);
4726 if (WINED3D_OK != hr) {
4727 WARN("(%p) : Call to update surface failed\n", This);
4733 case WINED3DRTYPE_CUBETEXTURE:
4735 IWineD3DSurface *srcSurface;
4736 IWineD3DSurface *destSurface;
4737 WINED3DCUBEMAP_FACES faceType;
4739 for (i = 0 ; i < levels ; ++i) {
4740 /* Update each cube face */
4741 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4742 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4743 if (WINED3D_OK != hr) {
4744 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4746 TRACE("Got srcSurface %p\n", srcSurface);
4748 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4749 if (WINED3D_OK != hr) {
4750 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4752 TRACE("Got desrSurface %p\n", destSurface);
4754 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4755 IWineD3DSurface_Release(srcSurface);
4756 IWineD3DSurface_Release(destSurface);
4757 if (WINED3D_OK != hr) {
4758 WARN("(%p) : Call to update surface failed\n", This);
4765 #if 0 /* TODO: Add support for volume textures */
4766 case WINED3DRTYPE_VOLUMETEXTURE:
4768 IWineD3DVolume srcVolume = NULL;
4769 IWineD3DSurface destVolume = NULL;
4771 for (i = 0 ; i < levels ; ++i) {
4772 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4773 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4774 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4775 IWineD3DVolume_Release(srcSurface);
4776 IWineD3DVolume_Release(destSurface);
4777 if (WINED3D_OK != hr) {
4778 WARN("(%p) : Call to update volume failed\n", This);
4786 FIXME("(%p) : Unsupported source and destination type\n", This);
4787 hr = WINED3DERR_INVALIDCALL;
4794 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4795 IWineD3DSwapChain *swapChain;
4797 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4798 if(hr == WINED3D_OK) {
4799 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4800 IWineD3DSwapChain_Release(swapChain);
4805 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4807 /* return a sensible default */
4809 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4810 FIXME("(%p) : stub\n", This);
4814 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4817 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4818 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4819 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4820 return WINED3DERR_INVALIDCALL;
4822 for (j = 0; j < 256; ++j) {
4823 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4824 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4825 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4826 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4828 TRACE("(%p) : returning\n", This);
4832 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4835 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4836 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4837 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4838 return WINED3DERR_INVALIDCALL;
4840 for (j = 0; j < 256; ++j) {
4841 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4842 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4843 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4844 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4846 TRACE("(%p) : returning\n", This);
4850 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4852 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4853 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4854 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4855 return WINED3DERR_INVALIDCALL;
4857 /*TODO: stateblocks */
4858 This->currentPalette = PaletteNumber;
4859 TRACE("(%p) : returning\n", This);
4863 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 if (PaletteNumber == NULL) {
4866 WARN("(%p) : returning Invalid Call\n", This);
4867 return WINED3DERR_INVALIDCALL;
4869 /*TODO: stateblocks */
4870 *PaletteNumber = This->currentPalette;
4871 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4875 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4877 static BOOL showFixmes = TRUE;
4879 FIXME("(%p) : stub\n", This);
4883 This->softwareVertexProcessing = bSoftware;
4888 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4890 static BOOL showFixmes = TRUE;
4892 FIXME("(%p) : stub\n", This);
4895 return This->softwareVertexProcessing;
4899 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4901 IWineD3DSwapChain *swapChain;
4904 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4906 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4907 if(hr == WINED3D_OK){
4908 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4909 IWineD3DSwapChain_Release(swapChain);
4911 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4917 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 static BOOL showfixmes = TRUE;
4920 if(nSegments != 0.0f) {
4922 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
4929 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
4930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4931 static BOOL showfixmes = TRUE;
4933 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
4939 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4941 /** TODO: remove casts to IWineD3DSurfaceImpl
4942 * NOTE: move code to surface to accomplish this
4943 ****************************************/
4944 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
4945 int srcWidth, srcHeight;
4946 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
4947 WINED3DFORMAT destFormat, srcFormat;
4949 int srcLeft, destLeft, destTop;
4950 WINED3DPOOL srcPool, destPool;
4952 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
4953 glDescriptor *glDescription = NULL;
4955 WINED3DSURFACE_DESC winedesc;
4957 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
4958 memset(&winedesc, 0, sizeof(winedesc));
4959 winedesc.Width = &srcSurfaceWidth;
4960 winedesc.Height = &srcSurfaceHeight;
4961 winedesc.Pool = &srcPool;
4962 winedesc.Format = &srcFormat;
4964 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
4966 winedesc.Width = &destSurfaceWidth;
4967 winedesc.Height = &destSurfaceHeight;
4968 winedesc.Pool = &destPool;
4969 winedesc.Format = &destFormat;
4970 winedesc.Size = &destSize;
4972 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4974 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
4975 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
4976 return WINED3DERR_INVALIDCALL;
4979 if (destFormat == WINED3DFMT_UNKNOWN) {
4980 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
4981 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
4983 /* Get the update surface description */
4984 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
4989 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4991 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
4992 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4993 checkGLcall("glActiveTextureARB");
4996 /* Make sure the surface is loaded and up to date */
4997 IWineD3DSurface_PreLoad(pDestinationSurface);
4999 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5001 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5002 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5003 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5004 srcLeft = pSourceRect ? pSourceRect->left : 0;
5005 destLeft = pDestPoint ? pDestPoint->x : 0;
5006 destTop = pDestPoint ? pDestPoint->y : 0;
5009 /* This function doesn't support compressed textures
5010 the pitch is just bytesPerPixel * width */
5011 if(srcWidth != srcSurfaceWidth || srcLeft ){
5012 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5013 offset += srcLeft * pSrcSurface->bytesPerPixel;
5014 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5016 /* TODO DXT formats */
5018 if(pSourceRect != NULL && pSourceRect->top != 0){
5019 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5021 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5023 ,glDescription->level
5028 ,glDescription->glFormat
5029 ,glDescription->glType
5030 ,IWineD3DSurface_GetData(pSourceSurface)
5034 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5036 /* need to lock the surface to get the data */
5037 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5040 /* TODO: Cube and volume support */
5042 /* not a whole row so we have to do it a line at a time */
5045 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5046 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5048 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5050 glTexSubImage2D(glDescription->target
5051 ,glDescription->level
5056 ,glDescription->glFormat
5057 ,glDescription->glType
5058 ,data /* could be quicker using */
5063 } else { /* Full width, so just write out the whole texture */
5065 if (WINED3DFMT_DXT1 == destFormat ||
5066 WINED3DFMT_DXT2 == destFormat ||
5067 WINED3DFMT_DXT3 == destFormat ||
5068 WINED3DFMT_DXT4 == destFormat ||
5069 WINED3DFMT_DXT5 == destFormat) {
5070 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5071 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5072 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5073 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5074 } if (destFormat != srcFormat) {
5075 FIXME("Updating mixed format compressed texture is not curretly support\n");
5077 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5078 glDescription->level,
5079 glDescription->glFormatInternal,
5084 IWineD3DSurface_GetData(pSourceSurface));
5087 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5092 glTexSubImage2D(glDescription->target
5093 ,glDescription->level
5098 ,glDescription->glFormat
5099 ,glDescription->glType
5100 ,IWineD3DSurface_GetData(pSourceSurface)
5104 checkGLcall("glTexSubImage2D");
5108 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5109 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5115 /* Implementation details at http://developer.nvidia.com/attach/6494
5117 http://oss.sgi.com/projects/ogl-sample/registry/NV/evaluators.txt
5118 hmm.. no longer supported use
5119 OpenGL evaluators or tessellate surfaces within your application.
5122 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawRectPatch.asp */
5123 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5125 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5126 FIXME("(%p) : Stub\n", This);
5131 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5132 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5134 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5135 FIXME("(%p) : Stub\n", This);
5139 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5141 TRACE("(%p) Handle(%d)\n", This, Handle);
5142 FIXME("(%p) : Stub\n", This);
5146 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5148 IWineD3DSwapChain *swapchain;
5150 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5151 if (SUCCEEDED(hr)) {
5152 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5159 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5163 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5164 checkGLcall("glGenFramebuffersEXT()");
5166 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5167 checkGLcall("glBindFramebuffer()");
5170 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5171 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5172 GLenum texttarget, target;
5175 texttarget = surface_impl->glDescription.target;
5176 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5177 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5179 IWineD3DSurface_PreLoad(surface);
5181 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
5182 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
5183 glBindTexture(target, old_binding);
5185 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5187 checkGLcall("attach_surface_fbo");
5190 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5192 IWineD3DSwapChain *swapchain;
5194 swapchain = get_swapchain(surface);
5198 TRACE("Surface %p is onscreen\n", surface);
5200 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5201 buffer = surface_get_gl_buffer(surface, swapchain);
5202 glDrawBuffer(buffer);
5203 checkGLcall("glDrawBuffer()");
5205 TRACE("Surface %p is offscreen\n", surface);
5206 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5207 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5211 glEnable(GL_SCISSOR_TEST);
5213 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5215 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5216 rect->x2 - rect->x1, rect->y2 - rect->y1);
5218 checkGLcall("glScissor");
5220 glDisable(GL_SCISSOR_TEST);
5222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5224 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5227 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5228 glClear(GL_COLOR_BUFFER_BIT);
5229 checkGLcall("glClear");
5231 if (This->render_offscreen) {
5232 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5234 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5235 checkGLcall("glBindFramebuffer()");
5238 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5239 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5240 glDrawBuffer(GL_BACK);
5241 checkGLcall("glDrawBuffer()");
5245 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5247 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5249 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5251 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5252 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5253 return WINED3DERR_INVALIDCALL;
5256 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5257 color_fill_fbo(iface, pSurface, pRect, color);
5260 /* Just forward this to the DirectDraw blitting engine */
5261 memset(&BltFx, 0, sizeof(BltFx));
5262 BltFx.dwSize = sizeof(BltFx);
5263 BltFx.u5.dwFillColor = color;
5264 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5268 /* rendertarget and deptth stencil functions */
5269 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5272 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5273 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5274 return WINED3DERR_INVALIDCALL;
5277 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5278 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5279 /* Note inc ref on returned surface */
5280 if(*ppRenderTarget != NULL)
5281 IWineD3DSurface_AddRef(*ppRenderTarget);
5285 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5287 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5288 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5289 IWineD3DSwapChainImpl *Swapchain;
5292 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5294 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5295 if(hr != WINED3D_OK) {
5296 ERR("Can't get the swapchain\n");
5300 /* Make sure to release the swapchain */
5301 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5303 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5304 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5305 return WINED3DERR_INVALIDCALL;
5307 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5308 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5309 return WINED3DERR_INVALIDCALL;
5312 if(Swapchain->frontBuffer != Front) {
5313 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5315 if(Swapchain->frontBuffer)
5316 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5317 Swapchain->frontBuffer = Front;
5319 if(Swapchain->frontBuffer) {
5320 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5324 if(Back && !Swapchain->backBuffer) {
5325 /* We need memory for the back buffer array - only one back buffer this way */
5326 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5327 if(!Swapchain->backBuffer) {
5328 ERR("Out of memory\n");
5329 return E_OUTOFMEMORY;
5333 if(Swapchain->backBuffer[0] != Back) {
5334 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5336 /* What to do about the context here in the case of multithreading? Not sure.
5337 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5340 if(!Swapchain->backBuffer[0]) {
5341 /* GL was told to draw to the front buffer at creation,
5344 glDrawBuffer(GL_BACK);
5345 checkGLcall("glDrawBuffer(GL_BACK)");
5346 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5347 Swapchain->presentParms.BackBufferCount = 1;
5349 /* That makes problems - disable for now */
5350 /* glDrawBuffer(GL_FRONT); */
5351 checkGLcall("glDrawBuffer(GL_FRONT)");
5352 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5353 Swapchain->presentParms.BackBufferCount = 0;
5357 if(Swapchain->backBuffer[0])
5358 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5359 Swapchain->backBuffer[0] = Back;
5361 if(Swapchain->backBuffer[0]) {
5362 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5364 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5372 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5374 *ppZStencilSurface = This->depthStencilBuffer;
5375 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5377 if(*ppZStencilSurface != NULL) {
5378 /* Note inc ref on returned surface */
5379 IWineD3DSurface_AddRef(*ppZStencilSurface);
5384 /* TODO: Handle stencil attachments */
5385 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5387 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5389 TRACE("Set depth stencil to %p\n", depth_stencil);
5391 if (depth_stencil_impl) {
5392 if (depth_stencil_impl->current_renderbuffer) {
5393 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5394 checkGLcall("glFramebufferRenderbufferEXT()");
5396 GLenum texttarget, target;
5397 GLint old_binding = 0;
5399 texttarget = depth_stencil_impl->glDescription.target;
5400 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5401 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5403 IWineD3DSurface_PreLoad(depth_stencil);
5405 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5406 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5407 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5408 glBindTexture(target, old_binding);
5410 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5411 checkGLcall("glFramebufferTexture2DEXT()");
5414 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5415 checkGLcall("glFramebufferTexture2DEXT()");
5419 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5421 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5423 TRACE("Set render target %u to %p\n", idx, render_target);
5426 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5427 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5429 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5430 checkGLcall("glFramebufferTexture2DEXT()");
5432 This->draw_buffers[idx] = GL_NONE;
5436 static void check_fbo_status(IWineD3DDevice *iface) {
5437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5440 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5441 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5442 TRACE("FBO complete\n");
5444 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5446 /* Dump the FBO attachments */
5447 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5448 IWineD3DSurfaceImpl *attachment;
5451 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5452 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5454 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5455 attachment->pow2Width, attachment->pow2Height);
5458 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5460 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5461 attachment->pow2Width, attachment->pow2Height);
5467 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5469 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5470 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5472 if (!ds_impl) return FALSE;
5474 if (ds_impl->current_renderbuffer) {
5475 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5476 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5479 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5480 rt_impl->pow2Height != ds_impl->pow2Height);
5483 void apply_fbo_state(IWineD3DDevice *iface) {
5484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5487 if (This->render_offscreen) {
5488 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5490 /* Apply render targets */
5491 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5492 IWineD3DSurface *render_target = This->render_targets[i];
5493 if (This->fbo_color_attachments[i] != render_target) {
5494 set_render_target_fbo(iface, i, render_target);
5495 This->fbo_color_attachments[i] = render_target;
5499 /* Apply depth targets */
5500 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5501 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5502 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5504 if (This->stencilBufferTarget) {
5505 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5507 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5508 This->fbo_depth_attachment = This->stencilBufferTarget;
5511 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5512 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5513 checkGLcall("glDrawBuffers()");
5515 glDrawBuffer(This->draw_buffers[0]);
5516 checkGLcall("glDrawBuffer()");
5519 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5522 check_fbo_status(iface);
5525 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5526 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5528 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5529 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5532 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5533 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5534 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5535 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5537 glDisable(GL_SCISSOR_TEST);
5538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5541 case WINED3DTEXF_LINEAR:
5542 gl_filter = GL_LINEAR;
5546 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5547 case WINED3DTEXF_NONE:
5548 case WINED3DTEXF_POINT:
5549 gl_filter = GL_NEAREST;
5553 /* Attach src surface to src fbo */
5554 src_swapchain = get_swapchain(src_surface);
5555 if (src_swapchain) {
5558 TRACE("Source surface %p is onscreen\n", src_surface);
5560 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5561 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5562 glReadBuffer(buffer);
5563 checkGLcall("glReadBuffer()");
5565 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5566 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5568 TRACE("Source surface %p is offscreen\n", src_surface);
5569 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5570 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5571 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5572 checkGLcall("glReadBuffer()");
5575 /* Attach dst surface to dst fbo */
5576 dst_swapchain = get_swapchain(dst_surface);
5577 if (dst_swapchain) {
5580 TRACE("Destination surface %p is onscreen\n", dst_surface);
5582 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5583 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5584 glDrawBuffer(buffer);
5585 checkGLcall("glDrawBuffer()");
5587 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5588 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5590 TRACE("Destination surface %p is offscreen\n", dst_surface);
5591 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5592 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5593 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5594 checkGLcall("glDrawBuffer()");
5598 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5599 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5600 checkGLcall("glBlitFramebuffer()");
5602 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5603 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5604 checkGLcall("glBlitFramebuffer()");
5607 if (This->render_offscreen) {
5608 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5610 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5611 checkGLcall("glBindFramebuffer()");
5614 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5615 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5616 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5617 glDrawBuffer(GL_BACK);
5618 checkGLcall("glDrawBuffer()");
5622 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5624 WINED3DVIEWPORT viewport;
5626 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5628 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5629 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5630 return WINED3DERR_INVALIDCALL;
5633 /* MSDN says that null disables the render target
5634 but a device must always be associated with a render target
5635 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5637 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5640 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5641 FIXME("Trying to set render target 0 to NULL\n");
5642 return WINED3DERR_INVALIDCALL;
5644 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5645 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);
5646 return WINED3DERR_INVALIDCALL;
5649 /* If we are trying to set what we already have, don't bother */
5650 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5651 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5654 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5655 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5656 This->render_targets[RenderTargetIndex] = pRenderTarget;
5658 /* Render target 0 is special */
5659 if(RenderTargetIndex == 0) {
5660 /* Finally, reset the viewport as the MSDN states. */
5661 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5662 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5665 viewport.MaxZ = 1.0f;
5666 viewport.MinZ = 0.0f;
5667 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5668 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5669 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5673 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5675 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5676 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5678 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5683 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5685 HRESULT hr = WINED3D_OK;
5686 IWineD3DSurface *tmp;
5688 TRACE("(%p) Swapping z-buffer\n",This);
5690 if (pNewZStencil == This->stencilBufferTarget) {
5691 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5693 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5694 * depending on the renter target implementation being used.
5695 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5696 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5697 * stencil buffer and incure an extra memory overhead
5698 ******************************************************/
5700 tmp = This->stencilBufferTarget;
5701 This->stencilBufferTarget = pNewZStencil;
5702 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5703 /* should we be calling the parent or the wined3d surface? */
5704 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5705 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5708 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5709 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5719 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5720 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5722 /* TODO: the use of Impl is deprecated. */
5723 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5724 WINED3DLOCKED_RECT lockedRect;
5726 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5728 /* some basic validation checks */
5729 if(This->cursorTexture) {
5731 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5732 glDeleteTextures(1, &This->cursorTexture);
5734 This->cursorTexture = 0;
5737 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5738 This->haveHardwareCursor = TRUE;
5740 This->haveHardwareCursor = FALSE;
5743 WINED3DLOCKED_RECT rect;
5745 /* MSDN: Cursor must be A8R8G8B8 */
5746 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5747 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5748 return WINED3DERR_INVALIDCALL;
5751 /* MSDN: Cursor must be smaller than the display mode */
5752 if(pSur->currentDesc.Width > This->ddraw_width ||
5753 pSur->currentDesc.Height > This->ddraw_height) {
5754 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);
5755 return WINED3DERR_INVALIDCALL;
5758 if (!This->haveHardwareCursor) {
5759 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5761 /* Do not store the surface's pointer because the application may
5762 * release it after setting the cursor image. Windows doesn't
5763 * addref the set surface, so we can't do this either without
5764 * creating circular refcount dependencies. Copy out the gl texture
5767 This->cursorWidth = pSur->currentDesc.Width;
5768 This->cursorHeight = pSur->currentDesc.Height;
5769 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5771 const PixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8);
5772 char *mem, *bits = (char *)rect.pBits;
5773 GLint intfmt = tableEntry->glInternal;
5774 GLint format = tableEntry->glFormat;
5775 GLint type = tableEntry->glType;
5776 INT height = This->cursorHeight;
5777 INT width = This->cursorWidth;
5778 INT bpp = tableEntry->bpp;
5781 /* Reformat the texture memory (pitch and width can be
5783 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5784 for(i = 0; i < height; i++)
5785 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5786 IWineD3DSurface_UnlockRect(pCursorBitmap);
5789 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5790 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5791 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5794 /* Make sure that a proper texture unit is selected */
5795 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5796 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5797 checkGLcall("glActiveTextureARB");
5799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5800 /* Create a new cursor texture */
5801 glGenTextures(1, &This->cursorTexture);
5802 checkGLcall("glGenTextures");
5803 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5804 checkGLcall("glBindTexture");
5805 /* Copy the bitmap memory into the cursor texture */
5806 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
5807 HeapFree(GetProcessHeap(), 0, mem);
5808 checkGLcall("glTexImage2D");
5810 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5811 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
5812 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
5819 FIXME("A cursor texture was not returned.\n");
5820 This->cursorTexture = 0;
5825 /* Draw a hardware cursor */
5826 ICONINFO cursorInfo;
5828 /* Create and clear maskBits because it is not needed for
5829 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
5831 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
5832 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
5833 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
5834 WINED3DLOCK_NO_DIRTY_UPDATE |
5835 WINED3DLOCK_READONLY
5837 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
5838 pSur->currentDesc.Height);
5840 cursorInfo.fIcon = FALSE;
5841 cursorInfo.xHotspot = XHotSpot;
5842 cursorInfo.yHotspot = YHotSpot;
5843 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
5844 pSur->currentDesc.Height, 1,
5846 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
5847 pSur->currentDesc.Height, 1,
5848 32, lockedRect.pBits);
5849 IWineD3DSurface_UnlockRect(pCursorBitmap);
5850 /* Create our cursor and clean up. */
5851 cursor = CreateIconIndirect(&cursorInfo);
5853 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
5854 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
5855 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
5856 This->hardwareCursor = cursor;
5857 HeapFree(GetProcessHeap(), 0, maskBits);
5861 This->xHotSpot = XHotSpot;
5862 This->yHotSpot = YHotSpot;
5866 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
5867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5868 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
5870 This->xScreenSpace = XScreenSpace;
5871 This->yScreenSpace = YScreenSpace;
5877 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
5878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5879 BOOL oldVisible = This->bCursorVisible;
5882 TRACE("(%p) : visible(%d)\n", This, bShow);
5885 * When ShowCursor is first called it should make the cursor appear at the OS's last
5886 * known cursor position. Because of this, some applications just repetitively call
5887 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
5890 This->xScreenSpace = pt.x;
5891 This->yScreenSpace = pt.y;
5893 if (This->haveHardwareCursor) {
5894 This->bCursorVisible = bShow;
5896 SetCursor(This->hardwareCursor);
5902 if (This->cursorTexture)
5903 This->bCursorVisible = bShow;
5909 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
5910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5911 TRACE("(%p) : state (%u)\n", This, This->state);
5912 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
5913 switch (This->state) {
5916 case WINED3DERR_DEVICELOST:
5918 ResourceList *resourceList = This->resources;
5919 while (NULL != resourceList) {
5920 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
5921 return WINED3DERR_DEVICENOTRESET;
5922 resourceList = resourceList->next;
5924 return WINED3DERR_DEVICELOST;
5926 case WINED3DERR_DRIVERINTERNALERROR:
5927 return WINED3DERR_DRIVERINTERNALERROR;
5931 return WINED3DERR_DRIVERINTERNALERROR;
5935 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
5936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5937 /** FIXME: Resource tracking needs to be done,
5938 * The closes we can do to this is set the priorities of all managed textures low
5939 * and then reset them.
5940 ***********************************************************/
5941 FIXME("(%p) : stub\n", This);
5945 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5946 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
5948 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
5949 if(surface->Flags & SFLAG_DIBSECTION) {
5950 /* Release the DC */
5951 SelectObject(surface->hDC, surface->dib.holdbitmap);
5952 DeleteDC(surface->hDC);
5953 /* Release the DIB section */
5954 DeleteObject(surface->dib.DIBsection);
5955 surface->dib.bitmap_data = NULL;
5956 surface->resource.allocatedMemory = NULL;
5957 surface->Flags &= ~SFLAG_DIBSECTION;
5959 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
5960 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
5961 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
5962 surface->pow2Width = pPresentationParameters->BackBufferWidth;
5963 surface->pow2Height = pPresentationParameters->BackBufferHeight;
5965 surface->pow2Width = surface->pow2Height = 1;
5966 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
5967 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
5969 if(surface->glDescription.textureName) {
5971 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5972 glDeleteTextures(1, &surface->glDescription.textureName);
5974 surface->glDescription.textureName = 0;
5975 surface->Flags &= ~SFLAG_CLIENT;
5977 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
5978 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
5979 surface->Flags |= SFLAG_NONPOW2;
5981 surface->Flags &= ~SFLAG_NONPOW2;
5983 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
5984 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
5987 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
5988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5989 IWineD3DSwapChainImpl *swapchain;
5991 BOOL DisplayModeChanged = FALSE;
5992 WINED3DDISPLAYMODE mode;
5993 TRACE("(%p)\n", This);
5995 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
5997 ERR("Failed to get the first implicit swapchain\n");
6001 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6002 * on an existing gl context, so there's no real need for recreation.
6004 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6006 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6008 TRACE("New params:\n");
6009 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6010 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6011 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6012 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6013 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6014 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6015 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6016 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6017 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6018 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6019 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6020 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6021 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6023 /* No special treatment of these parameters. Just store them */
6024 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6025 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6026 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6027 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6029 /* What to do about these? */
6030 if(pPresentationParameters->BackBufferCount != 0 &&
6031 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6032 ERR("Cannot change the back buffer count yet\n");
6034 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6035 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6036 ERR("Cannot change the back buffer format yet\n");
6038 if(pPresentationParameters->hDeviceWindow != NULL &&
6039 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6040 ERR("Cannot change the device window yet\n");
6042 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6043 ERR("What do do about a changed auto depth stencil parameter?\n");
6046 if(pPresentationParameters->Windowed) {
6047 mode.Width = swapchain->orig_width;
6048 mode.Height = swapchain->orig_height;
6049 mode.RefreshRate = 0;
6050 mode.Format = swapchain->presentParms.BackBufferFormat;
6052 mode.Width = pPresentationParameters->BackBufferWidth;
6053 mode.Height = pPresentationParameters->BackBufferHeight;
6054 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6055 mode.Format = swapchain->presentParms.BackBufferFormat;
6058 /* Should Width == 800 && Height == 0 set 800x600? */
6059 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6060 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6061 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6068 vp.Width = pPresentationParameters->BackBufferWidth;
6069 vp.Height = pPresentationParameters->BackBufferHeight;
6073 if(!pPresentationParameters->Windowed) {
6074 DisplayModeChanged = TRUE;
6076 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6077 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6079 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6080 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6081 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6084 /* Now set the new viewport */
6085 IWineD3DDevice_SetViewport(iface, &vp);
6088 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6089 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6090 DisplayModeChanged) {
6092 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6093 if(!pPresentationParameters->Windowed) {
6094 IWineD3DDevice_SetFullscreen(iface, TRUE);
6097 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6099 /* Switching out of fullscreen mode? First set the original res, then change the window */
6100 if(pPresentationParameters->Windowed) {
6101 IWineD3DDevice_SetFullscreen(iface, FALSE);
6103 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6106 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6110 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6112 /** FIXME: always true at the moment **/
6113 if(!bEnableDialogs) {
6114 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6120 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6122 TRACE("(%p) : pParameters %p\n", This, pParameters);
6124 *pParameters = This->createParms;
6128 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6129 IWineD3DSwapChain *swapchain;
6130 HRESULT hrc = WINED3D_OK;
6132 TRACE("Relaying to swapchain\n");
6134 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6135 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6136 IWineD3DSwapChain_Release(swapchain);
6141 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6142 IWineD3DSwapChain *swapchain;
6143 HRESULT hrc = WINED3D_OK;
6145 TRACE("Relaying to swapchain\n");
6147 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6148 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6149 IWineD3DSwapChain_Release(swapchain);
6155 /** ********************************************************
6156 * Notification functions
6157 ** ********************************************************/
6158 /** This function must be called in the release of a resource when ref == 0,
6159 * the contents of resource must still be correct,
6160 * any handels to other resource held by the caller must be closed
6161 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6162 *****************************************************/
6163 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6165 ResourceList* resourceList;
6167 TRACE("(%p) : resource %p\n", This, resource);
6168 /* add a new texture to the frot of the linked list */
6169 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6170 resourceList->resource = resource;
6172 /* Get the old head */
6173 resourceList->next = This->resources;
6175 This->resources = resourceList;
6176 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6181 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6183 ResourceList* resourceList = NULL;
6184 ResourceList* previousResourceList = NULL;
6186 TRACE("(%p) : resource %p\n", This, resource);
6188 resourceList = This->resources;
6190 while (resourceList != NULL) {
6191 if(resourceList->resource == resource) break;
6192 previousResourceList = resourceList;
6193 resourceList = resourceList->next;
6196 if (resourceList == NULL) {
6197 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6200 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6202 /* make sure we don't leave a hole in the list */
6203 if (previousResourceList != NULL) {
6204 previousResourceList->next = resourceList->next;
6206 This->resources = resourceList->next;
6213 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6214 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6217 TRACE("(%p) : resource %p\n", This, resource);
6218 switch(IWineD3DResource_GetType(resource)){
6219 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6220 case WINED3DRTYPE_SURFACE: {
6223 /* Cleanup any FBO attachments */
6224 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6225 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6226 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6227 set_render_target_fbo(iface, i, NULL);
6228 This->fbo_color_attachments[i] = NULL;
6231 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6232 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6233 set_depth_stencil_fbo(iface, NULL);
6234 This->fbo_depth_attachment = NULL;
6240 case WINED3DRTYPE_TEXTURE:
6241 case WINED3DRTYPE_CUBETEXTURE:
6242 case WINED3DRTYPE_VOLUMETEXTURE:
6243 for (counter = 0; counter < GL_LIMITS(sampler_stages); counter++) {
6244 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6245 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6246 This->stateBlock->textures[counter] = NULL;
6248 if (This->updateStateBlock != This->stateBlock ){
6249 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6250 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6251 This->updateStateBlock->textures[counter] = NULL;
6256 case WINED3DRTYPE_VOLUME:
6257 /* TODO: nothing really? */
6259 case WINED3DRTYPE_VERTEXBUFFER:
6260 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6263 TRACE("Cleaning up stream pointers\n");
6265 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6266 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6267 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6269 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6270 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6271 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6272 This->updateStateBlock->streamSource[streamNumber] = 0;
6273 /* Set changed flag? */
6276 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) */
6277 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6278 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6279 This->stateBlock->streamSource[streamNumber] = 0;
6282 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6283 else { /* This shouldn't happen */
6284 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6291 case WINED3DRTYPE_INDEXBUFFER:
6292 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6293 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6294 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6295 This->updateStateBlock->pIndexData = NULL;
6298 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6299 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6300 This->stateBlock->pIndexData = NULL;
6306 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6311 /* Remove the resoruce from the resourceStore */
6312 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6314 TRACE("Resource released\n");
6318 /**********************************************************
6319 * IWineD3DDevice VTbl follows
6320 **********************************************************/
6322 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6324 /*** IUnknown methods ***/
6325 IWineD3DDeviceImpl_QueryInterface,
6326 IWineD3DDeviceImpl_AddRef,
6327 IWineD3DDeviceImpl_Release,
6328 /*** IWineD3DDevice methods ***/
6329 IWineD3DDeviceImpl_GetParent,
6330 /*** Creation methods**/
6331 IWineD3DDeviceImpl_CreateVertexBuffer,
6332 IWineD3DDeviceImpl_CreateIndexBuffer,
6333 IWineD3DDeviceImpl_CreateStateBlock,
6334 IWineD3DDeviceImpl_CreateSurface,
6335 IWineD3DDeviceImpl_CreateTexture,
6336 IWineD3DDeviceImpl_CreateVolumeTexture,
6337 IWineD3DDeviceImpl_CreateVolume,
6338 IWineD3DDeviceImpl_CreateCubeTexture,
6339 IWineD3DDeviceImpl_CreateQuery,
6340 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6341 IWineD3DDeviceImpl_CreateVertexDeclaration,
6342 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6343 IWineD3DDeviceImpl_CreateVertexShader,
6344 IWineD3DDeviceImpl_CreatePixelShader,
6345 IWineD3DDeviceImpl_CreatePalette,
6346 /*** Odd functions **/
6347 IWineD3DDeviceImpl_Init3D,
6348 IWineD3DDeviceImpl_Uninit3D,
6349 IWineD3DDeviceImpl_SetFullscreen,
6350 IWineD3DDeviceImpl_SetMultithreaded,
6351 IWineD3DDeviceImpl_EvictManagedResources,
6352 IWineD3DDeviceImpl_GetAvailableTextureMem,
6353 IWineD3DDeviceImpl_GetBackBuffer,
6354 IWineD3DDeviceImpl_GetCreationParameters,
6355 IWineD3DDeviceImpl_GetDeviceCaps,
6356 IWineD3DDeviceImpl_GetDirect3D,
6357 IWineD3DDeviceImpl_GetDisplayMode,
6358 IWineD3DDeviceImpl_SetDisplayMode,
6359 IWineD3DDeviceImpl_GetHWND,
6360 IWineD3DDeviceImpl_SetHWND,
6361 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6362 IWineD3DDeviceImpl_GetRasterStatus,
6363 IWineD3DDeviceImpl_GetSwapChain,
6364 IWineD3DDeviceImpl_Reset,
6365 IWineD3DDeviceImpl_SetDialogBoxMode,
6366 IWineD3DDeviceImpl_SetCursorProperties,
6367 IWineD3DDeviceImpl_SetCursorPosition,
6368 IWineD3DDeviceImpl_ShowCursor,
6369 IWineD3DDeviceImpl_TestCooperativeLevel,
6370 /*** Getters and setters **/
6371 IWineD3DDeviceImpl_SetClipPlane,
6372 IWineD3DDeviceImpl_GetClipPlane,
6373 IWineD3DDeviceImpl_SetClipStatus,
6374 IWineD3DDeviceImpl_GetClipStatus,
6375 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6376 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6377 IWineD3DDeviceImpl_SetDepthStencilSurface,
6378 IWineD3DDeviceImpl_GetDepthStencilSurface,
6379 IWineD3DDeviceImpl_SetFVF,
6380 IWineD3DDeviceImpl_GetFVF,
6381 IWineD3DDeviceImpl_SetGammaRamp,
6382 IWineD3DDeviceImpl_GetGammaRamp,
6383 IWineD3DDeviceImpl_SetIndices,
6384 IWineD3DDeviceImpl_GetIndices,
6385 IWineD3DDeviceImpl_SetBaseVertexIndex,
6386 IWineD3DDeviceImpl_GetBaseVertexIndex,
6387 IWineD3DDeviceImpl_SetLight,
6388 IWineD3DDeviceImpl_GetLight,
6389 IWineD3DDeviceImpl_SetLightEnable,
6390 IWineD3DDeviceImpl_GetLightEnable,
6391 IWineD3DDeviceImpl_SetMaterial,
6392 IWineD3DDeviceImpl_GetMaterial,
6393 IWineD3DDeviceImpl_SetNPatchMode,
6394 IWineD3DDeviceImpl_GetNPatchMode,
6395 IWineD3DDeviceImpl_SetPaletteEntries,
6396 IWineD3DDeviceImpl_GetPaletteEntries,
6397 IWineD3DDeviceImpl_SetPixelShader,
6398 IWineD3DDeviceImpl_GetPixelShader,
6399 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6400 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6401 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6402 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6403 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6404 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6405 IWineD3DDeviceImpl_SetRenderState,
6406 IWineD3DDeviceImpl_GetRenderState,
6407 IWineD3DDeviceImpl_SetRenderTarget,
6408 IWineD3DDeviceImpl_GetRenderTarget,
6409 IWineD3DDeviceImpl_SetFrontBackBuffers,
6410 IWineD3DDeviceImpl_SetSamplerState,
6411 IWineD3DDeviceImpl_GetSamplerState,
6412 IWineD3DDeviceImpl_SetScissorRect,
6413 IWineD3DDeviceImpl_GetScissorRect,
6414 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6415 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6416 IWineD3DDeviceImpl_SetStreamSource,
6417 IWineD3DDeviceImpl_GetStreamSource,
6418 IWineD3DDeviceImpl_SetStreamSourceFreq,
6419 IWineD3DDeviceImpl_GetStreamSourceFreq,
6420 IWineD3DDeviceImpl_SetTexture,
6421 IWineD3DDeviceImpl_GetTexture,
6422 IWineD3DDeviceImpl_SetTextureStageState,
6423 IWineD3DDeviceImpl_GetTextureStageState,
6424 IWineD3DDeviceImpl_SetTransform,
6425 IWineD3DDeviceImpl_GetTransform,
6426 IWineD3DDeviceImpl_SetVertexDeclaration,
6427 IWineD3DDeviceImpl_GetVertexDeclaration,
6428 IWineD3DDeviceImpl_SetVertexShader,
6429 IWineD3DDeviceImpl_GetVertexShader,
6430 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6431 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6432 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6433 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6434 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6435 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6436 IWineD3DDeviceImpl_SetViewport,
6437 IWineD3DDeviceImpl_GetViewport,
6438 IWineD3DDeviceImpl_MultiplyTransform,
6439 IWineD3DDeviceImpl_ValidateDevice,
6440 IWineD3DDeviceImpl_ProcessVertices,
6441 /*** State block ***/
6442 IWineD3DDeviceImpl_BeginStateBlock,
6443 IWineD3DDeviceImpl_EndStateBlock,
6444 /*** Scene management ***/
6445 IWineD3DDeviceImpl_BeginScene,
6446 IWineD3DDeviceImpl_EndScene,
6447 IWineD3DDeviceImpl_Present,
6448 IWineD3DDeviceImpl_Clear,
6450 IWineD3DDeviceImpl_DrawPrimitive,
6451 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6452 IWineD3DDeviceImpl_DrawPrimitiveUP,
6453 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6454 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6455 IWineD3DDeviceImpl_DrawRectPatch,
6456 IWineD3DDeviceImpl_DrawTriPatch,
6457 IWineD3DDeviceImpl_DeletePatch,
6458 IWineD3DDeviceImpl_ColorFill,
6459 IWineD3DDeviceImpl_UpdateTexture,
6460 IWineD3DDeviceImpl_UpdateSurface,
6461 IWineD3DDeviceImpl_GetFrontBufferData,
6462 /*** object tracking ***/
6463 IWineD3DDeviceImpl_ResourceReleased
6467 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6468 WINED3DRS_ALPHABLENDENABLE ,
6469 WINED3DRS_ALPHAFUNC ,
6470 WINED3DRS_ALPHAREF ,
6471 WINED3DRS_ALPHATESTENABLE ,
6473 WINED3DRS_COLORWRITEENABLE ,
6474 WINED3DRS_DESTBLEND ,
6475 WINED3DRS_DITHERENABLE ,
6476 WINED3DRS_FILLMODE ,
6477 WINED3DRS_FOGDENSITY ,
6479 WINED3DRS_FOGSTART ,
6480 WINED3DRS_LASTPIXEL ,
6481 WINED3DRS_SHADEMODE ,
6482 WINED3DRS_SRCBLEND ,
6483 WINED3DRS_STENCILENABLE ,
6484 WINED3DRS_STENCILFAIL ,
6485 WINED3DRS_STENCILFUNC ,
6486 WINED3DRS_STENCILMASK ,
6487 WINED3DRS_STENCILPASS ,
6488 WINED3DRS_STENCILREF ,
6489 WINED3DRS_STENCILWRITEMASK ,
6490 WINED3DRS_STENCILZFAIL ,
6491 WINED3DRS_TEXTUREFACTOR ,
6502 WINED3DRS_ZWRITEENABLE
6505 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6506 WINED3DTSS_ADDRESSW ,
6507 WINED3DTSS_ALPHAARG0 ,
6508 WINED3DTSS_ALPHAARG1 ,
6509 WINED3DTSS_ALPHAARG2 ,
6510 WINED3DTSS_ALPHAOP ,
6511 WINED3DTSS_BUMPENVLOFFSET ,
6512 WINED3DTSS_BUMPENVLSCALE ,
6513 WINED3DTSS_BUMPENVMAT00 ,
6514 WINED3DTSS_BUMPENVMAT01 ,
6515 WINED3DTSS_BUMPENVMAT10 ,
6516 WINED3DTSS_BUMPENVMAT11 ,
6517 WINED3DTSS_COLORARG0 ,
6518 WINED3DTSS_COLORARG1 ,
6519 WINED3DTSS_COLORARG2 ,
6520 WINED3DTSS_COLOROP ,
6521 WINED3DTSS_RESULTARG ,
6522 WINED3DTSS_TEXCOORDINDEX ,
6523 WINED3DTSS_TEXTURETRANSFORMFLAGS
6526 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6527 WINED3DSAMP_ADDRESSU ,
6528 WINED3DSAMP_ADDRESSV ,
6529 WINED3DSAMP_ADDRESSW ,
6530 WINED3DSAMP_BORDERCOLOR ,
6531 WINED3DSAMP_MAGFILTER ,
6532 WINED3DSAMP_MINFILTER ,
6533 WINED3DSAMP_MIPFILTER ,
6534 WINED3DSAMP_MIPMAPLODBIAS ,
6535 WINED3DSAMP_MAXMIPLEVEL ,
6536 WINED3DSAMP_MAXANISOTROPY ,
6537 WINED3DSAMP_SRGBTEXTURE ,
6538 WINED3DSAMP_ELEMENTINDEX
6541 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6543 WINED3DRS_AMBIENTMATERIALSOURCE ,
6544 WINED3DRS_CLIPPING ,
6545 WINED3DRS_CLIPPLANEENABLE ,
6546 WINED3DRS_COLORVERTEX ,
6547 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6548 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6549 WINED3DRS_FOGDENSITY ,
6551 WINED3DRS_FOGSTART ,
6552 WINED3DRS_FOGTABLEMODE ,
6553 WINED3DRS_FOGVERTEXMODE ,
6554 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6555 WINED3DRS_LIGHTING ,
6556 WINED3DRS_LOCALVIEWER ,
6557 WINED3DRS_MULTISAMPLEANTIALIAS ,
6558 WINED3DRS_MULTISAMPLEMASK ,
6559 WINED3DRS_NORMALIZENORMALS ,
6560 WINED3DRS_PATCHEDGESTYLE ,
6561 WINED3DRS_POINTSCALE_A ,
6562 WINED3DRS_POINTSCALE_B ,
6563 WINED3DRS_POINTSCALE_C ,
6564 WINED3DRS_POINTSCALEENABLE ,
6565 WINED3DRS_POINTSIZE ,
6566 WINED3DRS_POINTSIZE_MAX ,
6567 WINED3DRS_POINTSIZE_MIN ,
6568 WINED3DRS_POINTSPRITEENABLE ,
6569 WINED3DRS_RANGEFOGENABLE ,
6570 WINED3DRS_SPECULARMATERIALSOURCE ,
6571 WINED3DRS_TWEENFACTOR ,
6572 WINED3DRS_VERTEXBLEND
6575 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6576 WINED3DTSS_TEXCOORDINDEX ,
6577 WINED3DTSS_TEXTURETRANSFORMFLAGS
6580 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6581 WINED3DSAMP_DMAPOFFSET
6584 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6585 DWORD rep = StateTable[state].representative;
6589 WineD3DContext *context;
6592 for(i = 0; i < This->numContexts; i++) {
6593 context = This->contexts[i];
6594 if(isStateDirty(context, rep)) continue;
6596 context->dirtyArray[context->numDirtyEntries++] = rep;
6599 context->isStateDirty[idx] |= (1 << shift);