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-2007 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 This->adapter->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 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
262 case WINED3DUSAGE_WRITEONLY:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
474 } else if (Type == WINED3DSBT_PIXELSTATE) {
476 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
477 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
479 object->changed.pixelShader = TRUE;
481 /* Pixel Shader Constants */
482 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
483 object->changed.pixelShaderConstantsF[i] = TRUE;
484 for (i = 0; i < MAX_CONST_B; ++i)
485 object->changed.pixelShaderConstantsB[i] = TRUE;
486 for (i = 0; i < MAX_CONST_I; ++i)
487 object->changed.pixelShaderConstantsI[i] = TRUE;
489 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
490 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
491 object->contained_render_states[i] = SavedPixelStates_R[i];
493 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
494 for (j = 0; j < MAX_TEXTURES; j++) {
495 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
496 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
499 for (j = 0 ; j < 16; j++) {
500 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
502 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
506 } else if (Type == WINED3DSBT_VERTEXSTATE) {
508 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
509 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
511 object->changed.vertexShader = TRUE;
513 /* Vertex Shader Constants */
514 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i)
515 object->changed.vertexShaderConstantsF[i] = TRUE;
516 for (i = 0; i < MAX_CONST_B; ++i)
517 object->changed.vertexShaderConstantsB[i] = TRUE;
518 for (i = 0; i < MAX_CONST_I; ++i)
519 object->changed.vertexShaderConstantsI[i] = TRUE;
521 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
522 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
523 object->contained_render_states[i] = SavedVertexStates_R[i];
525 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
526 for (j = 0; j < MAX_TEXTURES; j++) {
527 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
528 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
531 for (j = 0 ; j < 16; j++){
532 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
533 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
537 for(j = 0; j < LIGHTMAP_SIZE; j++) {
539 LIST_FOR_EACH(e, &object->lightMap[j]) {
540 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
541 light->changed = TRUE;
542 light->enabledChanged = TRUE;
546 FIXME("Unrecognized state block type %d\n", Type);
549 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
553 /* ************************************
555 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
558 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
560 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.
562 ******************************** */
564 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) {
565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
566 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
567 unsigned int Size = 1;
568 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
569 TRACE("(%p) Create surface\n",This);
571 /** FIXME: Check ranges on the inputs are valid
574 * [in] Quality level. The valid range is between zero and one less than the level
575 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
576 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
577 * values of paired render targets, depth stencil surfaces, and the MultiSample type
579 *******************************/
584 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
586 * If this flag is set, the contents of the depth stencil buffer will be
587 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
588 * with a different depth surface.
590 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
591 ***************************/
593 if(MultisampleQuality < 0) {
594 FIXME("Invalid multisample level %d\n", MultisampleQuality);
595 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
598 if(MultisampleQuality > 0) {
599 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
600 MultisampleQuality=0;
603 /** FIXME: Check that the format is supported
605 *******************************/
607 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
608 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
610 *********************************/
611 if (WINED3DFMT_UNKNOWN == Format) {
613 } else if (Format == WINED3DFMT_DXT1) {
614 /* DXT1 is half byte per pixel */
615 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
617 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
618 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
619 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
621 /* The pitch is a multiple of 4 bytes */
622 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
626 /** Create and initialise the surface resource **/
627 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
628 /* "Standalone" surface */
629 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
631 object->currentDesc.Width = Width;
632 object->currentDesc.Height = Height;
633 object->currentDesc.MultiSampleType = MultiSample;
634 object->currentDesc.MultiSampleQuality = MultisampleQuality;
635 object->glDescription.level = Level;
639 object->Flags |= Discard ? SFLAG_DISCARD : 0;
640 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
641 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
644 if (WINED3DFMT_UNKNOWN != Format) {
645 object->bytesPerPixel = tableEntry->bpp;
647 object->bytesPerPixel = 0;
650 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
652 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
654 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
655 * this function is too deep to need to care about things like this.
656 * Levels need to be checked too, and possibly Type since they all affect what can be done.
657 * ****************************************/
659 case WINED3DPOOL_SCRATCH:
661 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
662 "which are mutually exclusive, setting lockable to TRUE\n");
665 case WINED3DPOOL_SYSTEMMEM:
666 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
667 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
668 case WINED3DPOOL_MANAGED:
669 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
670 "Usage of DYNAMIC which are mutually exclusive, not doing "
671 "anything just telling you.\n");
673 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
674 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
675 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
676 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
679 FIXME("(%p) Unknown pool %d\n", This, Pool);
683 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
684 FIXME("Trying to create a render target that isn't in the default pool\n");
687 /* mark the texture as dirty so that it gets loaded first time around*/
688 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
689 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
690 This, Width, Height, Format, debug_d3dformat(Format),
691 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
693 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
694 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
695 This->ddraw_primary = (IWineD3DSurface *) object;
697 /* Look at the implementation and set the correct Vtable */
700 /* Check if a 3D adapter is available when creating gl surfaces */
702 ERR("OpenGL surfaces are not available without opengl\n");
703 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
704 HeapFree(GetProcessHeap(), 0, object);
705 return WINED3DERR_NOTAVAILABLE;
710 object->lpVtbl = &IWineGDISurface_Vtbl;
714 /* To be sure to catch this */
715 ERR("Unknown requested surface implementation %d!\n", Impl);
716 IWineD3DSurface_Release((IWineD3DSurface *) object);
717 return WINED3DERR_INVALIDCALL;
720 list_init(&object->renderbuffers);
722 /* Call the private setup routine */
723 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
727 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
728 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
729 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
730 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
733 IWineD3DTextureImpl *object;
738 unsigned int pow2Width;
739 unsigned int pow2Height;
742 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
743 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
744 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
746 /* TODO: It should only be possible to create textures for formats
747 that are reported as supported */
748 if (WINED3DFMT_UNKNOWN >= Format) {
749 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
750 return WINED3DERR_INVALIDCALL;
753 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
754 D3DINITIALIZEBASETEXTURE(object->baseTexture);
755 object->width = Width;
756 object->height = Height;
758 /** Non-power2 support **/
759 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
763 /* Find the nearest pow2 match */
764 pow2Width = pow2Height = 1;
765 while (pow2Width < Width) pow2Width <<= 1;
766 while (pow2Height < Height) pow2Height <<= 1;
769 /** FIXME: add support for real non-power-two if it's provided by the video card **/
770 /* Precalculated scaling for 'faked' non power of two texture coords */
771 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
772 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
773 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
775 /* Calculate levels for mip mapping */
777 TRACE("calculating levels %d\n", object->baseTexture.levels);
778 object->baseTexture.levels++;
781 while (tmpW > 1 || tmpH > 1) {
782 tmpW = max(1, tmpW >> 1);
783 tmpH = max(1, tmpH >> 1);
784 object->baseTexture.levels++;
786 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
789 /* Generate all the surfaces */
792 for (i = 0; i < object->baseTexture.levels; i++)
794 /* use the callback to create the texture surface */
795 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
796 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
797 FIXME("Failed to create surface %p\n", object);
799 object->surfaces[i] = NULL;
800 IWineD3DTexture_Release((IWineD3DTexture *)object);
806 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
807 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
808 /* calculate the next mipmap level */
809 tmpW = max(1, tmpW >> 1);
810 tmpH = max(1, tmpH >> 1);
813 TRACE("(%p) : Created texture %p\n", This, object);
817 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
818 UINT Width, UINT Height, UINT Depth,
819 UINT Levels, DWORD Usage,
820 WINED3DFORMAT Format, WINED3DPOOL Pool,
821 IWineD3DVolumeTexture **ppVolumeTexture,
822 HANDLE *pSharedHandle, IUnknown *parent,
823 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
826 IWineD3DVolumeTextureImpl *object;
832 /* TODO: It should only be possible to create textures for formats
833 that are reported as supported */
834 if (WINED3DFMT_UNKNOWN >= Format) {
835 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
836 return WINED3DERR_INVALIDCALL;
839 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
840 D3DINITIALIZEBASETEXTURE(object->baseTexture);
842 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
843 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
845 object->width = Width;
846 object->height = Height;
847 object->depth = Depth;
849 /* Calculate levels for mip mapping */
851 object->baseTexture.levels++;
855 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
856 tmpW = max(1, tmpW >> 1);
857 tmpH = max(1, tmpH >> 1);
858 tmpD = max(1, tmpD >> 1);
859 object->baseTexture.levels++;
861 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
864 /* Generate all the surfaces */
869 for (i = 0; i < object->baseTexture.levels; i++)
872 /* Create the volume */
873 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
874 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
877 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
878 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
879 *ppVolumeTexture = NULL;
883 /* Set its container to this object */
884 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
886 /* calcualte the next mipmap level */
887 tmpW = max(1, tmpW >> 1);
888 tmpH = max(1, tmpH >> 1);
889 tmpD = max(1, tmpD >> 1);
892 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
893 TRACE("(%p) : Created volume texture %p\n", This, object);
897 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
898 UINT Width, UINT Height, UINT Depth,
900 WINED3DFORMAT Format, WINED3DPOOL Pool,
901 IWineD3DVolume** ppVolume,
902 HANDLE* pSharedHandle, IUnknown *parent) {
904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
905 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
906 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
908 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
910 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
911 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
913 object->currentDesc.Width = Width;
914 object->currentDesc.Height = Height;
915 object->currentDesc.Depth = Depth;
916 object->bytesPerPixel = formatDesc->bpp;
918 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
919 object->lockable = TRUE;
920 object->locked = FALSE;
921 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
922 object->dirty = TRUE;
924 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
927 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
928 UINT Levels, DWORD Usage,
929 WINED3DFORMAT Format, WINED3DPOOL Pool,
930 IWineD3DCubeTexture **ppCubeTexture,
931 HANDLE *pSharedHandle, IUnknown *parent,
932 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
935 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
939 unsigned int pow2EdgeLength = EdgeLength;
941 /* TODO: It should only be possible to create textures for formats
942 that are reported as supported */
943 if (WINED3DFMT_UNKNOWN >= Format) {
944 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
945 return WINED3DERR_INVALIDCALL;
948 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
949 WARN("(%p) : Tried to create not supported cube texture\n", This);
950 return WINED3DERR_INVALIDCALL;
953 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
954 D3DINITIALIZEBASETEXTURE(object->baseTexture);
956 TRACE("(%p) Create Cube Texture\n", This);
958 /** Non-power2 support **/
960 /* Find the nearest pow2 match */
962 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
964 object->edgeLength = EdgeLength;
965 /* TODO: support for native non-power 2 */
966 /* Precalculated scaling for 'faked' non power of two texture coords */
967 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
969 /* Calculate levels for mip mapping */
971 object->baseTexture.levels++;
974 tmpW = max(1, tmpW >> 1);
975 object->baseTexture.levels++;
977 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
980 /* Generate all the surfaces */
982 for (i = 0; i < object->baseTexture.levels; i++) {
984 /* Create the 6 faces */
985 for (j = 0; j < 6; j++) {
987 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
988 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
990 if(hr!= WINED3D_OK) {
994 for (l = 0; l < j; l++) {
995 IWineD3DSurface_Release(object->surfaces[j][i]);
997 for (k = 0; k < i; k++) {
998 for (l = 0; l < 6; l++) {
999 IWineD3DSurface_Release(object->surfaces[l][j]);
1003 FIXME("(%p) Failed to create surface\n",object);
1004 HeapFree(GetProcessHeap(),0,object);
1005 *ppCubeTexture = NULL;
1008 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1009 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1011 tmpW = max(1, tmpW >> 1);
1014 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1015 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1019 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1021 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1022 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1024 /* Just a check to see if we support this type of query */
1026 case WINED3DQUERYTYPE_OCCLUSION:
1027 TRACE("(%p) occlusion query\n", This);
1028 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1031 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1034 case WINED3DQUERYTYPE_EVENT:
1035 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1036 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1037 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1039 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1044 case WINED3DQUERYTYPE_VCACHE:
1045 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1046 case WINED3DQUERYTYPE_VERTEXSTATS:
1047 case WINED3DQUERYTYPE_TIMESTAMP:
1048 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1049 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1050 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1051 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1052 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1053 case WINED3DQUERYTYPE_PIXELTIMINGS:
1054 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1055 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1057 FIXME("(%p) Unhandled query type %d\n", This, Type);
1059 if(NULL == ppQuery || hr != WINED3D_OK) {
1063 D3DCREATEOBJECTINSTANCE(object, Query)
1064 object->type = Type;
1065 /* allocated the 'extended' data based on the type of query requested */
1067 case WINED3DQUERYTYPE_OCCLUSION:
1068 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1069 TRACE("(%p) Allocating data for an occlusion query\n", This);
1070 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1071 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1074 case WINED3DQUERYTYPE_EVENT:
1075 /* TODO: GL_APPLE_fence */
1076 if(GL_SUPPORT(APPLE_FENCE)) {
1077 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1078 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1079 checkGLcall("glGenFencesAPPLE");
1080 } else if(GL_SUPPORT(NV_FENCE)) {
1081 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1082 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1083 checkGLcall("glGenFencesNV");
1087 case WINED3DQUERYTYPE_VCACHE:
1088 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1089 case WINED3DQUERYTYPE_VERTEXSTATS:
1090 case WINED3DQUERYTYPE_TIMESTAMP:
1091 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1092 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1093 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1094 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1095 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1096 case WINED3DQUERYTYPE_PIXELTIMINGS:
1097 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1098 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1100 object->extendedData = 0;
1101 FIXME("(%p) Unhandled query type %d\n",This , Type);
1103 TRACE("(%p) : Created Query %p\n", This, object);
1107 /*****************************************************************************
1108 * IWineD3DDeviceImpl_SetupFullscreenWindow
1110 * Helper function that modifies a HWND's Style and ExStyle for proper
1114 * iface: Pointer to the IWineD3DDevice interface
1115 * window: Window to setup
1117 *****************************************************************************/
1118 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1121 LONG style, exStyle;
1122 /* Don't do anything if an original style is stored.
1123 * That shouldn't happen
1125 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1126 if (This->style || This->exStyle) {
1127 ERR("(%p): Want to change the window parameters of HWND %p, but "
1128 "another style is stored for restoration afterwards\n", This, window);
1131 /* Get the parameters and save them */
1132 style = GetWindowLongW(window, GWL_STYLE);
1133 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1134 This->style = style;
1135 This->exStyle = exStyle;
1137 /* Filter out window decorations */
1138 style &= ~WS_CAPTION;
1139 style &= ~WS_THICKFRAME;
1140 exStyle &= ~WS_EX_WINDOWEDGE;
1141 exStyle &= ~WS_EX_CLIENTEDGE;
1143 /* Make sure the window is managed, otherwise we won't get keyboard input */
1144 style |= WS_POPUP | WS_SYSMENU;
1146 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1147 This->style, This->exStyle, style, exStyle);
1149 SetWindowLongW(window, GWL_STYLE, style);
1150 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1152 /* Inform the window about the update. */
1153 SetWindowPos(window, HWND_TOP, 0, 0,
1154 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1155 ShowWindow(window, SW_NORMAL);
1158 /*****************************************************************************
1159 * IWineD3DDeviceImpl_RestoreWindow
1161 * Helper function that restores a windows' properties when taking it out
1162 * of fullscreen mode
1165 * iface: Pointer to the IWineD3DDevice interface
1166 * window: Window to setup
1168 *****************************************************************************/
1169 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1172 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1173 * switch, do nothing
1175 if (!This->style && !This->exStyle) return;
1177 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1178 This, window, This->style, This->exStyle);
1180 SetWindowLongW(window, GWL_STYLE, This->style);
1181 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1183 /* Delete the old values */
1187 /* Inform the window about the update */
1188 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1189 0, 0, 0, 0, /* Pos, Size, ignored */
1190 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1193 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1194 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1196 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1197 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1201 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1202 HRESULT hr = WINED3D_OK;
1203 IUnknown *bufferParent;
1205 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1207 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1208 * does a device hold a reference to a swap chain giving them a lifetime of the device
1209 * or does the swap chain notify the device of its destruction.
1210 *******************************/
1212 /* Check the params */
1213 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1214 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1215 return WINED3DERR_INVALIDCALL;
1216 } else if (pPresentationParameters->BackBufferCount > 1) {
1217 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");
1220 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1222 /*********************
1223 * Lookup the window Handle and the relating X window handle
1224 ********************/
1226 /* Setup hwnd we are using, plus which display this equates to */
1227 object->win_handle = pPresentationParameters->hDeviceWindow;
1228 if (!object->win_handle) {
1229 object->win_handle = This->createParms.hFocusWindow;
1232 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1233 hDc = GetDC(object->win_handle);
1234 TRACE("Using hDc %p\n", hDc);
1237 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1238 return WINED3DERR_NOTAVAILABLE;
1241 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1242 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1243 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1244 ReleaseDC(object->win_handle, hDc);
1246 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1247 * then the corresponding dimension of the client area of the hDeviceWindow
1248 * (or the focus window, if hDeviceWindow is NULL) is taken.
1249 **********************/
1251 if (pPresentationParameters->Windowed &&
1252 ((pPresentationParameters->BackBufferWidth == 0) ||
1253 (pPresentationParameters->BackBufferHeight == 0))) {
1256 GetClientRect(object->win_handle, &Rect);
1258 if (pPresentationParameters->BackBufferWidth == 0) {
1259 pPresentationParameters->BackBufferWidth = Rect.right;
1260 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1262 if (pPresentationParameters->BackBufferHeight == 0) {
1263 pPresentationParameters->BackBufferHeight = Rect.bottom;
1264 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1268 /* Put the correct figures in the presentation parameters */
1269 TRACE("Copying across presentation parameters\n");
1270 object->presentParms = *pPresentationParameters;
1272 TRACE("calling rendertarget CB\n");
1273 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1275 object->presentParms.BackBufferWidth,
1276 object->presentParms.BackBufferHeight,
1277 object->presentParms.BackBufferFormat,
1278 object->presentParms.MultiSampleType,
1279 object->presentParms.MultiSampleQuality,
1280 TRUE /* Lockable */,
1281 &object->frontBuffer,
1282 NULL /* pShared (always null)*/);
1283 if (object->frontBuffer != NULL) {
1284 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1286 ERR("Failed to create the front buffer\n");
1291 * Create an opengl context for the display visual
1292 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1293 * use different properties after that point in time. FIXME: How to handle when requested format
1294 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1295 * it chooses is identical to the one already being used!
1296 **********************************/
1297 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1299 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1300 if(!object->context)
1301 return E_OUTOFMEMORY;
1302 object->num_contexts = 1;
1305 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1308 if (!object->context[0]) {
1309 ERR("Failed to create a new context\n");
1310 hr = WINED3DERR_NOTAVAILABLE;
1313 TRACE("Context created (HWND=%p, glContext=%p)\n",
1314 object->win_handle, object->context[0]->glCtx);
1317 /*********************
1318 * Windowed / Fullscreen
1319 *******************/
1322 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1323 * so we should really check to see if there is a fullscreen swapchain already
1324 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1325 **************************************/
1327 if (!pPresentationParameters->Windowed) {
1334 /* Get info on the current display setup */
1336 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1339 /* Change the display settings */
1340 memset(&devmode, 0, sizeof(devmode));
1341 devmode.dmSize = sizeof(devmode);
1342 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1343 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1344 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1345 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1346 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1348 /* For GetDisplayMode */
1349 This->ddraw_width = devmode.dmPelsWidth;
1350 This->ddraw_height = devmode.dmPelsHeight;
1351 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1353 IWineD3DDevice_SetFullscreen(iface, TRUE);
1355 /* And finally clip mouse to our screen */
1356 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1357 ClipCursor(&clip_rc);
1360 /*********************
1361 * Create the back, front and stencil buffers
1362 *******************/
1363 if(object->presentParms.BackBufferCount > 0) {
1366 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1367 if(!object->backBuffer) {
1368 ERR("Out of memory\n");
1373 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1374 TRACE("calling rendertarget CB\n");
1375 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1377 object->presentParms.BackBufferWidth,
1378 object->presentParms.BackBufferHeight,
1379 object->presentParms.BackBufferFormat,
1380 object->presentParms.MultiSampleType,
1381 object->presentParms.MultiSampleQuality,
1382 TRUE /* Lockable */,
1383 &object->backBuffer[i],
1384 NULL /* pShared (always null)*/);
1385 if(hr == WINED3D_OK && object->backBuffer[i]) {
1386 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1388 ERR("Cannot create new back buffer\n");
1392 glDrawBuffer(GL_BACK);
1393 checkGLcall("glDrawBuffer(GL_BACK)");
1397 object->backBuffer = NULL;
1399 /* Single buffering - draw to front buffer */
1401 glDrawBuffer(GL_FRONT);
1402 checkGLcall("glDrawBuffer(GL_FRONT)");
1406 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1407 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1408 TRACE("Creating depth stencil buffer\n");
1409 if (This->depthStencilBuffer == NULL ) {
1410 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1412 object->presentParms.BackBufferWidth,
1413 object->presentParms.BackBufferHeight,
1414 object->presentParms.AutoDepthStencilFormat,
1415 object->presentParms.MultiSampleType,
1416 object->presentParms.MultiSampleQuality,
1417 FALSE /* FIXME: Discard */,
1418 &This->depthStencilBuffer,
1419 NULL /* pShared (always null)*/ );
1420 if (This->depthStencilBuffer != NULL)
1421 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1424 /** TODO: A check on width, height and multisample types
1425 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1426 ****************************/
1427 object->wantsDepthStencilBuffer = TRUE;
1429 object->wantsDepthStencilBuffer = FALSE;
1432 TRACE("Created swapchain %p\n", object);
1433 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1437 if (object->backBuffer) {
1439 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1440 if(object->backBuffer[i]) {
1441 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1442 IUnknown_Release(bufferParent); /* once for the get parent */
1443 if (IUnknown_Release(bufferParent) > 0) {
1444 FIXME("(%p) Something's still holding the back buffer\n",This);
1448 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1449 object->backBuffer = NULL;
1451 if(object->context[0])
1452 DestroyContext(This, object->context[0]);
1453 if(object->frontBuffer) {
1454 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1455 IUnknown_Release(bufferParent); /* once for the get parent */
1456 if (IUnknown_Release(bufferParent) > 0) {
1457 FIXME("(%p) Something's still holding the front buffer\n",This);
1460 HeapFree(GetProcessHeap(), 0, object);
1464 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1465 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1467 TRACE("(%p)\n", This);
1469 return This->NumberOfSwapChains;
1472 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1474 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1476 if(iSwapChain < This->NumberOfSwapChains) {
1477 *pSwapChain = This->swapchains[iSwapChain];
1478 IWineD3DSwapChain_AddRef(*pSwapChain);
1479 TRACE("(%p) returning %p\n", This, *pSwapChain);
1482 TRACE("Swapchain out of range\n");
1484 return WINED3DERR_INVALIDCALL;
1489 * Vertex Declaration
1491 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1492 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1494 IWineD3DVertexDeclarationImpl *object = NULL;
1495 HRESULT hr = WINED3D_OK;
1497 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1498 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1500 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1502 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1507 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1509 unsigned int idx, idx2;
1510 unsigned int offset;
1511 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1512 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1513 BOOL has_blend_idx = has_blend &&
1514 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1515 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1516 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1517 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1518 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1519 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1520 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1522 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1523 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1525 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1526 WINED3DVERTEXELEMENT *elements = NULL;
1529 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1530 if (has_blend_idx) num_blends--;
1532 /* Compute declaration size */
1533 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1534 has_psize + has_diffuse + has_specular + num_textures + 1;
1536 /* convert the declaration */
1537 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1541 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1544 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1545 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1546 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1549 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1550 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1552 elements[idx].UsageIndex = 0;
1555 if (has_blend && (num_blends > 0)) {
1556 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1557 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1559 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1560 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1561 elements[idx].UsageIndex = 0;
1564 if (has_blend_idx) {
1565 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1566 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1567 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1568 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1569 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1571 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1572 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1573 elements[idx].UsageIndex = 0;
1577 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1578 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1579 elements[idx].UsageIndex = 0;
1583 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1584 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1585 elements[idx].UsageIndex = 0;
1589 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1590 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1591 elements[idx].UsageIndex = 0;
1595 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1596 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1597 elements[idx].UsageIndex = 1;
1600 for (idx2 = 0; idx2 < num_textures; idx2++) {
1601 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1602 switch (numcoords) {
1603 case WINED3DFVF_TEXTUREFORMAT1:
1604 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1606 case WINED3DFVF_TEXTUREFORMAT2:
1607 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1609 case WINED3DFVF_TEXTUREFORMAT3:
1610 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1612 case WINED3DFVF_TEXTUREFORMAT4:
1613 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1616 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1617 elements[idx].UsageIndex = idx2;
1621 /* Now compute offsets, and initialize the rest of the fields */
1622 for (idx = 0, offset = 0; idx < size-1; idx++) {
1623 elements[idx].Stream = 0;
1624 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1625 elements[idx].Offset = offset;
1626 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1629 *ppVertexElements = elements;
1633 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1634 WINED3DVERTEXELEMENT* elements = NULL;
1638 size = ConvertFvfToDeclaration(Fvf, &elements);
1639 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1641 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1642 HeapFree(GetProcessHeap(), 0, elements);
1643 if (hr != S_OK) return hr;
1648 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1649 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1651 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1652 HRESULT hr = WINED3D_OK;
1653 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1654 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1656 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1658 if (vertex_declaration) {
1659 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1662 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1664 if (WINED3D_OK != hr) {
1665 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1666 IWineD3DVertexShader_Release(*ppVertexShader);
1667 return WINED3DERR_INVALIDCALL;
1673 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1675 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1676 HRESULT hr = WINED3D_OK;
1678 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1679 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1680 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1681 if (WINED3D_OK == hr) {
1682 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1684 WARN("(%p) : Failed to create pixel shader\n", This);
1690 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1692 IWineD3DPaletteImpl *object;
1694 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1696 /* Create the new object */
1697 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1699 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1700 return E_OUTOFMEMORY;
1703 object->lpVtbl = &IWineD3DPalette_Vtbl;
1705 object->Flags = Flags;
1706 object->parent = Parent;
1707 object->wineD3DDevice = This;
1708 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1710 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1713 HeapFree( GetProcessHeap(), 0, object);
1714 return E_OUTOFMEMORY;
1717 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1719 IWineD3DPalette_Release((IWineD3DPalette *) object);
1723 *Palette = (IWineD3DPalette *) object;
1728 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1730 IWineD3DSwapChainImpl *swapchain;
1734 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1735 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1737 /* TODO: Test if OpenGL is compiled in and loaded */
1739 TRACE("(%p) : Creating stateblock\n", This);
1740 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1741 hr = IWineD3DDevice_CreateStateBlock(iface,
1743 (IWineD3DStateBlock **)&This->stateBlock,
1745 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1746 WARN("Failed to create stateblock\n");
1749 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1750 This->updateStateBlock = This->stateBlock;
1751 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1753 hr = allocate_shader_constants(This->updateStateBlock);
1754 if (WINED3D_OK != hr)
1757 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1758 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1759 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1761 /* Initialize the texture unit mapping to a 1:1 mapping */
1762 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1763 if (state < GL_LIMITS(fragment_samplers)) {
1764 This->texUnitMap[state] = state;
1765 This->rev_tex_unit_map[state] = state;
1767 This->texUnitMap[state] = -1;
1768 This->rev_tex_unit_map[state] = -1;
1772 /* Setup the implicit swapchain */
1773 TRACE("Creating implicit swapchain\n");
1774 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1775 if (FAILED(hr) || !swapchain) {
1776 WARN("Failed to create implicit swapchain\n");
1780 This->NumberOfSwapChains = 1;
1781 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1782 if(!This->swapchains) {
1783 ERR("Out of memory!\n");
1784 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1785 return E_OUTOFMEMORY;
1787 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1789 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1791 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1792 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1793 This->render_targets[0] = swapchain->backBuffer[0];
1794 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1797 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1798 This->render_targets[0] = swapchain->frontBuffer;
1799 This->lastActiveRenderTarget = swapchain->frontBuffer;
1801 IWineD3DSurface_AddRef(This->render_targets[0]);
1802 This->activeContext = swapchain->context[0];
1803 This->lastThread = GetCurrentThreadId();
1805 /* Depth Stencil support */
1806 This->stencilBufferTarget = This->depthStencilBuffer;
1807 if (NULL != This->stencilBufferTarget) {
1808 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1811 /* Set up some starting GL setup */
1814 /* Setup all the devices defaults */
1815 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1817 IWineD3DImpl_CheckGraphicsMemory();
1820 { /* Set a default viewport */
1824 vp.Width = pPresentationParameters->BackBufferWidth;
1825 vp.Height = pPresentationParameters->BackBufferHeight;
1828 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1831 /* Initialize the current view state */
1832 This->view_ident = 1;
1833 This->contexts[0]->last_was_rhw = 0;
1834 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1835 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1837 switch(wined3d_settings.offscreen_rendering_mode) {
1840 This->offscreenBuffer = GL_BACK;
1843 case ORM_BACKBUFFER:
1845 if(GL_LIMITS(aux_buffers) > 0) {
1846 TRACE("Using auxilliary buffer for offscreen rendering\n");
1847 This->offscreenBuffer = GL_AUX0;
1849 TRACE("Using back buffer for offscreen rendering\n");
1850 This->offscreenBuffer = GL_BACK;
1855 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1858 /* Clear the screen */
1859 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1860 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1863 This->d3d_initialized = TRUE;
1867 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1871 TRACE("(%p)\n", This);
1873 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1875 /* I don't think that the interface guarants that the device is destroyed from the same thread
1876 * it was created. Thus make sure a context is active for the glDelete* calls
1878 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1880 TRACE("Deleting high order patches\n");
1881 for(i = 0; i < PATCHMAP_SIZE; i++) {
1882 struct list *e1, *e2;
1883 struct WineD3DRectPatch *patch;
1884 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1885 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1886 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1890 /* Delete the pbuffer context if there is any */
1891 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1893 /* Delete the mouse cursor texture */
1894 if(This->cursorTexture) {
1896 glDeleteTextures(1, &This->cursorTexture);
1898 This->cursorTexture = 0;
1901 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1902 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1904 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1905 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1908 /* Release the buffers (with sanity checks)*/
1909 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1910 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1911 if(This->depthStencilBuffer != This->stencilBufferTarget)
1912 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1914 This->stencilBufferTarget = NULL;
1916 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1917 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1918 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1920 TRACE("Setting rendertarget to NULL\n");
1921 This->render_targets[0] = NULL;
1923 if (This->depthStencilBuffer) {
1924 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1925 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1927 This->depthStencilBuffer = NULL;
1930 for(i=0; i < This->NumberOfSwapChains; i++) {
1931 TRACE("Releasing the implicit swapchain %d\n", i);
1932 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
1933 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
1937 HeapFree(GetProcessHeap(), 0, This->swapchains);
1938 This->swapchains = NULL;
1939 This->NumberOfSwapChains = 0;
1941 /* Release the update stateblock */
1942 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1943 if(This->updateStateBlock != This->stateBlock)
1944 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1946 This->updateStateBlock = NULL;
1948 { /* because were not doing proper internal refcounts releasing the primary state block
1949 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1950 to set this->stateBlock = NULL; first */
1951 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1952 This->stateBlock = NULL;
1954 /* Release the stateblock */
1955 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1956 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1960 HeapFree(GetProcessHeap(), 0, This->render_targets);
1961 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
1962 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
1963 This->render_targets = NULL;
1964 This->fbo_color_attachments = NULL;
1965 This->draw_buffers = NULL;
1968 This->d3d_initialized = FALSE;
1972 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
1973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1974 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
1976 /* Setup the window for fullscreen mode */
1977 if(fullscreen && !This->ddraw_fullscreen) {
1978 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
1979 } else if(!fullscreen && This->ddraw_fullscreen) {
1980 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
1983 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
1984 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
1985 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
1988 This->ddraw_fullscreen = fullscreen;
1991 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
1992 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
1993 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
1995 * There is no way to deactivate thread safety once it is enabled
1997 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
1998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2000 /*For now just store the flag(needed in case of ddraw) */
2001 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2006 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2010 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2013 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2015 /* Resize the screen even without a window:
2016 * The app could have unset it with SetCooperativeLevel, but not called
2017 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2018 * but we don't have any hwnd
2021 memset(&devmode, 0, sizeof(devmode));
2022 devmode.dmSize = sizeof(devmode);
2023 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2024 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2025 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2026 devmode.dmPelsWidth = pMode->Width;
2027 devmode.dmPelsHeight = pMode->Height;
2029 devmode.dmDisplayFrequency = pMode->RefreshRate;
2030 if (pMode->RefreshRate != 0) {
2031 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2034 /* Only change the mode if necessary */
2035 if( (This->ddraw_width == pMode->Width) &&
2036 (This->ddraw_height == pMode->Height) &&
2037 (This->ddraw_format == pMode->Format) &&
2038 (pMode->RefreshRate == 0) ) {
2042 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2043 if (ret != DISP_CHANGE_SUCCESSFUL) {
2044 if(devmode.dmDisplayFrequency != 0) {
2045 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2046 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2047 devmode.dmDisplayFrequency = 0;
2048 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2050 if(ret != DISP_CHANGE_SUCCESSFUL) {
2051 return WINED3DERR_NOTAVAILABLE;
2055 /* Store the new values */
2056 This->ddraw_width = pMode->Width;
2057 This->ddraw_height = pMode->Height;
2058 This->ddraw_format = pMode->Format;
2060 /* Only do this with a window of course */
2061 if(This->ddraw_window)
2062 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2064 /* And finally clip mouse to our screen */
2065 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2066 ClipCursor(&clip_rc);
2071 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2073 *ppD3D= This->wineD3D;
2074 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2075 IWineD3D_AddRef(*ppD3D);
2079 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2080 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2081 * into the video ram as possible and seeing how many fit
2082 * you can also get the correct initial value from nvidia and ATI's driver via X
2083 * texture memory is video memory + AGP memory
2084 *******************/
2085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2086 static BOOL showfixmes = TRUE;
2088 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2089 (wined3d_settings.emulated_textureram/(1024*1024)),
2090 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2093 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2094 (wined3d_settings.emulated_textureram/(1024*1024)),
2095 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2096 /* return simulated texture memory left */
2097 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2105 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2108 /* Update the current state block */
2109 This->updateStateBlock->changed.fvf = TRUE;
2111 if(This->updateStateBlock->fvf == fvf) {
2112 TRACE("Application is setting the old fvf over, nothing to do\n");
2116 This->updateStateBlock->fvf = fvf;
2117 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2123 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2125 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2126 *pfvf = This->stateBlock->fvf;
2131 * Get / Set Stream Source
2133 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2135 IWineD3DVertexBuffer *oldSrc;
2137 if (StreamNumber >= MAX_STREAMS) {
2138 WARN("Stream out of range %d\n", StreamNumber);
2139 return WINED3DERR_INVALIDCALL;
2142 oldSrc = This->stateBlock->streamSource[StreamNumber];
2143 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2145 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2147 if(oldSrc == pStreamData &&
2148 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2149 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2150 TRACE("Application is setting the old values over, nothing to do\n");
2154 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2156 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2157 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2160 /* Handle recording of state blocks */
2161 if (This->isRecordingState) {
2162 TRACE("Recording... not performing anything\n");
2166 /* Need to do a getParent and pass the reffs up */
2167 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2168 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2169 so for now, just count internally */
2170 if (pStreamData != NULL) {
2171 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2172 InterlockedIncrement(&vbImpl->bindCount);
2174 if (oldSrc != NULL) {
2175 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2183 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2186 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2187 This->stateBlock->streamSource[StreamNumber],
2188 This->stateBlock->streamOffset[StreamNumber],
2189 This->stateBlock->streamStride[StreamNumber]);
2191 if (StreamNumber >= MAX_STREAMS) {
2192 WARN("Stream out of range %d\n", StreamNumber);
2193 return WINED3DERR_INVALIDCALL;
2195 *pStream = This->stateBlock->streamSource[StreamNumber];
2196 *pStride = This->stateBlock->streamStride[StreamNumber];
2198 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2201 if (*pStream != NULL) {
2202 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2207 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2209 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2210 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2212 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2213 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2215 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2216 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2218 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2219 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2226 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2229 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2230 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2232 TRACE("(%p) : returning %d\n", This, *Divider);
2238 * Get / Set & Multiply Transform
2240 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2243 /* Most of this routine, comments included copied from ddraw tree initially: */
2244 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2246 /* Handle recording of state blocks */
2247 if (This->isRecordingState) {
2248 TRACE("Recording... not performing anything\n");
2249 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2250 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2255 * If the new matrix is the same as the current one,
2256 * we cut off any further processing. this seems to be a reasonable
2257 * optimization because as was noticed, some apps (warcraft3 for example)
2258 * tend towards setting the same matrix repeatedly for some reason.
2260 * From here on we assume that the new matrix is different, wherever it matters.
2262 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2263 TRACE("The app is setting the same matrix over again\n");
2266 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2270 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2271 where ViewMat = Camera space, WorldMat = world space.
2273 In OpenGL, camera and world space is combined into GL_MODELVIEW
2274 matrix. The Projection matrix stay projection matrix.
2277 /* Capture the times we can just ignore the change for now */
2278 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2279 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2280 /* Handled by the state manager */
2283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2287 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2289 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2290 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2294 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2295 WINED3DMATRIX *mat = NULL;
2298 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2299 * below means it will be recorded in a state block change, but it
2300 * works regardless where it is recorded.
2301 * If this is found to be wrong, change to StateBlock.
2303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2304 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2306 if (State < HIGHEST_TRANSFORMSTATE)
2308 mat = &This->updateStateBlock->transforms[State];
2310 FIXME("Unhandled transform state!!\n");
2313 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2315 /* Apply change via set transform - will reapply to eg. lights this way */
2316 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2322 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2323 you can reference any indexes you want as long as that number max are enabled at any
2324 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2325 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2326 but when recording, just build a chain pretty much of commands to be replayed. */
2328 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2330 PLIGHTINFOEL *object = NULL;
2331 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2335 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2337 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2341 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2342 return WINED3DERR_INVALIDCALL;
2345 switch(pLight->Type) {
2346 case WINED3DLIGHT_POINT:
2347 case WINED3DLIGHT_SPOT:
2348 case WINED3DLIGHT_PARALLELPOINT:
2349 case WINED3DLIGHT_GLSPOT:
2350 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2353 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2354 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2355 return WINED3DERR_INVALIDCALL;
2359 case WINED3DLIGHT_DIRECTIONAL:
2360 /* Ignores attenuation */
2364 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2365 return WINED3DERR_INVALIDCALL;
2368 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2369 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2370 if(object->OriginalIndex == Index) break;
2375 TRACE("Adding new light\n");
2376 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2378 ERR("Out of memory error when allocating a light\n");
2379 return E_OUTOFMEMORY;
2381 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2382 object->glIndex = -1;
2383 object->OriginalIndex = Index;
2384 object->changed = TRUE;
2387 /* Initialize the object */
2388 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,
2389 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2390 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2391 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2392 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2393 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2394 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2396 /* Save away the information */
2397 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2399 switch (pLight->Type) {
2400 case WINED3DLIGHT_POINT:
2402 object->lightPosn[0] = pLight->Position.x;
2403 object->lightPosn[1] = pLight->Position.y;
2404 object->lightPosn[2] = pLight->Position.z;
2405 object->lightPosn[3] = 1.0f;
2406 object->cutoff = 180.0f;
2410 case WINED3DLIGHT_DIRECTIONAL:
2412 object->lightPosn[0] = -pLight->Direction.x;
2413 object->lightPosn[1] = -pLight->Direction.y;
2414 object->lightPosn[2] = -pLight->Direction.z;
2415 object->lightPosn[3] = 0.0;
2416 object->exponent = 0.0f;
2417 object->cutoff = 180.0f;
2420 case WINED3DLIGHT_SPOT:
2422 object->lightPosn[0] = pLight->Position.x;
2423 object->lightPosn[1] = pLight->Position.y;
2424 object->lightPosn[2] = pLight->Position.z;
2425 object->lightPosn[3] = 1.0;
2428 object->lightDirn[0] = pLight->Direction.x;
2429 object->lightDirn[1] = pLight->Direction.y;
2430 object->lightDirn[2] = pLight->Direction.z;
2431 object->lightDirn[3] = 1.0;
2434 * opengl-ish and d3d-ish spot lights use too different models for the
2435 * light "intensity" as a function of the angle towards the main light direction,
2436 * so we only can approximate very roughly.
2437 * however spot lights are rather rarely used in games (if ever used at all).
2438 * furthermore if still used, probably nobody pays attention to such details.
2440 if (pLight->Falloff == 0) {
2443 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2445 if (rho < 0.0001) rho = 0.0001f;
2446 object->exponent = -0.3/log(cos(rho/2));
2447 if (object->exponent > 128.0) {
2448 object->exponent = 128.0;
2450 object->cutoff = pLight->Phi*90/M_PI;
2456 FIXME("Unrecognized light type %d\n", pLight->Type);
2459 /* Update the live definitions if the light is currently assigned a glIndex */
2460 if (object->glIndex != -1 && !This->isRecordingState) {
2461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2466 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2467 PLIGHTINFOEL *lightInfo = NULL;
2468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2469 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2471 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2473 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2474 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2475 if(lightInfo->OriginalIndex == Index) break;
2479 if (lightInfo == NULL) {
2480 TRACE("Light information requested but light not defined\n");
2481 return WINED3DERR_INVALIDCALL;
2484 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2489 * Get / Set Light Enable
2490 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2492 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2493 PLIGHTINFOEL *lightInfo = NULL;
2494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2495 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2497 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2499 /* Tests show true = 128...not clear why */
2500 Enable = Enable? 128: 0;
2502 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2503 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2504 if(lightInfo->OriginalIndex == Index) break;
2507 TRACE("Found light: %p\n", lightInfo);
2509 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2510 if (lightInfo == NULL) {
2512 TRACE("Light enabled requested but light not defined, so defining one!\n");
2513 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2515 /* Search for it again! Should be fairly quick as near head of list */
2516 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2517 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2518 if(lightInfo->OriginalIndex == Index) break;
2521 if (lightInfo == NULL) {
2522 FIXME("Adding default lights has failed dismally\n");
2523 return WINED3DERR_INVALIDCALL;
2527 lightInfo->enabledChanged = TRUE;
2529 if(lightInfo->glIndex != -1) {
2530 if(!This->isRecordingState) {
2531 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2534 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2535 lightInfo->glIndex = -1;
2537 TRACE("Light already disabled, nothing to do\n");
2540 if (lightInfo->glIndex != -1) {
2542 TRACE("Nothing to do as light was enabled\n");
2545 /* Find a free gl light */
2546 for(i = 0; i < This->maxConcurrentLights; i++) {
2547 if(This->stateBlock->activeLights[i] == NULL) {
2548 This->stateBlock->activeLights[i] = lightInfo;
2549 lightInfo->glIndex = i;
2553 if(lightInfo->glIndex == -1) {
2554 ERR("Too many concurrently active lights\n");
2555 return WINED3DERR_INVALIDCALL;
2558 /* i == lightInfo->glIndex */
2559 if(!This->isRecordingState) {
2560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2568 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2570 PLIGHTINFOEL *lightInfo = NULL;
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2573 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2574 TRACE("(%p) : for idx(%d)\n", This, Index);
2576 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2577 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2578 if(lightInfo->OriginalIndex == Index) break;
2582 if (lightInfo == NULL) {
2583 TRACE("Light enabled state requested but light not defined\n");
2584 return WINED3DERR_INVALIDCALL;
2586 /* true is 128 according to SetLightEnable */
2587 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2592 * Get / Set Clip Planes
2594 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2596 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2598 /* Validate Index */
2599 if (Index >= GL_LIMITS(clipplanes)) {
2600 TRACE("Application has requested clipplane this device doesn't support\n");
2601 return WINED3DERR_INVALIDCALL;
2604 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2606 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2607 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2608 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2609 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2610 TRACE("Application is setting old values over, nothing to do\n");
2614 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2615 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2616 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2617 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2619 /* Handle recording of state blocks */
2620 if (This->isRecordingState) {
2621 TRACE("Recording... not performing anything\n");
2625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2630 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p) : for idx %d\n", This, Index);
2634 /* Validate Index */
2635 if (Index >= GL_LIMITS(clipplanes)) {
2636 TRACE("Application has requested clipplane this device doesn't support\n");
2637 return WINED3DERR_INVALIDCALL;
2640 pPlane[0] = This->stateBlock->clipplane[Index][0];
2641 pPlane[1] = This->stateBlock->clipplane[Index][1];
2642 pPlane[2] = This->stateBlock->clipplane[Index][2];
2643 pPlane[3] = This->stateBlock->clipplane[Index][3];
2648 * Get / Set Clip Plane Status
2649 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2651 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2653 FIXME("(%p) : stub\n", This);
2654 if (NULL == pClipStatus) {
2655 return WINED3DERR_INVALIDCALL;
2657 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2658 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2662 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 FIXME("(%p) : stub\n", This);
2665 if (NULL == pClipStatus) {
2666 return WINED3DERR_INVALIDCALL;
2668 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2669 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2674 * Get / Set Material
2676 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2679 This->updateStateBlock->changed.material = TRUE;
2680 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2682 /* Handle recording of state blocks */
2683 if (This->isRecordingState) {
2684 TRACE("Recording... not performing anything\n");
2688 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2692 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2694 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2695 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2696 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2697 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2698 pMaterial->Ambient.b, pMaterial->Ambient.a);
2699 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2700 pMaterial->Specular.b, pMaterial->Specular.a);
2701 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2702 pMaterial->Emissive.b, pMaterial->Emissive.a);
2703 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2711 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713 IWineD3DIndexBuffer *oldIdxs;
2715 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2716 oldIdxs = This->updateStateBlock->pIndexData;
2718 This->updateStateBlock->changed.indices = TRUE;
2719 This->updateStateBlock->pIndexData = pIndexData;
2721 /* Handle recording of state blocks */
2722 if (This->isRecordingState) {
2723 TRACE("Recording... not performing anything\n");
2727 if(oldIdxs != pIndexData) {
2728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2733 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2736 *ppIndexData = This->stateBlock->pIndexData;
2738 /* up ref count on ppindexdata */
2740 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2741 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2743 TRACE("(%p) No index data set\n", This);
2745 TRACE("Returning %p\n", *ppIndexData);
2750 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2751 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2753 TRACE("(%p)->(%d)\n", This, BaseIndex);
2755 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2756 TRACE("Application is setting the old value over, nothing to do\n");
2760 This->updateStateBlock->baseVertexIndex = BaseIndex;
2762 if (This->isRecordingState) {
2763 TRACE("Recording... not performing anything\n");
2766 /* The base vertex index affects the stream sources */
2767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2771 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 TRACE("(%p) : base_index %p\n", This, base_index);
2775 *base_index = This->stateBlock->baseVertexIndex;
2777 TRACE("Returning %u\n", *base_index);
2783 * Get / Set Viewports
2785 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2788 TRACE("(%p)\n", This);
2789 This->updateStateBlock->changed.viewport = TRUE;
2790 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2792 /* Handle recording of state blocks */
2793 if (This->isRecordingState) {
2794 TRACE("Recording... not performing anything\n");
2798 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2799 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2806 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 TRACE("(%p)\n", This);
2809 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2814 * Get / Set Render States
2815 * TODO: Verify against dx9 definitions
2817 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2820 DWORD oldValue = This->stateBlock->renderState[State];
2822 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2824 This->updateStateBlock->changed.renderState[State] = TRUE;
2825 This->updateStateBlock->renderState[State] = Value;
2827 /* Handle recording of state blocks */
2828 if (This->isRecordingState) {
2829 TRACE("Recording... not performing anything\n");
2833 /* Compared here and not before the assignment to allow proper stateblock recording */
2834 if(Value == oldValue) {
2835 TRACE("Application is setting the old value over, nothing to do\n");
2837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2843 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2845 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2846 *pValue = This->stateBlock->renderState[State];
2851 * Get / Set Sampler States
2852 * TODO: Verify against dx9 definitions
2855 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2859 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2860 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2862 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2863 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2867 * SetSampler is designed to allow for more than the standard up to 8 textures
2868 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2869 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2871 * http://developer.nvidia.com/object/General_FAQ.html#t6
2873 * There are two new settings for GForce
2875 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2876 * and the texture one:
2877 * GL_MAX_TEXTURE_COORDS_ARB.
2878 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2881 oldValue = This->stateBlock->samplerState[Sampler][Type];
2882 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2883 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2885 /* Handle recording of state blocks */
2886 if (This->isRecordingState) {
2887 TRACE("Recording... not performing anything\n");
2891 if(oldValue == Value) {
2892 TRACE("Application is setting the old value over, nothing to do\n");
2896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2905 This, Sampler, debug_d3dsamplerstate(Type), Type);
2907 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2908 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2911 *Value = This->stateBlock->samplerState[Sampler][Type];
2912 TRACE("(%p) : Returning %#x\n", This, *Value);
2917 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 This->updateStateBlock->changed.scissorRect = TRUE;
2921 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2922 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2925 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2927 if(This->isRecordingState) {
2928 TRACE("Recording... not performing anything\n");
2932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
2937 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
2938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
2941 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
2945 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
2946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2947 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
2949 TRACE("(%p) : pDecl=%p\n", This, pDecl);
2951 This->updateStateBlock->vertexDecl = pDecl;
2952 This->updateStateBlock->changed.vertexDecl = TRUE;
2954 if (This->isRecordingState) {
2955 TRACE("Recording... not performing anything\n");
2957 } else if(pDecl == oldDecl) {
2958 /* Checked after the assignment to allow proper stateblock recording */
2959 TRACE("Application is setting the old declaration over, nothing to do\n");
2963 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2967 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
2968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
2972 *ppDecl = This->stateBlock->vertexDecl;
2973 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
2977 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
2981 This->updateStateBlock->vertexShader = pShader;
2982 This->updateStateBlock->changed.vertexShader = TRUE;
2984 if (This->isRecordingState) {
2985 TRACE("Recording... not performing anything\n");
2987 } else if(oldShader == pShader) {
2988 /* Checked here to allow proper stateblock recording */
2989 TRACE("App is setting the old shader over, nothing to do\n");
2993 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
2995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3000 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 if (NULL == ppShader) {
3004 return WINED3DERR_INVALIDCALL;
3006 *ppShader = This->stateBlock->vertexShader;
3007 if( NULL != *ppShader)
3008 IWineD3DVertexShader_AddRef(*ppShader);
3010 TRACE("(%p) : returning %p\n", This, *ppShader);
3014 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3015 IWineD3DDevice *iface,
3017 CONST BOOL *srcData,
3020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 int i, cnt = min(count, MAX_CONST_B - start);
3023 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3024 iface, srcData, start, count);
3026 if (srcData == NULL || cnt < 0)
3027 return WINED3DERR_INVALIDCALL;
3029 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3030 for (i = 0; i < cnt; i++)
3031 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3033 for (i = start; i < cnt + start; ++i) {
3034 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3043 IWineD3DDevice *iface,
3048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 int cnt = min(count, MAX_CONST_B - start);
3051 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3052 iface, dstData, start, count);
3054 if (dstData == NULL || cnt < 0)
3055 return WINED3DERR_INVALIDCALL;
3057 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3062 IWineD3DDevice *iface,
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3068 int i, cnt = min(count, MAX_CONST_I - start);
3070 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3071 iface, srcData, start, count);
3073 if (srcData == NULL || cnt < 0)
3074 return WINED3DERR_INVALIDCALL;
3076 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3077 for (i = 0; i < cnt; i++)
3078 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3079 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3081 for (i = start; i < cnt + start; ++i) {
3082 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3090 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3091 IWineD3DDevice *iface,
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 int cnt = min(count, MAX_CONST_I - start);
3099 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3100 iface, dstData, start, count);
3102 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3103 return WINED3DERR_INVALIDCALL;
3105 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3109 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3110 IWineD3DDevice *iface,
3112 CONST float *srcData,
3115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3118 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3119 iface, srcData, start, count);
3121 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3122 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3123 return WINED3DERR_INVALIDCALL;
3125 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3127 for (i = 0; i < count; i++)
3128 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3129 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3132 for (i = start; i < count + start; ++i) {
3133 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3134 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3135 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3136 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3137 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3139 ptr->idx[ptr->count++] = i;
3140 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3144 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3149 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3150 IWineD3DDevice *iface,
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3158 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3159 iface, dstData, start, count);
3161 if (dstData == NULL || cnt < 0)
3162 return WINED3DERR_INVALIDCALL;
3164 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3168 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3170 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3175 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3176 int i = This->rev_tex_unit_map[unit];
3177 int j = This->texUnitMap[stage];
3179 This->texUnitMap[stage] = unit;
3180 if (i != -1 && i != stage) {
3181 This->texUnitMap[i] = -1;
3184 This->rev_tex_unit_map[unit] = stage;
3185 if (j != -1 && j != unit) {
3186 This->rev_tex_unit_map[j] = -1;
3190 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3193 for (i = 0; i < MAX_TEXTURES; ++i) {
3194 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3195 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3196 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3197 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3198 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3199 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3200 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3201 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3203 if (color_op == WINED3DTOP_DISABLE) {
3204 /* Not used, and disable higher stages */
3205 while (i < MAX_TEXTURES) {
3206 This->fixed_function_usage_map[i] = FALSE;
3212 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3213 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3214 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3215 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3216 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3217 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3218 This->fixed_function_usage_map[i] = TRUE;
3220 This->fixed_function_usage_map[i] = FALSE;
3223 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3224 This->fixed_function_usage_map[i+1] = TRUE;
3229 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3232 device_update_fixed_function_usage_map(This);
3234 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3235 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3236 if (!This->fixed_function_usage_map[i]) continue;
3238 if (This->texUnitMap[i] != i) {
3239 device_map_stage(This, i, i);
3240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3241 markTextureStagesDirty(This, i);
3247 /* Now work out the mapping */
3249 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3250 if (!This->fixed_function_usage_map[i]) continue;
3252 if (This->texUnitMap[i] != tex) {
3253 device_map_stage(This, i, tex);
3254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3255 markTextureStagesDirty(This, i);
3262 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3263 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3266 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3267 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3268 device_map_stage(This, i, i);
3269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3270 if (i < MAX_TEXTURES) {
3271 markTextureStagesDirty(This, i);
3277 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3278 int current_mapping = This->rev_tex_unit_map[unit];
3280 if (current_mapping == -1) {
3281 /* Not currently used */
3285 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3286 /* Used by a fragment sampler */
3288 if (!pshader_sampler_tokens) {
3289 /* No pixel shader, check fixed function */
3290 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3293 /* Pixel shader, check the shader's sampler map */
3294 return !pshader_sampler_tokens[current_mapping];
3297 /* Used by a vertex sampler */
3298 return !vshader_sampler_tokens[current_mapping];
3301 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3302 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3303 DWORD *pshader_sampler_tokens = NULL;
3304 int start = GL_LIMITS(combined_samplers) - 1;
3308 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3310 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3311 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3312 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3315 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3316 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3317 if (vshader_sampler_tokens[i]) {
3318 if (This->texUnitMap[vsampler_idx] != -1) {
3319 /* Already mapped somewhere */
3323 while (start >= 0) {
3324 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3325 device_map_stage(This, vsampler_idx, start);
3326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3338 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3339 BOOL vs = use_vs(This);
3340 BOOL ps = use_ps(This);
3343 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3344 * that would be really messy and require shader recompilation
3345 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3346 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3349 device_map_psamplers(This);
3351 device_map_fixed_function_samplers(This);
3355 device_map_vsamplers(This, ps);
3359 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3361 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3362 This->updateStateBlock->pixelShader = pShader;
3363 This->updateStateBlock->changed.pixelShader = TRUE;
3365 /* Handle recording of state blocks */
3366 if (This->isRecordingState) {
3367 TRACE("Recording... not performing anything\n");
3370 if (This->isRecordingState) {
3371 TRACE("Recording... not performing anything\n");
3375 if(pShader == oldShader) {
3376 TRACE("App is setting the old pixel shader over, nothing to do\n");
3380 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3386 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3389 if (NULL == ppShader) {
3390 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3391 return WINED3DERR_INVALIDCALL;
3394 *ppShader = This->stateBlock->pixelShader;
3395 if (NULL != *ppShader) {
3396 IWineD3DPixelShader_AddRef(*ppShader);
3398 TRACE("(%p) : returning %p\n", This, *ppShader);
3402 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3403 IWineD3DDevice *iface,
3405 CONST BOOL *srcData,
3408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3409 int i, cnt = min(count, MAX_CONST_B - start);
3411 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3412 iface, srcData, start, count);
3414 if (srcData == NULL || cnt < 0)
3415 return WINED3DERR_INVALIDCALL;
3417 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3418 for (i = 0; i < cnt; i++)
3419 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3421 for (i = start; i < cnt + start; ++i) {
3422 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3430 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3431 IWineD3DDevice *iface,
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 int cnt = min(count, MAX_CONST_B - start);
3439 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3440 iface, dstData, start, count);
3442 if (dstData == NULL || cnt < 0)
3443 return WINED3DERR_INVALIDCALL;
3445 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3449 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3450 IWineD3DDevice *iface,
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3456 int i, cnt = min(count, MAX_CONST_I - start);
3458 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3459 iface, srcData, start, count);
3461 if (srcData == NULL || cnt < 0)
3462 return WINED3DERR_INVALIDCALL;
3464 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3465 for (i = 0; i < cnt; i++)
3466 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3467 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3469 for (i = start; i < cnt + start; ++i) {
3470 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3478 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3479 IWineD3DDevice *iface,
3484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3485 int cnt = min(count, MAX_CONST_I - start);
3487 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3488 iface, dstData, start, count);
3490 if (dstData == NULL || cnt < 0)
3491 return WINED3DERR_INVALIDCALL;
3493 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3497 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3498 IWineD3DDevice *iface,
3500 CONST float *srcData,
3503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3506 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3507 iface, srcData, start, count);
3509 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3510 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3511 return WINED3DERR_INVALIDCALL;
3513 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3515 for (i = 0; i < count; i++)
3516 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3517 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3520 for (i = start; i < count + start; ++i) {
3521 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3522 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3523 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3524 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3525 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3527 ptr->idx[ptr->count++] = i;
3528 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3537 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3538 IWineD3DDevice *iface,
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3546 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3547 iface, dstData, start, count);
3549 if (dstData == NULL || cnt < 0)
3550 return WINED3DERR_INVALIDCALL;
3552 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3556 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3558 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3559 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3561 DWORD DestFVF = dest->fvf;
3563 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3567 if (lpStrideData->u.s.normal.lpData) {
3568 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3571 if (lpStrideData->u.s.position.lpData == NULL) {
3572 ERR("Source has no position mask\n");
3573 return WINED3DERR_INVALIDCALL;
3576 /* We might access VBOs from this code, so hold the lock */
3579 if (dest->resource.allocatedMemory == NULL) {
3580 /* This may happen if we do direct locking into a vbo. Unlikely,
3581 * but theoretically possible(ddraw processvertices test)
3583 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3584 if(!dest->resource.allocatedMemory) {
3586 ERR("Out of memory\n");
3587 return E_OUTOFMEMORY;
3591 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3592 checkGLcall("glBindBufferARB");
3593 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3595 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3597 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3598 checkGLcall("glUnmapBufferARB");
3602 /* Get a pointer into the destination vbo(create one if none exists) and
3603 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3605 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3610 unsigned char extrabytes = 0;
3611 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3612 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3613 * this may write 4 extra bytes beyond the area that should be written
3615 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3616 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3617 if(!dest_conv_addr) {
3618 ERR("Out of memory\n");
3619 /* Continue without storing converted vertices */
3621 dest_conv = dest_conv_addr;
3625 * a) WINED3DRS_CLIPPING is enabled
3626 * b) WINED3DVOP_CLIP is passed
3628 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3629 static BOOL warned = FALSE;
3631 * The clipping code is not quite correct. Some things need
3632 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3633 * so disable clipping for now.
3634 * (The graphics in Half-Life are broken, and my processvertices
3635 * test crashes with IDirect3DDevice3)
3641 FIXME("Clipping is broken and disabled for now\n");
3643 } else doClip = FALSE;
3644 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3646 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3649 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3650 WINED3DTS_PROJECTION,
3652 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3653 WINED3DTS_WORLDMATRIX(0),
3656 TRACE("View mat:\n");
3657 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);
3658 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);
3659 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);
3660 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);
3662 TRACE("Proj mat:\n");
3663 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);
3664 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);
3665 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);
3666 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);
3668 TRACE("World mat:\n");
3669 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);
3670 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);
3671 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);
3672 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);
3674 /* Get the viewport */
3675 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3676 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3677 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3679 multiply_matrix(&mat,&view_mat,&world_mat);
3680 multiply_matrix(&mat,&proj_mat,&mat);
3682 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3684 for (i = 0; i < dwCount; i+= 1) {
3685 unsigned int tex_index;
3687 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3688 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3689 /* The position first */
3691 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3693 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3695 /* Multiplication with world, view and projection matrix */
3696 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);
3697 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);
3698 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);
3699 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);
3701 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3703 /* WARNING: The following things are taken from d3d7 and were not yet checked
3704 * against d3d8 or d3d9!
3707 /* Clipping conditions: From
3708 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3710 * A vertex is clipped if it does not match the following requirements
3714 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3716 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3717 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3722 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3723 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3726 /* "Normal" viewport transformation (not clipped)
3727 * 1) The values are divided by rhw
3728 * 2) The y axis is negative, so multiply it with -1
3729 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3730 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3731 * 4) Multiply x with Width/2 and add Width/2
3732 * 5) The same for the height
3733 * 6) Add the viewpoint X and Y to the 2D coordinates and
3734 * The minimum Z value to z
3735 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3737 * Well, basically it's simply a linear transformation into viewport
3749 z *= vp.MaxZ - vp.MinZ;
3751 x += vp.Width / 2 + vp.X;
3752 y += vp.Height / 2 + vp.Y;
3757 /* That vertex got clipped
3758 * Contrary to OpenGL it is not dropped completely, it just
3759 * undergoes a different calculation.
3761 TRACE("Vertex got clipped\n");
3768 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3769 * outside of the main vertex buffer memory. That needs some more
3774 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3777 ( (float *) dest_ptr)[0] = x;
3778 ( (float *) dest_ptr)[1] = y;
3779 ( (float *) dest_ptr)[2] = z;
3780 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3782 dest_ptr += 3 * sizeof(float);
3784 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3785 dest_ptr += sizeof(float);
3790 ( (float *) dest_conv)[0] = x * w;
3791 ( (float *) dest_conv)[1] = y * w;
3792 ( (float *) dest_conv)[2] = z * w;
3793 ( (float *) dest_conv)[3] = w;
3795 dest_conv += 3 * sizeof(float);
3797 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3798 dest_conv += sizeof(float);
3802 if (DestFVF & WINED3DFVF_PSIZE) {
3803 dest_ptr += sizeof(DWORD);
3804 if(dest_conv) dest_conv += sizeof(DWORD);
3806 if (DestFVF & WINED3DFVF_NORMAL) {
3808 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3809 /* AFAIK this should go into the lighting information */
3810 FIXME("Didn't expect the destination to have a normal\n");
3811 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3813 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3817 if (DestFVF & WINED3DFVF_DIFFUSE) {
3819 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3821 static BOOL warned = FALSE;
3824 ERR("No diffuse color in source, but destination has one\n");
3828 *( (DWORD *) dest_ptr) = 0xffffffff;
3829 dest_ptr += sizeof(DWORD);
3832 *( (DWORD *) dest_conv) = 0xffffffff;
3833 dest_conv += sizeof(DWORD);
3837 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3839 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3840 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3841 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3842 dest_conv += sizeof(DWORD);
3847 if (DestFVF & WINED3DFVF_SPECULAR) {
3848 /* What's the color value in the feedback buffer? */
3850 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3852 static BOOL warned = FALSE;
3855 ERR("No specular color in source, but destination has one\n");
3859 *( (DWORD *) dest_ptr) = 0xFF000000;
3860 dest_ptr += sizeof(DWORD);
3863 *( (DWORD *) dest_conv) = 0xFF000000;
3864 dest_conv += sizeof(DWORD);
3868 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3870 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3871 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3872 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3873 dest_conv += sizeof(DWORD);
3878 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3880 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3881 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3883 ERR("No source texture, but destination requests one\n");
3884 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3885 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3888 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3890 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3897 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3898 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3899 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3900 dwCount * get_flexible_vertex_size(DestFVF),
3902 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3903 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3910 #undef copy_and_next
3912 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3914 WineDirect3DVertexStridedData strided;
3915 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3916 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3919 ERR("Output vertex declaration not implemented yet\n");
3922 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3923 * and this call is quite performance critical, so don't call needlessly
3925 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3926 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3929 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
3930 * control the streamIsUP flag, thus restore it afterwards.
3932 This->stateBlock->streamIsUP = FALSE;
3933 memset(&strided, 0, sizeof(strided));
3934 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
3935 This->stateBlock->streamIsUP = streamWasUP;
3937 if(vbo || SrcStartIndex) {
3939 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
3940 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
3942 * Also get the start index in, but only loop over all elements if there's something to add at all.
3944 #define FIXSRC(type) \
3945 if(strided.u.s.type.VBO) { \
3946 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
3947 strided.u.s.type.VBO = 0; \
3948 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
3950 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
3954 if(strided.u.s.type.lpData) { \
3955 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
3958 FIXSRC(blendWeights);
3959 FIXSRC(blendMatrixIndices);
3964 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
3965 FIXSRC(texCoords[i]);
3978 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
3982 * Get / Set Texture Stage States
3983 * TODO: Verify against dx9 definitions
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
3986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3987 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
3989 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
3991 if (Stage >= MAX_TEXTURES) {
3992 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
3996 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
3997 This->updateStateBlock->textureState[Stage][Type] = Value;
3999 if (This->isRecordingState) {
4000 TRACE("Recording... not performing anything\n");
4004 /* Checked after the assignments to allow proper stateblock recording */
4005 if(oldValue == Value) {
4006 TRACE("App is setting the old value over, nothing to do\n");
4010 if(Stage > This->stateBlock->lowest_disabled_stage &&
4011 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4012 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4013 * Changes in other states are important on disabled stages too
4018 if(Type == WINED3DTSS_COLOROP) {
4021 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4022 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4023 * they have to be disabled
4025 * The current stage is dirtified below.
4027 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4028 TRACE("Additionally dirtifying stage %d\n", i);
4029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4031 This->stateBlock->lowest_disabled_stage = Stage;
4032 TRACE("New lowest disabled: %d\n", Stage);
4033 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4034 /* Previously disabled stage enabled. Stages above it may need enabling
4035 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4036 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4038 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4041 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4042 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4045 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4046 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4048 This->stateBlock->lowest_disabled_stage = i;
4049 TRACE("New lowest disabled: %d\n", i);
4051 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4052 /* TODO: Built a stage -> texture unit mapping for register combiners */
4056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4061 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4063 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4064 *pValue = This->updateStateBlock->textureState[Stage][Type];
4071 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4073 IWineD3DBaseTexture *oldTexture;
4075 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4077 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4078 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4081 oldTexture = This->updateStateBlock->textures[Stage];
4083 if(pTexture != NULL) {
4084 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4086 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4087 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4088 return WINED3DERR_INVALIDCALL;
4090 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4093 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4094 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4096 This->updateStateBlock->changed.textures[Stage] = TRUE;
4097 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4098 This->updateStateBlock->textures[Stage] = pTexture;
4100 /* Handle recording of state blocks */
4101 if (This->isRecordingState) {
4102 TRACE("Recording... not performing anything\n");
4106 if(oldTexture == pTexture) {
4107 TRACE("App is setting the same texture again, nothing to do\n");
4111 /** NOTE: MSDN says that setTexture increases the reference count,
4112 * and the the application must set the texture back to null (or have a leaky application),
4113 * This means we should pass the refcount up to the parent
4114 *******************************/
4115 if (NULL != This->updateStateBlock->textures[Stage]) {
4116 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4117 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4119 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4120 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4121 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4122 * so the COLOROP and ALPHAOP have to be dirtified.
4124 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4125 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4127 if(bindCount == 1) {
4128 new->baseTexture.sampler = Stage;
4130 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4134 if (NULL != oldTexture) {
4135 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4136 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4138 IWineD3DBaseTexture_Release(oldTexture);
4139 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4144 if(bindCount && old->baseTexture.sampler == Stage) {
4146 /* Have to do a search for the other sampler(s) where the texture is bound to
4147 * Shouldn't happen as long as apps bind a texture only to one stage
4149 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4150 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4151 if(This->updateStateBlock->textures[i] == oldTexture) {
4152 old->baseTexture.sampler = i;
4159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4164 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4167 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4169 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4170 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4173 *ppTexture=This->stateBlock->textures[Stage];
4175 IWineD3DBaseTexture_AddRef(*ppTexture);
4177 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4185 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4186 IWineD3DSurface **ppBackBuffer) {
4187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4188 IWineD3DSwapChain *swapChain;
4191 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4193 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4194 if (hr == WINED3D_OK) {
4195 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4196 IWineD3DSwapChain_Release(swapChain);
4198 *ppBackBuffer = NULL;
4203 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4205 WARN("(%p) : stub, calling idirect3d for now\n", This);
4206 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4209 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4211 IWineD3DSwapChain *swapChain;
4214 if(iSwapChain > 0) {
4215 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4216 if (hr == WINED3D_OK) {
4217 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4218 IWineD3DSwapChain_Release(swapChain);
4220 FIXME("(%p) Error getting display mode\n", This);
4223 /* Don't read the real display mode,
4224 but return the stored mode instead. X11 can't change the color
4225 depth, and some apps are pretty angry if they SetDisplayMode from
4226 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4228 Also don't relay to the swapchain because with ddraw it's possible
4229 that there isn't a swapchain at all */
4230 pMode->Width = This->ddraw_width;
4231 pMode->Height = This->ddraw_height;
4232 pMode->Format = This->ddraw_format;
4233 pMode->RefreshRate = 0;
4240 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4242 TRACE("(%p)->(%p)\n", This, hWnd);
4244 if(This->ddraw_fullscreen) {
4245 if(This->ddraw_window && This->ddraw_window != hWnd) {
4246 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4248 if(hWnd && This->ddraw_window != hWnd) {
4249 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4253 This->ddraw_window = hWnd;
4257 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4259 TRACE("(%p)->(%p)\n", This, hWnd);
4261 *hWnd = This->ddraw_window;
4266 * Stateblock related functions
4269 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4271 IWineD3DStateBlockImpl *object;
4272 HRESULT temp_result;
4275 TRACE("(%p)\n", This);
4277 if (This->isRecordingState) {
4278 return WINED3DERR_INVALIDCALL;
4281 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4282 if (NULL == object ) {
4283 FIXME("(%p)Error allocating memory for stateblock\n", This);
4284 return E_OUTOFMEMORY;
4286 TRACE("(%p) created object %p\n", This, object);
4287 object->wineD3DDevice= This;
4288 /** FIXME: object->parent = parent; **/
4289 object->parent = NULL;
4290 object->blockType = WINED3DSBT_ALL;
4292 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4294 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4295 list_init(&object->lightMap[i]);
4298 temp_result = allocate_shader_constants(object);
4299 if (WINED3D_OK != temp_result)
4302 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4303 This->updateStateBlock = object;
4304 This->isRecordingState = TRUE;
4306 TRACE("(%p) recording stateblock %p\n",This , object);
4310 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4313 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4315 if (!This->isRecordingState) {
4316 FIXME("(%p) not recording! returning error\n", This);
4317 *ppStateBlock = NULL;
4318 return WINED3DERR_INVALIDCALL;
4321 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4322 if(object->changed.renderState[i]) {
4323 object->contained_render_states[object->num_contained_render_states] = i;
4324 object->num_contained_render_states++;
4328 *ppStateBlock = (IWineD3DStateBlock*) object;
4329 This->isRecordingState = FALSE;
4330 This->updateStateBlock = This->stateBlock;
4331 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4332 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4333 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4338 * Scene related functions
4340 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4341 /* At the moment we have no need for any functionality at the beginning
4343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4344 TRACE("(%p)\n", This);
4347 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4348 return WINED3DERR_INVALIDCALL;
4350 This->inScene = TRUE;
4354 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4356 TRACE("(%p)\n", This);
4358 if(!This->inScene) {
4359 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4360 return WINED3DERR_INVALIDCALL;
4363 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4364 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4366 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4369 checkGLcall("glFlush");
4372 This->inScene = FALSE;
4376 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4377 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4378 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4380 IWineD3DSwapChain *swapChain = NULL;
4382 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4384 TRACE("(%p) Presenting the frame\n", This);
4386 for(i = 0 ; i < swapchains ; i ++) {
4388 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4389 TRACE("presentinng chain %d, %p\n", i, swapChain);
4390 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4391 IWineD3DSwapChain_Release(swapChain);
4397 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4398 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4400 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4402 GLbitfield glMask = 0;
4404 CONST WINED3DRECT* curRect;
4406 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4407 Count, pRects, Flags, Color, Z, Stencil);
4409 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4410 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4411 /* TODO: What about depth stencil buffers without stencil bits? */
4412 return WINED3DERR_INVALIDCALL;
4415 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4416 * and not the last active one.
4418 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4421 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4422 apply_fbo_state(iface);
4425 if (Count > 0 && pRects) {
4431 /* Only set the values up once, as they are not changing */
4432 if (Flags & WINED3DCLEAR_STENCIL) {
4433 glClearStencil(Stencil);
4434 checkGLcall("glClearStencil");
4435 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4436 glStencilMask(0xFFFFFFFF);
4439 if (Flags & WINED3DCLEAR_ZBUFFER) {
4440 glDepthMask(GL_TRUE);
4442 checkGLcall("glClearDepth");
4443 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4447 if (Flags & WINED3DCLEAR_TARGET) {
4448 TRACE("Clearing screen with glClear to color %x\n", Color);
4449 glClearColor(D3DCOLOR_R(Color),
4453 checkGLcall("glClearColor");
4455 /* Clear ALL colors! */
4456 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4457 glMask = glMask | GL_COLOR_BUFFER_BIT;
4461 /* In drawable flag is set below */
4463 if (This->render_offscreen) {
4464 glScissor(This->stateBlock->viewport.X,
4465 This->stateBlock->viewport.Y,
4466 This->stateBlock->viewport.Width,
4467 This->stateBlock->viewport.Height);
4469 glScissor(This->stateBlock->viewport.X,
4470 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4471 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4472 This->stateBlock->viewport.Width,
4473 This->stateBlock->viewport.Height);
4475 checkGLcall("glScissor");
4477 checkGLcall("glClear");
4479 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4480 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4482 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4483 curRect[0].x2 < target->currentDesc.Width ||
4484 curRect[0].y2 < target->currentDesc.Height) {
4485 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4486 blt_to_drawable(This, target);
4490 /* Now process each rect in turn */
4491 for (i = 0; i < Count; i++) {
4492 /* Note gl uses lower left, width/height */
4493 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4494 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4495 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4496 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4498 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4499 * The rectangle is not cleared, no error is returned, but further rectanlges are
4500 * still cleared if they are valid
4502 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4503 TRACE("Rectangle with negative dimensions, ignoring\n");
4507 if(This->render_offscreen) {
4508 glScissor(curRect[i].x1, curRect[i].y1,
4509 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4511 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4512 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4514 checkGLcall("glScissor");
4517 checkGLcall("glClear");
4521 /* Restore the old values (why..?) */
4522 if (Flags & WINED3DCLEAR_STENCIL) {
4523 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4525 if (Flags & WINED3DCLEAR_TARGET) {
4526 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4527 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4528 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4529 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4530 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4535 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4536 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4538 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4539 target->Flags |= SFLAG_INTEXTURE;
4540 target->Flags &= ~SFLAG_INSYSMEM;
4542 target->Flags |= SFLAG_INDRAWABLE;
4543 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4551 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4552 UINT PrimitiveCount) {
4554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4556 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4557 debug_d3dprimitivetype(PrimitiveType),
4558 StartVertex, PrimitiveCount);
4560 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4561 if(This->stateBlock->streamIsUP) {
4562 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4563 This->stateBlock->streamIsUP = FALSE;
4566 if(This->stateBlock->loadBaseVertexIndex != 0) {
4567 This->stateBlock->loadBaseVertexIndex = 0;
4568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4570 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4571 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4572 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4576 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4577 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4578 WINED3DPRIMITIVETYPE PrimitiveType,
4579 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4583 IWineD3DIndexBuffer *pIB;
4584 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4587 pIB = This->stateBlock->pIndexData;
4589 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4590 * without an index buffer set. (The first time at least...)
4591 * D3D8 simply dies, but I doubt it can do much harm to return
4592 * D3DERR_INVALIDCALL there as well. */
4593 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4594 return WINED3DERR_INVALIDCALL;
4597 if(This->stateBlock->streamIsUP) {
4598 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4599 This->stateBlock->streamIsUP = FALSE;
4601 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4603 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4604 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4605 minIndex, NumVertices, startIndex, primCount);
4607 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4608 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4614 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4615 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4619 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4620 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4625 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4626 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4627 UINT VertexStreamZeroStride) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4631 debug_d3dprimitivetype(PrimitiveType),
4632 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4634 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4635 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4636 This->stateBlock->streamOffset[0] = 0;
4637 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4638 This->stateBlock->streamIsUP = TRUE;
4639 This->stateBlock->loadBaseVertexIndex = 0;
4641 /* TODO: Only mark dirty if drawing from a different UP address */
4642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4644 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4645 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4647 /* MSDN specifies stream zero settings must be set to NULL */
4648 This->stateBlock->streamStride[0] = 0;
4649 This->stateBlock->streamSource[0] = NULL;
4651 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4652 * the new stream sources or use UP drawing again
4657 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4658 UINT MinVertexIndex, UINT NumVertices,
4659 UINT PrimitiveCount, CONST void* pIndexData,
4660 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4661 UINT VertexStreamZeroStride) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4665 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4666 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4667 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4668 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4670 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4676 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4677 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4678 This->stateBlock->streamIsUP = TRUE;
4679 This->stateBlock->streamOffset[0] = 0;
4680 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4682 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4683 This->stateBlock->baseVertexIndex = 0;
4684 This->stateBlock->loadBaseVertexIndex = 0;
4685 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4687 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4689 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4691 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4692 This->stateBlock->streamSource[0] = NULL;
4693 This->stateBlock->streamStride[0] = 0;
4694 This->stateBlock->pIndexData = NULL;
4695 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4696 * SetStreamSource to specify a vertex buffer
4702 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4705 /* Mark the state dirty until we have nicer tracking
4706 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4711 This->stateBlock->baseVertexIndex = 0;
4712 This->up_strided = DrawPrimStrideData;
4713 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4714 This->up_strided = NULL;
4718 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4720 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4722 /* Mark the state dirty until we have nicer tracking
4723 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4728 This->stateBlock->streamIsUP = TRUE;
4729 This->stateBlock->baseVertexIndex = 0;
4730 This->up_strided = DrawPrimStrideData;
4731 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4732 This->up_strided = NULL;
4737 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4738 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 HRESULT hr = WINED3D_OK;
4741 WINED3DRESOURCETYPE sourceType;
4742 WINED3DRESOURCETYPE destinationType;
4745 /* TODO: think about moving the code into IWineD3DBaseTexture */
4747 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4749 /* verify that the source and destination textures aren't NULL */
4750 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4751 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4752 This, pSourceTexture, pDestinationTexture);
4753 hr = WINED3DERR_INVALIDCALL;
4756 if (pSourceTexture == pDestinationTexture) {
4757 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4758 This, pSourceTexture, pDestinationTexture);
4759 hr = WINED3DERR_INVALIDCALL;
4761 /* Verify that the source and destination textures are the same type */
4762 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4763 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4765 if (sourceType != destinationType) {
4766 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4768 hr = WINED3DERR_INVALIDCALL;
4771 /* check that both textures have the identical numbers of levels */
4772 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4773 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4774 hr = WINED3DERR_INVALIDCALL;
4777 if (WINED3D_OK == hr) {
4779 /* Make sure that the destination texture is loaded */
4780 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4782 /* Update every surface level of the texture */
4783 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4785 switch (sourceType) {
4786 case WINED3DRTYPE_TEXTURE:
4788 IWineD3DSurface *srcSurface;
4789 IWineD3DSurface *destSurface;
4791 for (i = 0 ; i < levels ; ++i) {
4792 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4793 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4794 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4795 IWineD3DSurface_Release(srcSurface);
4796 IWineD3DSurface_Release(destSurface);
4797 if (WINED3D_OK != hr) {
4798 WARN("(%p) : Call to update surface failed\n", This);
4804 case WINED3DRTYPE_CUBETEXTURE:
4806 IWineD3DSurface *srcSurface;
4807 IWineD3DSurface *destSurface;
4808 WINED3DCUBEMAP_FACES faceType;
4810 for (i = 0 ; i < levels ; ++i) {
4811 /* Update each cube face */
4812 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4813 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4814 if (WINED3D_OK != hr) {
4815 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4817 TRACE("Got srcSurface %p\n", srcSurface);
4819 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4820 if (WINED3D_OK != hr) {
4821 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4823 TRACE("Got desrSurface %p\n", destSurface);
4825 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4826 IWineD3DSurface_Release(srcSurface);
4827 IWineD3DSurface_Release(destSurface);
4828 if (WINED3D_OK != hr) {
4829 WARN("(%p) : Call to update surface failed\n", This);
4836 #if 0 /* TODO: Add support for volume textures */
4837 case WINED3DRTYPE_VOLUMETEXTURE:
4839 IWineD3DVolume srcVolume = NULL;
4840 IWineD3DSurface destVolume = NULL;
4842 for (i = 0 ; i < levels ; ++i) {
4843 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4844 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4845 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4846 IWineD3DVolume_Release(srcSurface);
4847 IWineD3DVolume_Release(destSurface);
4848 if (WINED3D_OK != hr) {
4849 WARN("(%p) : Call to update volume failed\n", This);
4857 FIXME("(%p) : Unsupported source and destination type\n", This);
4858 hr = WINED3DERR_INVALIDCALL;
4865 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4866 IWineD3DSwapChain *swapChain;
4868 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4869 if(hr == WINED3D_OK) {
4870 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4871 IWineD3DSwapChain_Release(swapChain);
4876 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
4877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4878 /* return a sensible default */
4880 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
4881 FIXME("(%p) : stub\n", This);
4885 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
4886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4888 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4889 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4890 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4891 return WINED3DERR_INVALIDCALL;
4893 for (j = 0; j < 256; ++j) {
4894 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
4895 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
4896 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
4897 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
4899 TRACE("(%p) : returning\n", This);
4903 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
4904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4906 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4907 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4908 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4909 return WINED3DERR_INVALIDCALL;
4911 for (j = 0; j < 256; ++j) {
4912 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
4913 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
4914 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
4915 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
4917 TRACE("(%p) : returning\n", This);
4921 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
4922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4923 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
4924 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
4925 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
4926 return WINED3DERR_INVALIDCALL;
4928 /*TODO: stateblocks */
4929 This->currentPalette = PaletteNumber;
4930 TRACE("(%p) : returning\n", This);
4934 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4936 if (PaletteNumber == NULL) {
4937 WARN("(%p) : returning Invalid Call\n", This);
4938 return WINED3DERR_INVALIDCALL;
4940 /*TODO: stateblocks */
4941 *PaletteNumber = This->currentPalette;
4942 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
4946 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
4947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4948 static BOOL showFixmes = TRUE;
4950 FIXME("(%p) : stub\n", This);
4954 This->softwareVertexProcessing = bSoftware;
4959 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 static BOOL showFixmes = TRUE;
4963 FIXME("(%p) : stub\n", This);
4966 return This->softwareVertexProcessing;
4970 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
4971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4972 IWineD3DSwapChain *swapChain;
4975 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
4977 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4978 if(hr == WINED3D_OK){
4979 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
4980 IWineD3DSwapChain_Release(swapChain);
4982 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
4988 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
4989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4990 static BOOL showfixmes = TRUE;
4991 if(nSegments != 0.0f) {
4993 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5000 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5002 static BOOL showfixmes = TRUE;
5004 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5010 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5012 /** TODO: remove casts to IWineD3DSurfaceImpl
5013 * NOTE: move code to surface to accomplish this
5014 ****************************************/
5015 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5016 int srcWidth, srcHeight;
5017 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5018 WINED3DFORMAT destFormat, srcFormat;
5020 int srcLeft, destLeft, destTop;
5021 WINED3DPOOL srcPool, destPool;
5023 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5024 glDescriptor *glDescription = NULL;
5026 WINED3DSURFACE_DESC winedesc;
5028 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5029 memset(&winedesc, 0, sizeof(winedesc));
5030 winedesc.Width = &srcSurfaceWidth;
5031 winedesc.Height = &srcSurfaceHeight;
5032 winedesc.Pool = &srcPool;
5033 winedesc.Format = &srcFormat;
5035 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5037 winedesc.Width = &destSurfaceWidth;
5038 winedesc.Height = &destSurfaceHeight;
5039 winedesc.Pool = &destPool;
5040 winedesc.Format = &destFormat;
5041 winedesc.Size = &destSize;
5043 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5045 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5046 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5047 return WINED3DERR_INVALIDCALL;
5050 if (destFormat == WINED3DFMT_UNKNOWN) {
5051 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5052 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5054 /* Get the update surface description */
5055 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5058 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5062 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5063 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5064 checkGLcall("glActiveTextureARB");
5067 /* Make sure the surface is loaded and up to date */
5068 IWineD3DSurface_PreLoad(pDestinationSurface);
5070 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5072 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5073 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5074 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5075 srcLeft = pSourceRect ? pSourceRect->left : 0;
5076 destLeft = pDestPoint ? pDestPoint->x : 0;
5077 destTop = pDestPoint ? pDestPoint->y : 0;
5080 /* This function doesn't support compressed textures
5081 the pitch is just bytesPerPixel * width */
5082 if(srcWidth != srcSurfaceWidth || srcLeft ){
5083 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5084 offset += srcLeft * pSrcSurface->bytesPerPixel;
5085 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5087 /* TODO DXT formats */
5089 if(pSourceRect != NULL && pSourceRect->top != 0){
5090 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5092 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5094 ,glDescription->level
5099 ,glDescription->glFormat
5100 ,glDescription->glType
5101 ,IWineD3DSurface_GetData(pSourceSurface)
5105 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5107 /* need to lock the surface to get the data */
5108 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5111 /* TODO: Cube and volume support */
5113 /* not a whole row so we have to do it a line at a time */
5116 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5117 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5119 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5121 glTexSubImage2D(glDescription->target
5122 ,glDescription->level
5127 ,glDescription->glFormat
5128 ,glDescription->glType
5129 ,data /* could be quicker using */
5134 } else { /* Full width, so just write out the whole texture */
5136 if (WINED3DFMT_DXT1 == destFormat ||
5137 WINED3DFMT_DXT2 == destFormat ||
5138 WINED3DFMT_DXT3 == destFormat ||
5139 WINED3DFMT_DXT4 == destFormat ||
5140 WINED3DFMT_DXT5 == destFormat) {
5141 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5142 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5143 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5144 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5145 } if (destFormat != srcFormat) {
5146 FIXME("Updating mixed format compressed texture is not curretly support\n");
5148 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5149 glDescription->level,
5150 glDescription->glFormatInternal,
5155 IWineD3DSurface_GetData(pSourceSurface));
5158 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5163 glTexSubImage2D(glDescription->target
5164 ,glDescription->level
5169 ,glDescription->glFormat
5170 ,glDescription->glType
5171 ,IWineD3DSurface_GetData(pSourceSurface)
5175 checkGLcall("glTexSubImage2D");
5179 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5180 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5186 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5188 struct WineD3DRectPatch *patch;
5192 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5194 if(!(Handle || pRectPatchInfo)) {
5195 /* TODO: Write a test for the return value, thus the FIXME */
5196 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5197 return WINED3DERR_INVALIDCALL;
5201 i = PATCHMAP_HASHFUNC(Handle);
5203 LIST_FOR_EACH(e, &This->patches[i]) {
5204 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5205 if(patch->Handle == Handle) {
5212 TRACE("Patch does not exist. Creating a new one\n");
5213 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5214 patch->Handle = Handle;
5215 list_add_head(&This->patches[i], &patch->entry);
5217 TRACE("Found existing patch %p\n", patch);
5220 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5221 * attributes we have to tesselate, read back, and draw. This needs a patch
5222 * management structure instance. Create one.
5224 * A possible improvement is to check if a vertex shader is used, and if not directly
5227 FIXME("Drawing an uncached patch. This is slow\n");
5228 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5231 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5232 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5233 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5235 TRACE("Tesselation density or patch info changed, retesselating\n");
5237 if(pRectPatchInfo) {
5238 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5240 patch->numSegs[0] = pNumSegs[0];
5241 patch->numSegs[1] = pNumSegs[1];
5242 patch->numSegs[2] = pNumSegs[2];
5243 patch->numSegs[3] = pNumSegs[3];
5245 hr = tesselate_rectpatch(This, patch);
5247 WARN("Patch tesselation failed\n");
5249 /* Do not release the handle to store the params of the patch */
5251 HeapFree(GetProcessHeap(), 0, patch);
5257 This->currentPatch = patch;
5258 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5259 This->currentPatch = NULL;
5261 /* Destroy uncached patches */
5263 HeapFree(GetProcessHeap(), 0, patch->mem);
5264 HeapFree(GetProcessHeap(), 0, patch);
5269 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5270 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5272 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5273 FIXME("(%p) : Stub\n", This);
5277 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5280 struct WineD3DRectPatch *patch;
5282 TRACE("(%p) Handle(%d)\n", This, Handle);
5284 i = PATCHMAP_HASHFUNC(Handle);
5285 LIST_FOR_EACH(e, &This->patches[i]) {
5286 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5287 if(patch->Handle == Handle) {
5288 TRACE("Deleting patch %p\n", patch);
5289 list_remove(&patch->entry);
5290 HeapFree(GetProcessHeap(), 0, patch->mem);
5291 HeapFree(GetProcessHeap(), 0, patch);
5296 /* TODO: Write a test for the return value */
5297 FIXME("Attempt to destroy nonexistant patch\n");
5298 return WINED3DERR_INVALIDCALL;
5301 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5303 IWineD3DSwapChain *swapchain;
5305 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5306 if (SUCCEEDED(hr)) {
5307 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5314 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5318 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5319 checkGLcall("glGenFramebuffersEXT()");
5321 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5322 checkGLcall("glBindFramebuffer()");
5325 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5326 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5327 IWineD3DBaseTextureImpl *texture_impl;
5328 GLenum texttarget, target;
5331 texttarget = surface_impl->glDescription.target;
5332 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5333 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5335 IWineD3DSurface_PreLoad(surface);
5337 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5338 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5339 glBindTexture(target, old_binding);
5341 /* Update base texture states array */
5342 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5343 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5344 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5345 if (texture_impl->baseTexture.bindCount) {
5346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5349 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5352 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5354 checkGLcall("attach_surface_fbo");
5357 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5359 IWineD3DSwapChain *swapchain;
5361 swapchain = get_swapchain(surface);
5365 TRACE("Surface %p is onscreen\n", surface);
5367 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5368 buffer = surface_get_gl_buffer(surface, swapchain);
5369 glDrawBuffer(buffer);
5370 checkGLcall("glDrawBuffer()");
5372 TRACE("Surface %p is offscreen\n", surface);
5373 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5374 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5378 glEnable(GL_SCISSOR_TEST);
5380 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5382 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5383 rect->x2 - rect->x1, rect->y2 - rect->y1);
5385 checkGLcall("glScissor");
5387 glDisable(GL_SCISSOR_TEST);
5389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5391 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5394 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5395 glClear(GL_COLOR_BUFFER_BIT);
5396 checkGLcall("glClear");
5398 if (This->render_offscreen) {
5399 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5401 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5402 checkGLcall("glBindFramebuffer()");
5405 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5406 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5407 glDrawBuffer(GL_BACK);
5408 checkGLcall("glDrawBuffer()");
5412 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5414 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5416 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5418 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5419 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5420 return WINED3DERR_INVALIDCALL;
5423 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5424 color_fill_fbo(iface, pSurface, pRect, color);
5427 /* Just forward this to the DirectDraw blitting engine */
5428 memset(&BltFx, 0, sizeof(BltFx));
5429 BltFx.dwSize = sizeof(BltFx);
5430 BltFx.u5.dwFillColor = color;
5431 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5435 /* rendertarget and deptth stencil functions */
5436 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5439 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5440 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5441 return WINED3DERR_INVALIDCALL;
5444 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5445 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5446 /* Note inc ref on returned surface */
5447 if(*ppRenderTarget != NULL)
5448 IWineD3DSurface_AddRef(*ppRenderTarget);
5452 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5454 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5455 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5456 IWineD3DSwapChainImpl *Swapchain;
5459 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5461 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5462 if(hr != WINED3D_OK) {
5463 ERR("Can't get the swapchain\n");
5467 /* Make sure to release the swapchain */
5468 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5470 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5471 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5472 return WINED3DERR_INVALIDCALL;
5474 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5475 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5476 return WINED3DERR_INVALIDCALL;
5479 if(Swapchain->frontBuffer != Front) {
5480 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5482 if(Swapchain->frontBuffer)
5483 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5484 Swapchain->frontBuffer = Front;
5486 if(Swapchain->frontBuffer) {
5487 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5491 if(Back && !Swapchain->backBuffer) {
5492 /* We need memory for the back buffer array - only one back buffer this way */
5493 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5494 if(!Swapchain->backBuffer) {
5495 ERR("Out of memory\n");
5496 return E_OUTOFMEMORY;
5500 if(Swapchain->backBuffer[0] != Back) {
5501 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5503 /* What to do about the context here in the case of multithreading? Not sure.
5504 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5507 if(!Swapchain->backBuffer[0]) {
5508 /* GL was told to draw to the front buffer at creation,
5511 glDrawBuffer(GL_BACK);
5512 checkGLcall("glDrawBuffer(GL_BACK)");
5513 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5514 Swapchain->presentParms.BackBufferCount = 1;
5516 /* That makes problems - disable for now */
5517 /* glDrawBuffer(GL_FRONT); */
5518 checkGLcall("glDrawBuffer(GL_FRONT)");
5519 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5520 Swapchain->presentParms.BackBufferCount = 0;
5524 if(Swapchain->backBuffer[0])
5525 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5526 Swapchain->backBuffer[0] = Back;
5528 if(Swapchain->backBuffer[0]) {
5529 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5531 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5539 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5541 *ppZStencilSurface = This->depthStencilBuffer;
5542 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5544 if(*ppZStencilSurface != NULL) {
5545 /* Note inc ref on returned surface */
5546 IWineD3DSurface_AddRef(*ppZStencilSurface);
5551 /* TODO: Handle stencil attachments */
5552 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5554 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5556 TRACE("Set depth stencil to %p\n", depth_stencil);
5558 if (depth_stencil_impl) {
5559 if (depth_stencil_impl->current_renderbuffer) {
5560 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5561 checkGLcall("glFramebufferRenderbufferEXT()");
5563 IWineD3DBaseTextureImpl *texture_impl;
5564 GLenum texttarget, target;
5565 GLint old_binding = 0;
5567 texttarget = depth_stencil_impl->glDescription.target;
5568 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5569 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5571 IWineD3DSurface_PreLoad(depth_stencil);
5573 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5574 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5575 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5576 glBindTexture(target, old_binding);
5578 /* Update base texture states array */
5579 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5580 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5581 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5582 if (texture_impl->baseTexture.bindCount) {
5583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5586 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5589 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5590 checkGLcall("glFramebufferTexture2DEXT()");
5593 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5594 checkGLcall("glFramebufferTexture2DEXT()");
5598 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5600 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5602 TRACE("Set render target %u to %p\n", idx, render_target);
5605 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5606 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5608 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5609 checkGLcall("glFramebufferTexture2DEXT()");
5611 This->draw_buffers[idx] = GL_NONE;
5615 static void check_fbo_status(IWineD3DDevice *iface) {
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5619 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5620 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5621 TRACE("FBO complete\n");
5623 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5625 /* Dump the FBO attachments */
5626 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5627 IWineD3DSurfaceImpl *attachment;
5630 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5631 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5633 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5634 attachment->pow2Width, attachment->pow2Height);
5637 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5639 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5640 attachment->pow2Width, attachment->pow2Height);
5646 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5648 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5649 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5651 if (!ds_impl) return FALSE;
5653 if (ds_impl->current_renderbuffer) {
5654 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5655 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5658 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5659 rt_impl->pow2Height != ds_impl->pow2Height);
5662 void apply_fbo_state(IWineD3DDevice *iface) {
5663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5666 if (This->render_offscreen) {
5667 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5669 /* Apply render targets */
5670 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5671 IWineD3DSurface *render_target = This->render_targets[i];
5672 if (This->fbo_color_attachments[i] != render_target) {
5673 set_render_target_fbo(iface, i, render_target);
5674 This->fbo_color_attachments[i] = render_target;
5678 /* Apply depth targets */
5679 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5680 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5681 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5683 if (This->stencilBufferTarget) {
5684 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5686 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5687 This->fbo_depth_attachment = This->stencilBufferTarget;
5690 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5691 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5692 checkGLcall("glDrawBuffers()");
5694 glDrawBuffer(This->draw_buffers[0]);
5695 checkGLcall("glDrawBuffer()");
5698 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5701 check_fbo_status(iface);
5704 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5705 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5707 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5708 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5711 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5712 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5713 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5714 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5717 case WINED3DTEXF_LINEAR:
5718 gl_filter = GL_LINEAR;
5722 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5723 case WINED3DTEXF_NONE:
5724 case WINED3DTEXF_POINT:
5725 gl_filter = GL_NEAREST;
5729 /* Attach src surface to src fbo */
5730 src_swapchain = get_swapchain(src_surface);
5731 if (src_swapchain) {
5734 TRACE("Source surface %p is onscreen\n", src_surface);
5735 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5738 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5739 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5740 glReadBuffer(buffer);
5741 checkGLcall("glReadBuffer()");
5743 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5744 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5746 TRACE("Source surface %p is offscreen\n", src_surface);
5748 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5749 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5750 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5751 checkGLcall("glReadBuffer()");
5755 /* Attach dst surface to dst fbo */
5756 dst_swapchain = get_swapchain(dst_surface);
5757 if (dst_swapchain) {
5760 TRACE("Destination surface %p is onscreen\n", dst_surface);
5761 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5764 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5765 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5766 glDrawBuffer(buffer);
5767 checkGLcall("glDrawBuffer()");
5769 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5770 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5772 TRACE("Destination surface %p is offscreen\n", dst_surface);
5774 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5775 if(!src_swapchain) {
5776 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5780 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5781 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5782 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5783 checkGLcall("glDrawBuffer()");
5785 glDisable(GL_SCISSOR_TEST);
5786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5789 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5790 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5791 checkGLcall("glBlitFramebuffer()");
5793 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5794 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5795 checkGLcall("glBlitFramebuffer()");
5798 if (This->render_offscreen) {
5799 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5801 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5802 checkGLcall("glBindFramebuffer()");
5805 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5806 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5807 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5808 glDrawBuffer(GL_BACK);
5809 checkGLcall("glDrawBuffer()");
5814 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5816 WINED3DVIEWPORT viewport;
5818 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5820 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5821 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5822 return WINED3DERR_INVALIDCALL;
5825 /* MSDN says that null disables the render target
5826 but a device must always be associated with a render target
5827 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5829 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5832 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5833 FIXME("Trying to set render target 0 to NULL\n");
5834 return WINED3DERR_INVALIDCALL;
5836 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5837 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);
5838 return WINED3DERR_INVALIDCALL;
5841 /* If we are trying to set what we already have, don't bother */
5842 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5843 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5846 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5847 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5848 This->render_targets[RenderTargetIndex] = pRenderTarget;
5850 /* Render target 0 is special */
5851 if(RenderTargetIndex == 0) {
5852 /* Finally, reset the viewport as the MSDN states. */
5853 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5854 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5857 viewport.MaxZ = 1.0f;
5858 viewport.MinZ = 0.0f;
5859 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5860 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5861 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5863 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5865 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5867 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5868 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5870 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5875 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
5876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5877 HRESULT hr = WINED3D_OK;
5878 IWineD3DSurface *tmp;
5880 TRACE("(%p) Swapping z-buffer\n",This);
5882 if (pNewZStencil == This->stencilBufferTarget) {
5883 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5885 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
5886 * depending on the renter target implementation being used.
5887 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
5888 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
5889 * stencil buffer and incure an extra memory overhead
5890 ******************************************************/
5892 tmp = This->stencilBufferTarget;
5893 This->stencilBufferTarget = pNewZStencil;
5894 This->depth_copy_state = WINED3D_DCS_NO_COPY;
5895 /* should we be calling the parent or the wined3d surface? */
5896 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
5897 if (NULL != tmp) IWineD3DSurface_Release(tmp);
5900 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
5901 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
5902 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
5903 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
5904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5911 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
5912 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
5913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5914 /* TODO: the use of Impl is deprecated. */
5915 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
5916 WINED3DLOCKED_RECT lockedRect;
5918 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
5920 /* some basic validation checks */
5921 if(This->cursorTexture) {
5922 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5924 glDeleteTextures(1, &This->cursorTexture);
5926 This->cursorTexture = 0;
5929 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
5930 This->haveHardwareCursor = TRUE;
5932 This->haveHardwareCursor = FALSE;
5935 WINED3DLOCKED_RECT rect;
5937 /* MSDN: Cursor must be A8R8G8B8 */
5938 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
5939 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
5940 return WINED3DERR_INVALIDCALL;
5943 /* MSDN: Cursor must be smaller than the display mode */
5944 if(pSur->currentDesc.Width > This->ddraw_width ||
5945 pSur->currentDesc.Height > This->ddraw_height) {
5946 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);
5947 return WINED3DERR_INVALIDCALL;
5950 if (!This->haveHardwareCursor) {
5951 /* TODO: MSDN: Cursor sizes must be a power of 2 */
5953 /* Do not store the surface's pointer because the application may
5954 * release it after setting the cursor image. Windows doesn't
5955 * addref the set surface, so we can't do this either without
5956 * creating circular refcount dependencies. Copy out the gl texture
5959 This->cursorWidth = pSur->currentDesc.Width;
5960 This->cursorHeight = pSur->currentDesc.Height;
5961 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
5963 const GlPixelFormatDesc *glDesc;
5964 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
5965 char *mem, *bits = (char *)rect.pBits;
5966 GLint intfmt = glDesc->glInternal;
5967 GLint format = glDesc->glFormat;
5968 GLint type = glDesc->glType;
5969 INT height = This->cursorHeight;
5970 INT width = This->cursorWidth;
5971 INT bpp = tableEntry->bpp;
5974 /* Reformat the texture memory (pitch and width can be
5976 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
5977 for(i = 0; i < height; i++)
5978 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
5979 IWineD3DSurface_UnlockRect(pCursorBitmap);
5982 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
5983 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
5984 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
5987 /* Make sure that a proper texture unit is selected */
5988 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5989 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5990 checkGLcall("glActiveTextureARB");
5992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5993 /* Create a new cursor texture */
5994 glGenTextures(1, &This->cursorTexture);
5995 checkGLcall("glGenTextures");
5996 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
5997 checkGLcall("glBindTexture");
5998 /* Copy the bitmap memory into the cursor texture */
5999 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6000 HeapFree(GetProcessHeap(), 0, mem);
6001 checkGLcall("glTexImage2D");
6003 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6004 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6005 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6012 FIXME("A cursor texture was not returned.\n");
6013 This->cursorTexture = 0;
6018 /* Draw a hardware cursor */
6019 ICONINFO cursorInfo;
6021 /* Create and clear maskBits because it is not needed for
6022 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6024 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6025 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6026 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6027 WINED3DLOCK_NO_DIRTY_UPDATE |
6028 WINED3DLOCK_READONLY
6030 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6031 pSur->currentDesc.Height);
6033 cursorInfo.fIcon = FALSE;
6034 cursorInfo.xHotspot = XHotSpot;
6035 cursorInfo.yHotspot = YHotSpot;
6036 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6037 pSur->currentDesc.Height, 1,
6039 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6040 pSur->currentDesc.Height, 1,
6041 32, lockedRect.pBits);
6042 IWineD3DSurface_UnlockRect(pCursorBitmap);
6043 /* Create our cursor and clean up. */
6044 cursor = CreateIconIndirect(&cursorInfo);
6046 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6047 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6048 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6049 This->hardwareCursor = cursor;
6050 HeapFree(GetProcessHeap(), 0, maskBits);
6054 This->xHotSpot = XHotSpot;
6055 This->yHotSpot = YHotSpot;
6059 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6061 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6063 This->xScreenSpace = XScreenSpace;
6064 This->yScreenSpace = YScreenSpace;
6070 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6072 BOOL oldVisible = This->bCursorVisible;
6075 TRACE("(%p) : visible(%d)\n", This, bShow);
6078 * When ShowCursor is first called it should make the cursor appear at the OS's last
6079 * known cursor position. Because of this, some applications just repetitively call
6080 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6083 This->xScreenSpace = pt.x;
6084 This->yScreenSpace = pt.y;
6086 if (This->haveHardwareCursor) {
6087 This->bCursorVisible = bShow;
6089 SetCursor(This->hardwareCursor);
6095 if (This->cursorTexture)
6096 This->bCursorVisible = bShow;
6102 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6104 TRACE("(%p) : state (%u)\n", This, This->state);
6105 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6106 switch (This->state) {
6109 case WINED3DERR_DEVICELOST:
6111 ResourceList *resourceList = This->resources;
6112 while (NULL != resourceList) {
6113 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6114 return WINED3DERR_DEVICENOTRESET;
6115 resourceList = resourceList->next;
6117 return WINED3DERR_DEVICELOST;
6119 case WINED3DERR_DRIVERINTERNALERROR:
6120 return WINED3DERR_DRIVERINTERNALERROR;
6124 return WINED3DERR_DRIVERINTERNALERROR;
6128 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6130 /** FIXME: Resource tracking needs to be done,
6131 * The closes we can do to this is set the priorities of all managed textures low
6132 * and then reset them.
6133 ***********************************************************/
6134 FIXME("(%p) : stub\n", This);
6138 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6139 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6141 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6142 if(surface->Flags & SFLAG_DIBSECTION) {
6143 /* Release the DC */
6144 SelectObject(surface->hDC, surface->dib.holdbitmap);
6145 DeleteDC(surface->hDC);
6146 /* Release the DIB section */
6147 DeleteObject(surface->dib.DIBsection);
6148 surface->dib.bitmap_data = NULL;
6149 surface->resource.allocatedMemory = NULL;
6150 surface->Flags &= ~SFLAG_DIBSECTION;
6152 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6153 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6154 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6155 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6156 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6158 surface->pow2Width = surface->pow2Height = 1;
6159 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6160 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6162 if(surface->glDescription.textureName) {
6163 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6165 glDeleteTextures(1, &surface->glDescription.textureName);
6167 surface->glDescription.textureName = 0;
6168 surface->Flags &= ~SFLAG_CLIENT;
6170 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6171 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6172 surface->Flags |= SFLAG_NONPOW2;
6174 surface->Flags &= ~SFLAG_NONPOW2;
6176 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6177 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6180 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6182 IWineD3DSwapChainImpl *swapchain;
6184 BOOL DisplayModeChanged = FALSE;
6185 WINED3DDISPLAYMODE mode;
6186 TRACE("(%p)\n", This);
6188 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6190 ERR("Failed to get the first implicit swapchain\n");
6194 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6195 * on an existing gl context, so there's no real need for recreation.
6197 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6199 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6201 TRACE("New params:\n");
6202 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6203 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6204 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6205 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6206 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6207 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6208 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6209 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6210 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6211 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6212 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6213 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6214 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6216 /* No special treatment of these parameters. Just store them */
6217 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6218 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6219 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6220 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6222 /* What to do about these? */
6223 if(pPresentationParameters->BackBufferCount != 0 &&
6224 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6225 ERR("Cannot change the back buffer count yet\n");
6227 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6228 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6229 ERR("Cannot change the back buffer format yet\n");
6231 if(pPresentationParameters->hDeviceWindow != NULL &&
6232 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6233 ERR("Cannot change the device window yet\n");
6235 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6236 ERR("What do do about a changed auto depth stencil parameter?\n");
6239 if(pPresentationParameters->Windowed) {
6240 mode.Width = swapchain->orig_width;
6241 mode.Height = swapchain->orig_height;
6242 mode.RefreshRate = 0;
6243 mode.Format = swapchain->presentParms.BackBufferFormat;
6245 mode.Width = pPresentationParameters->BackBufferWidth;
6246 mode.Height = pPresentationParameters->BackBufferHeight;
6247 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6248 mode.Format = swapchain->presentParms.BackBufferFormat;
6251 /* Should Width == 800 && Height == 0 set 800x600? */
6252 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6253 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6254 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6261 vp.Width = pPresentationParameters->BackBufferWidth;
6262 vp.Height = pPresentationParameters->BackBufferHeight;
6266 if(!pPresentationParameters->Windowed) {
6267 DisplayModeChanged = TRUE;
6269 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6270 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6272 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6273 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6274 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6277 /* Now set the new viewport */
6278 IWineD3DDevice_SetViewport(iface, &vp);
6281 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6282 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6283 DisplayModeChanged) {
6285 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6286 if(!pPresentationParameters->Windowed) {
6287 IWineD3DDevice_SetFullscreen(iface, TRUE);
6290 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6292 /* Switching out of fullscreen mode? First set the original res, then change the window */
6293 if(pPresentationParameters->Windowed) {
6294 IWineD3DDevice_SetFullscreen(iface, FALSE);
6296 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6299 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6303 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6305 /** FIXME: always true at the moment **/
6306 if(!bEnableDialogs) {
6307 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6313 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6315 TRACE("(%p) : pParameters %p\n", This, pParameters);
6317 *pParameters = This->createParms;
6321 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6322 IWineD3DSwapChain *swapchain;
6323 HRESULT hrc = WINED3D_OK;
6325 TRACE("Relaying to swapchain\n");
6327 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6328 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6329 IWineD3DSwapChain_Release(swapchain);
6334 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6335 IWineD3DSwapChain *swapchain;
6336 HRESULT hrc = WINED3D_OK;
6338 TRACE("Relaying to swapchain\n");
6340 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6341 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6342 IWineD3DSwapChain_Release(swapchain);
6348 /** ********************************************************
6349 * Notification functions
6350 ** ********************************************************/
6351 /** This function must be called in the release of a resource when ref == 0,
6352 * the contents of resource must still be correct,
6353 * any handels to other resource held by the caller must be closed
6354 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6355 *****************************************************/
6356 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6358 ResourceList* resourceList;
6360 TRACE("(%p) : resource %p\n", This, resource);
6361 /* add a new texture to the frot of the linked list */
6362 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6363 resourceList->resource = resource;
6365 /* Get the old head */
6366 resourceList->next = This->resources;
6368 This->resources = resourceList;
6369 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6374 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6376 ResourceList* resourceList = NULL;
6377 ResourceList* previousResourceList = NULL;
6379 TRACE("(%p) : resource %p\n", This, resource);
6381 resourceList = This->resources;
6383 while (resourceList != NULL) {
6384 if(resourceList->resource == resource) break;
6385 previousResourceList = resourceList;
6386 resourceList = resourceList->next;
6389 if (resourceList == NULL) {
6390 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6393 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6395 /* make sure we don't leave a hole in the list */
6396 if (previousResourceList != NULL) {
6397 previousResourceList->next = resourceList->next;
6399 This->resources = resourceList->next;
6406 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6410 TRACE("(%p) : resource %p\n", This, resource);
6411 switch(IWineD3DResource_GetType(resource)){
6412 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6413 case WINED3DRTYPE_SURFACE: {
6416 /* Cleanup any FBO attachments if d3d is enabled */
6417 if(This->d3d_initialized) {
6418 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6419 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6420 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6421 set_render_target_fbo(iface, i, NULL);
6422 This->fbo_color_attachments[i] = NULL;
6425 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6426 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6427 set_depth_stencil_fbo(iface, NULL);
6428 This->fbo_depth_attachment = NULL;
6434 case WINED3DRTYPE_TEXTURE:
6435 case WINED3DRTYPE_CUBETEXTURE:
6436 case WINED3DRTYPE_VOLUMETEXTURE:
6437 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6438 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6439 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6440 This->stateBlock->textures[counter] = NULL;
6442 if (This->updateStateBlock != This->stateBlock ){
6443 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6444 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6445 This->updateStateBlock->textures[counter] = NULL;
6450 case WINED3DRTYPE_VOLUME:
6451 /* TODO: nothing really? */
6453 case WINED3DRTYPE_VERTEXBUFFER:
6454 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6457 TRACE("Cleaning up stream pointers\n");
6459 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6460 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6461 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6463 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6464 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6465 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6466 This->updateStateBlock->streamSource[streamNumber] = 0;
6467 /* Set changed flag? */
6470 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) */
6471 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6472 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6473 This->stateBlock->streamSource[streamNumber] = 0;
6476 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6477 else { /* This shouldn't happen */
6478 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6485 case WINED3DRTYPE_INDEXBUFFER:
6486 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6487 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6488 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6489 This->updateStateBlock->pIndexData = NULL;
6492 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6493 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6494 This->stateBlock->pIndexData = NULL;
6500 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6505 /* Remove the resoruce from the resourceStore */
6506 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6508 TRACE("Resource released\n");
6512 /**********************************************************
6513 * IWineD3DDevice VTbl follows
6514 **********************************************************/
6516 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6518 /*** IUnknown methods ***/
6519 IWineD3DDeviceImpl_QueryInterface,
6520 IWineD3DDeviceImpl_AddRef,
6521 IWineD3DDeviceImpl_Release,
6522 /*** IWineD3DDevice methods ***/
6523 IWineD3DDeviceImpl_GetParent,
6524 /*** Creation methods**/
6525 IWineD3DDeviceImpl_CreateVertexBuffer,
6526 IWineD3DDeviceImpl_CreateIndexBuffer,
6527 IWineD3DDeviceImpl_CreateStateBlock,
6528 IWineD3DDeviceImpl_CreateSurface,
6529 IWineD3DDeviceImpl_CreateTexture,
6530 IWineD3DDeviceImpl_CreateVolumeTexture,
6531 IWineD3DDeviceImpl_CreateVolume,
6532 IWineD3DDeviceImpl_CreateCubeTexture,
6533 IWineD3DDeviceImpl_CreateQuery,
6534 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6535 IWineD3DDeviceImpl_CreateVertexDeclaration,
6536 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6537 IWineD3DDeviceImpl_CreateVertexShader,
6538 IWineD3DDeviceImpl_CreatePixelShader,
6539 IWineD3DDeviceImpl_CreatePalette,
6540 /*** Odd functions **/
6541 IWineD3DDeviceImpl_Init3D,
6542 IWineD3DDeviceImpl_Uninit3D,
6543 IWineD3DDeviceImpl_SetFullscreen,
6544 IWineD3DDeviceImpl_SetMultithreaded,
6545 IWineD3DDeviceImpl_EvictManagedResources,
6546 IWineD3DDeviceImpl_GetAvailableTextureMem,
6547 IWineD3DDeviceImpl_GetBackBuffer,
6548 IWineD3DDeviceImpl_GetCreationParameters,
6549 IWineD3DDeviceImpl_GetDeviceCaps,
6550 IWineD3DDeviceImpl_GetDirect3D,
6551 IWineD3DDeviceImpl_GetDisplayMode,
6552 IWineD3DDeviceImpl_SetDisplayMode,
6553 IWineD3DDeviceImpl_GetHWND,
6554 IWineD3DDeviceImpl_SetHWND,
6555 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6556 IWineD3DDeviceImpl_GetRasterStatus,
6557 IWineD3DDeviceImpl_GetSwapChain,
6558 IWineD3DDeviceImpl_Reset,
6559 IWineD3DDeviceImpl_SetDialogBoxMode,
6560 IWineD3DDeviceImpl_SetCursorProperties,
6561 IWineD3DDeviceImpl_SetCursorPosition,
6562 IWineD3DDeviceImpl_ShowCursor,
6563 IWineD3DDeviceImpl_TestCooperativeLevel,
6564 /*** Getters and setters **/
6565 IWineD3DDeviceImpl_SetClipPlane,
6566 IWineD3DDeviceImpl_GetClipPlane,
6567 IWineD3DDeviceImpl_SetClipStatus,
6568 IWineD3DDeviceImpl_GetClipStatus,
6569 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6570 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6571 IWineD3DDeviceImpl_SetDepthStencilSurface,
6572 IWineD3DDeviceImpl_GetDepthStencilSurface,
6573 IWineD3DDeviceImpl_SetFVF,
6574 IWineD3DDeviceImpl_GetFVF,
6575 IWineD3DDeviceImpl_SetGammaRamp,
6576 IWineD3DDeviceImpl_GetGammaRamp,
6577 IWineD3DDeviceImpl_SetIndices,
6578 IWineD3DDeviceImpl_GetIndices,
6579 IWineD3DDeviceImpl_SetBaseVertexIndex,
6580 IWineD3DDeviceImpl_GetBaseVertexIndex,
6581 IWineD3DDeviceImpl_SetLight,
6582 IWineD3DDeviceImpl_GetLight,
6583 IWineD3DDeviceImpl_SetLightEnable,
6584 IWineD3DDeviceImpl_GetLightEnable,
6585 IWineD3DDeviceImpl_SetMaterial,
6586 IWineD3DDeviceImpl_GetMaterial,
6587 IWineD3DDeviceImpl_SetNPatchMode,
6588 IWineD3DDeviceImpl_GetNPatchMode,
6589 IWineD3DDeviceImpl_SetPaletteEntries,
6590 IWineD3DDeviceImpl_GetPaletteEntries,
6591 IWineD3DDeviceImpl_SetPixelShader,
6592 IWineD3DDeviceImpl_GetPixelShader,
6593 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6594 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6595 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6596 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6597 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6598 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6599 IWineD3DDeviceImpl_SetRenderState,
6600 IWineD3DDeviceImpl_GetRenderState,
6601 IWineD3DDeviceImpl_SetRenderTarget,
6602 IWineD3DDeviceImpl_GetRenderTarget,
6603 IWineD3DDeviceImpl_SetFrontBackBuffers,
6604 IWineD3DDeviceImpl_SetSamplerState,
6605 IWineD3DDeviceImpl_GetSamplerState,
6606 IWineD3DDeviceImpl_SetScissorRect,
6607 IWineD3DDeviceImpl_GetScissorRect,
6608 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6609 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6610 IWineD3DDeviceImpl_SetStreamSource,
6611 IWineD3DDeviceImpl_GetStreamSource,
6612 IWineD3DDeviceImpl_SetStreamSourceFreq,
6613 IWineD3DDeviceImpl_GetStreamSourceFreq,
6614 IWineD3DDeviceImpl_SetTexture,
6615 IWineD3DDeviceImpl_GetTexture,
6616 IWineD3DDeviceImpl_SetTextureStageState,
6617 IWineD3DDeviceImpl_GetTextureStageState,
6618 IWineD3DDeviceImpl_SetTransform,
6619 IWineD3DDeviceImpl_GetTransform,
6620 IWineD3DDeviceImpl_SetVertexDeclaration,
6621 IWineD3DDeviceImpl_GetVertexDeclaration,
6622 IWineD3DDeviceImpl_SetVertexShader,
6623 IWineD3DDeviceImpl_GetVertexShader,
6624 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6625 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6626 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6627 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6628 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6629 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6630 IWineD3DDeviceImpl_SetViewport,
6631 IWineD3DDeviceImpl_GetViewport,
6632 IWineD3DDeviceImpl_MultiplyTransform,
6633 IWineD3DDeviceImpl_ValidateDevice,
6634 IWineD3DDeviceImpl_ProcessVertices,
6635 /*** State block ***/
6636 IWineD3DDeviceImpl_BeginStateBlock,
6637 IWineD3DDeviceImpl_EndStateBlock,
6638 /*** Scene management ***/
6639 IWineD3DDeviceImpl_BeginScene,
6640 IWineD3DDeviceImpl_EndScene,
6641 IWineD3DDeviceImpl_Present,
6642 IWineD3DDeviceImpl_Clear,
6644 IWineD3DDeviceImpl_DrawPrimitive,
6645 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6646 IWineD3DDeviceImpl_DrawPrimitiveUP,
6647 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6648 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6649 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6650 IWineD3DDeviceImpl_DrawRectPatch,
6651 IWineD3DDeviceImpl_DrawTriPatch,
6652 IWineD3DDeviceImpl_DeletePatch,
6653 IWineD3DDeviceImpl_ColorFill,
6654 IWineD3DDeviceImpl_UpdateTexture,
6655 IWineD3DDeviceImpl_UpdateSurface,
6656 IWineD3DDeviceImpl_GetFrontBufferData,
6657 /*** object tracking ***/
6658 IWineD3DDeviceImpl_ResourceReleased
6662 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6663 WINED3DRS_ALPHABLENDENABLE ,
6664 WINED3DRS_ALPHAFUNC ,
6665 WINED3DRS_ALPHAREF ,
6666 WINED3DRS_ALPHATESTENABLE ,
6668 WINED3DRS_COLORWRITEENABLE ,
6669 WINED3DRS_DESTBLEND ,
6670 WINED3DRS_DITHERENABLE ,
6671 WINED3DRS_FILLMODE ,
6672 WINED3DRS_FOGDENSITY ,
6674 WINED3DRS_FOGSTART ,
6675 WINED3DRS_LASTPIXEL ,
6676 WINED3DRS_SHADEMODE ,
6677 WINED3DRS_SRCBLEND ,
6678 WINED3DRS_STENCILENABLE ,
6679 WINED3DRS_STENCILFAIL ,
6680 WINED3DRS_STENCILFUNC ,
6681 WINED3DRS_STENCILMASK ,
6682 WINED3DRS_STENCILPASS ,
6683 WINED3DRS_STENCILREF ,
6684 WINED3DRS_STENCILWRITEMASK ,
6685 WINED3DRS_STENCILZFAIL ,
6686 WINED3DRS_TEXTUREFACTOR ,
6697 WINED3DRS_ZWRITEENABLE
6700 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6701 WINED3DTSS_ADDRESSW ,
6702 WINED3DTSS_ALPHAARG0 ,
6703 WINED3DTSS_ALPHAARG1 ,
6704 WINED3DTSS_ALPHAARG2 ,
6705 WINED3DTSS_ALPHAOP ,
6706 WINED3DTSS_BUMPENVLOFFSET ,
6707 WINED3DTSS_BUMPENVLSCALE ,
6708 WINED3DTSS_BUMPENVMAT00 ,
6709 WINED3DTSS_BUMPENVMAT01 ,
6710 WINED3DTSS_BUMPENVMAT10 ,
6711 WINED3DTSS_BUMPENVMAT11 ,
6712 WINED3DTSS_COLORARG0 ,
6713 WINED3DTSS_COLORARG1 ,
6714 WINED3DTSS_COLORARG2 ,
6715 WINED3DTSS_COLOROP ,
6716 WINED3DTSS_RESULTARG ,
6717 WINED3DTSS_TEXCOORDINDEX ,
6718 WINED3DTSS_TEXTURETRANSFORMFLAGS
6721 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6722 WINED3DSAMP_ADDRESSU ,
6723 WINED3DSAMP_ADDRESSV ,
6724 WINED3DSAMP_ADDRESSW ,
6725 WINED3DSAMP_BORDERCOLOR ,
6726 WINED3DSAMP_MAGFILTER ,
6727 WINED3DSAMP_MINFILTER ,
6728 WINED3DSAMP_MIPFILTER ,
6729 WINED3DSAMP_MIPMAPLODBIAS ,
6730 WINED3DSAMP_MAXMIPLEVEL ,
6731 WINED3DSAMP_MAXANISOTROPY ,
6732 WINED3DSAMP_SRGBTEXTURE ,
6733 WINED3DSAMP_ELEMENTINDEX
6736 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6738 WINED3DRS_AMBIENTMATERIALSOURCE ,
6739 WINED3DRS_CLIPPING ,
6740 WINED3DRS_CLIPPLANEENABLE ,
6741 WINED3DRS_COLORVERTEX ,
6742 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6743 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6744 WINED3DRS_FOGDENSITY ,
6746 WINED3DRS_FOGSTART ,
6747 WINED3DRS_FOGTABLEMODE ,
6748 WINED3DRS_FOGVERTEXMODE ,
6749 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6750 WINED3DRS_LIGHTING ,
6751 WINED3DRS_LOCALVIEWER ,
6752 WINED3DRS_MULTISAMPLEANTIALIAS ,
6753 WINED3DRS_MULTISAMPLEMASK ,
6754 WINED3DRS_NORMALIZENORMALS ,
6755 WINED3DRS_PATCHEDGESTYLE ,
6756 WINED3DRS_POINTSCALE_A ,
6757 WINED3DRS_POINTSCALE_B ,
6758 WINED3DRS_POINTSCALE_C ,
6759 WINED3DRS_POINTSCALEENABLE ,
6760 WINED3DRS_POINTSIZE ,
6761 WINED3DRS_POINTSIZE_MAX ,
6762 WINED3DRS_POINTSIZE_MIN ,
6763 WINED3DRS_POINTSPRITEENABLE ,
6764 WINED3DRS_RANGEFOGENABLE ,
6765 WINED3DRS_SPECULARMATERIALSOURCE ,
6766 WINED3DRS_TWEENFACTOR ,
6767 WINED3DRS_VERTEXBLEND
6770 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6771 WINED3DTSS_TEXCOORDINDEX ,
6772 WINED3DTSS_TEXTURETRANSFORMFLAGS
6775 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6776 WINED3DSAMP_DMAPOFFSET
6779 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6780 DWORD rep = StateTable[state].representative;
6784 WineD3DContext *context;
6787 for(i = 0; i < This->numContexts; i++) {
6788 context = This->contexts[i];
6789 if(isStateDirty(context, rep)) continue;
6791 context->dirtyArray[context->numDirtyEntries++] = rep;
6794 context->isStateDirty[idx] |= (1 << shift);