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;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 for(i = 0; i < MAX_STREAMS; i++) {
518 if(object->streamSource[i]) {
519 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
522 if(object->pIndexData) {
523 IWineD3DIndexBuffer_AddRef(object->pIndexData);
525 if(object->vertexShader) {
526 IWineD3DVertexShader_AddRef(object->vertexShader);
528 if(object->pixelShader) {
529 IWineD3DPixelShader_AddRef(object->pixelShader);
532 } else if (Type == WINED3DSBT_PIXELSTATE) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.pixelShader = TRUE;
539 /* Pixel Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541 object->contained_ps_consts_f[i] = i;
542 object->changed.pixelShaderConstantsF[i] = TRUE;
544 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545 for (i = 0; i < MAX_CONST_B; ++i) {
546 object->contained_ps_consts_b[i] = i;
547 object->changed.pixelShaderConstantsB[i] = TRUE;
549 object->num_contained_ps_consts_b = MAX_CONST_B;
550 for (i = 0; i < MAX_CONST_I; ++i) {
551 object->contained_ps_consts_i[i] = i;
552 object->changed.pixelShaderConstantsI[i] = TRUE;
554 object->num_contained_ps_consts_i = MAX_CONST_I;
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558 object->contained_render_states[i] = SavedPixelStates_R[i];
560 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561 for (j = 0; j < MAX_TEXTURES; j++) {
562 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566 object->num_contained_tss_states++;
569 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574 object->num_contained_sampler_states++;
577 if(object->pixelShader) {
578 IWineD3DPixelShader_AddRef(object->pixelShader);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i = 0; i < MAX_STREAMS; i++) {
585 object->streamSource[i] = NULL;
587 object->pIndexData = NULL;
588 object->vertexShader = NULL;
590 } else if (Type == WINED3DSBT_VERTEXSTATE) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
595 object->changed.vertexShader = TRUE;
597 /* Vertex Shader Constants */
598 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599 object->changed.vertexShaderConstantsF[i] = TRUE;
600 object->contained_vs_consts_f[i] = i;
602 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603 for (i = 0; i < MAX_CONST_B; ++i) {
604 object->changed.vertexShaderConstantsB[i] = TRUE;
605 object->contained_vs_consts_b[i] = i;
607 object->num_contained_vs_consts_b = MAX_CONST_B;
608 for (i = 0; i < MAX_CONST_I; ++i) {
609 object->changed.vertexShaderConstantsI[i] = TRUE;
610 object->contained_vs_consts_i[i] = i;
612 object->num_contained_vs_consts_i = MAX_CONST_I;
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 object->contained_render_states[i] = SavedVertexStates_R[i];
617 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618 for (j = 0; j < MAX_TEXTURES; j++) {
619 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623 object->num_contained_tss_states++;
626 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631 object->num_contained_sampler_states++;
635 for(j = 0; j < LIGHTMAP_SIZE; j++) {
637 LIST_FOR_EACH(e, &object->lightMap[j]) {
638 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639 light->changed = TRUE;
640 light->enabledChanged = TRUE;
644 for(i = 0; i < MAX_STREAMS; i++) {
645 if(object->streamSource[i]) {
646 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
649 if(object->vertexShader) {
650 IWineD3DVertexShader_AddRef(object->vertexShader);
652 object->pIndexData = NULL;
653 object->pixelShader = NULL;
655 FIXME("Unrecognized state block type %d\n", Type);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
662 /* ************************************
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 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.
671 ******************************** */
673 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) {
674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
675 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size = 1;
677 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678 TRACE("(%p) Create surface\n",This);
680 /** FIXME: Check ranges on the inputs are valid
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
688 *******************************/
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality < 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality);
704 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
707 if(MultisampleQuality > 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709 MultisampleQuality=0;
712 /** FIXME: Check that the format is supported
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
719 *********************************/
720 if (WINED3DFMT_UNKNOWN == Format) {
722 } else if (Format == WINED3DFMT_DXT1) {
723 /* DXT1 is half byte per pixel */
724 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
726 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
730 /* The pitch is a multiple of 4 bytes */
731 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
740 object->currentDesc.Width = Width;
741 object->currentDesc.Height = Height;
742 object->currentDesc.MultiSampleType = MultiSample;
743 object->currentDesc.MultiSampleQuality = MultisampleQuality;
744 object->glDescription.level = Level;
748 object->Flags |= Discard ? SFLAG_DISCARD : 0;
749 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
753 if (WINED3DFMT_UNKNOWN != Format) {
754 object->bytesPerPixel = tableEntry->bpp;
756 object->bytesPerPixel = 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
768 case WINED3DPOOL_SCRATCH:
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
774 case WINED3DPOOL_SYSTEMMEM:
775 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED:
778 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
782 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
788 FIXME("(%p) Unknown pool %d\n", This, Pool);
792 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This, Width, Height, Format, debug_d3dformat(Format),
800 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804 This->ddraw_primary = (IWineD3DSurface *) object;
806 /* Look at the implementation and set the correct Vtable */
809 /* Check if a 3D adapter is available when creating gl surfaces */
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813 HeapFree(GetProcessHeap(), 0, object);
814 return WINED3DERR_NOTAVAILABLE;
819 object->lpVtbl = &IWineGDISurface_Vtbl;
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl);
825 IWineD3DSurface_Release((IWineD3DSurface *) object);
826 return WINED3DERR_INVALIDCALL;
829 list_init(&object->renderbuffers);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842 IWineD3DTextureImpl *object;
847 unsigned int pow2Width;
848 unsigned int pow2Height;
851 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
852 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
853 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
855 /* TODO: It should only be possible to create textures for formats
856 that are reported as supported */
857 if (WINED3DFMT_UNKNOWN >= Format) {
858 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
859 return WINED3DERR_INVALIDCALL;
862 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
863 D3DINITIALIZEBASETEXTURE(object->baseTexture);
864 object->width = Width;
865 object->height = Height;
867 /** Non-power2 support **/
868 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
872 /* Find the nearest pow2 match */
873 pow2Width = pow2Height = 1;
874 while (pow2Width < Width) pow2Width <<= 1;
875 while (pow2Height < Height) pow2Height <<= 1;
878 /** FIXME: add support for real non-power-two if it's provided by the video card **/
879 /* Precalculated scaling for 'faked' non power of two texture coords */
880 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
881 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
882 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
884 /* Calculate levels for mip mapping */
885 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
886 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
887 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
888 return WINED3DERR_INVALIDCALL;
891 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
892 return WINED3DERR_INVALIDCALL;
894 object->baseTexture.levels = 1;
895 } else if (Levels == 0) {
896 TRACE("calculating levels %d\n", object->baseTexture.levels);
897 object->baseTexture.levels++;
900 while (tmpW > 1 || tmpH > 1) {
901 tmpW = max(1, tmpW >> 1);
902 tmpH = max(1, tmpH >> 1);
903 object->baseTexture.levels++;
905 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
908 /* Generate all the surfaces */
911 for (i = 0; i < object->baseTexture.levels; i++)
913 /* use the callback to create the texture surface */
914 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
915 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
916 FIXME("Failed to create surface %p\n", object);
918 object->surfaces[i] = NULL;
919 IWineD3DTexture_Release((IWineD3DTexture *)object);
925 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
926 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
927 /* calculate the next mipmap level */
928 tmpW = max(1, tmpW >> 1);
929 tmpH = max(1, tmpH >> 1);
932 TRACE("(%p) : Created texture %p\n", This, object);
936 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
937 UINT Width, UINT Height, UINT Depth,
938 UINT Levels, DWORD Usage,
939 WINED3DFORMAT Format, WINED3DPOOL Pool,
940 IWineD3DVolumeTexture **ppVolumeTexture,
941 HANDLE *pSharedHandle, IUnknown *parent,
942 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
945 IWineD3DVolumeTextureImpl *object;
951 /* TODO: It should only be possible to create textures for formats
952 that are reported as supported */
953 if (WINED3DFMT_UNKNOWN >= Format) {
954 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
955 return WINED3DERR_INVALIDCALL;
958 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
959 D3DINITIALIZEBASETEXTURE(object->baseTexture);
961 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
962 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
964 object->width = Width;
965 object->height = Height;
966 object->depth = Depth;
968 /* Calculate levels for mip mapping */
969 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
970 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
971 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
972 return WINED3DERR_INVALIDCALL;
975 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
976 return WINED3DERR_INVALIDCALL;
979 } else if (Levels == 0) {
980 object->baseTexture.levels++;
984 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
985 tmpW = max(1, tmpW >> 1);
986 tmpH = max(1, tmpH >> 1);
987 tmpD = max(1, tmpD >> 1);
988 object->baseTexture.levels++;
990 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
993 /* Generate all the surfaces */
998 for (i = 0; i < object->baseTexture.levels; i++)
1001 /* Create the volume */
1002 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1003 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1006 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1007 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1008 *ppVolumeTexture = NULL;
1012 /* Set its container to this object */
1013 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1015 /* calcualte the next mipmap level */
1016 tmpW = max(1, tmpW >> 1);
1017 tmpH = max(1, tmpH >> 1);
1018 tmpD = max(1, tmpD >> 1);
1021 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1022 TRACE("(%p) : Created volume texture %p\n", This, object);
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1027 UINT Width, UINT Height, UINT Depth,
1029 WINED3DFORMAT Format, WINED3DPOOL Pool,
1030 IWineD3DVolume** ppVolume,
1031 HANDLE* pSharedHandle, IUnknown *parent) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1035 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1037 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1039 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1040 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1042 object->currentDesc.Width = Width;
1043 object->currentDesc.Height = Height;
1044 object->currentDesc.Depth = Depth;
1045 object->bytesPerPixel = formatDesc->bpp;
1047 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1048 object->lockable = TRUE;
1049 object->locked = FALSE;
1050 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1051 object->dirty = TRUE;
1053 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1056 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1057 UINT Levels, DWORD Usage,
1058 WINED3DFORMAT Format, WINED3DPOOL Pool,
1059 IWineD3DCubeTexture **ppCubeTexture,
1060 HANDLE *pSharedHandle, IUnknown *parent,
1061 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1064 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1068 unsigned int pow2EdgeLength = EdgeLength;
1070 /* TODO: It should only be possible to create textures for formats
1071 that are reported as supported */
1072 if (WINED3DFMT_UNKNOWN >= Format) {
1073 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1074 return WINED3DERR_INVALIDCALL;
1077 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1078 WARN("(%p) : Tried to create not supported cube texture\n", This);
1079 return WINED3DERR_INVALIDCALL;
1082 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1083 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1085 TRACE("(%p) Create Cube Texture\n", This);
1087 /** Non-power2 support **/
1089 /* Find the nearest pow2 match */
1091 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1093 object->edgeLength = EdgeLength;
1094 /* TODO: support for native non-power 2 */
1095 /* Precalculated scaling for 'faked' non power of two texture coords */
1096 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 /* Calculate levels for mip mapping */
1099 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1100 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1101 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1102 return WINED3DERR_INVALIDCALL;
1105 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1106 return WINED3DERR_INVALIDCALL;
1109 } else if (Levels == 0) {
1110 object->baseTexture.levels++;
1113 tmpW = max(1, tmpW >> 1);
1114 object->baseTexture.levels++;
1116 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1119 /* Generate all the surfaces */
1121 for (i = 0; i < object->baseTexture.levels; i++) {
1123 /* Create the 6 faces */
1124 for (j = 0; j < 6; j++) {
1126 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1127 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1129 if(hr!= WINED3D_OK) {
1133 for (l = 0; l < j; l++) {
1134 IWineD3DSurface_Release(object->surfaces[j][i]);
1136 for (k = 0; k < i; k++) {
1137 for (l = 0; l < 6; l++) {
1138 IWineD3DSurface_Release(object->surfaces[l][j]);
1142 FIXME("(%p) Failed to create surface\n",object);
1143 HeapFree(GetProcessHeap(),0,object);
1144 *ppCubeTexture = NULL;
1147 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1148 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1150 tmpW = max(1, tmpW >> 1);
1153 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1154 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1158 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1160 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1161 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1163 /* Just a check to see if we support this type of query */
1165 case WINED3DQUERYTYPE_OCCLUSION:
1166 TRACE("(%p) occlusion query\n", This);
1167 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1170 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1173 case WINED3DQUERYTYPE_EVENT:
1174 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1175 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1176 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1178 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1183 case WINED3DQUERYTYPE_VCACHE:
1184 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1185 case WINED3DQUERYTYPE_VERTEXSTATS:
1186 case WINED3DQUERYTYPE_TIMESTAMP:
1187 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1188 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1189 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1190 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1191 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1192 case WINED3DQUERYTYPE_PIXELTIMINGS:
1193 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1194 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1196 FIXME("(%p) Unhandled query type %d\n", This, Type);
1198 if(NULL == ppQuery || hr != WINED3D_OK) {
1202 D3DCREATEOBJECTINSTANCE(object, Query)
1203 object->type = Type;
1204 /* allocated the 'extended' data based on the type of query requested */
1206 case WINED3DQUERYTYPE_OCCLUSION:
1207 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1208 TRACE("(%p) Allocating data for an occlusion query\n", This);
1209 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1210 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1211 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1214 case WINED3DQUERYTYPE_EVENT:
1215 if(GL_SUPPORT(APPLE_FENCE)) {
1216 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1217 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1218 checkGLcall("glGenFencesAPPLE");
1219 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1220 } else if(GL_SUPPORT(NV_FENCE)) {
1221 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1222 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1223 checkGLcall("glGenFencesNV");
1224 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1228 case WINED3DQUERYTYPE_VCACHE:
1229 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1230 case WINED3DQUERYTYPE_VERTEXSTATS:
1231 case WINED3DQUERYTYPE_TIMESTAMP:
1232 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1233 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1234 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1235 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1236 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1237 case WINED3DQUERYTYPE_PIXELTIMINGS:
1238 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1239 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1241 object->extendedData = 0;
1242 FIXME("(%p) Unhandled query type %d\n",This , Type);
1244 TRACE("(%p) : Created Query %p\n", This, object);
1248 /*****************************************************************************
1249 * IWineD3DDeviceImpl_SetupFullscreenWindow
1251 * Helper function that modifies a HWND's Style and ExStyle for proper
1255 * iface: Pointer to the IWineD3DDevice interface
1256 * window: Window to setup
1258 *****************************************************************************/
1259 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1262 LONG style, exStyle;
1263 /* Don't do anything if an original style is stored.
1264 * That shouldn't happen
1266 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1267 if (This->style || This->exStyle) {
1268 ERR("(%p): Want to change the window parameters of HWND %p, but "
1269 "another style is stored for restoration afterwards\n", This, window);
1272 /* Get the parameters and save them */
1273 style = GetWindowLongW(window, GWL_STYLE);
1274 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1275 This->style = style;
1276 This->exStyle = exStyle;
1278 /* Filter out window decorations */
1279 style &= ~WS_CAPTION;
1280 style &= ~WS_THICKFRAME;
1281 exStyle &= ~WS_EX_WINDOWEDGE;
1282 exStyle &= ~WS_EX_CLIENTEDGE;
1284 /* Make sure the window is managed, otherwise we won't get keyboard input */
1285 style |= WS_POPUP | WS_SYSMENU;
1287 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1288 This->style, This->exStyle, style, exStyle);
1290 SetWindowLongW(window, GWL_STYLE, style);
1291 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1293 /* Inform the window about the update. */
1294 SetWindowPos(window, HWND_TOP, 0, 0,
1295 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1296 ShowWindow(window, SW_NORMAL);
1299 /*****************************************************************************
1300 * IWineD3DDeviceImpl_RestoreWindow
1302 * Helper function that restores a windows' properties when taking it out
1303 * of fullscreen mode
1306 * iface: Pointer to the IWineD3DDevice interface
1307 * window: Window to setup
1309 *****************************************************************************/
1310 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1314 * switch, do nothing
1316 if (!This->style && !This->exStyle) return;
1318 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1319 This, window, This->style, This->exStyle);
1321 SetWindowLongW(window, GWL_STYLE, This->style);
1322 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1324 /* Delete the old values */
1328 /* Inform the window about the update */
1329 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1330 0, 0, 0, 0, /* Pos, Size, ignored */
1331 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1334 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1337 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1338 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1342 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1343 HRESULT hr = WINED3D_OK;
1344 IUnknown *bufferParent;
1346 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1348 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1349 * does a device hold a reference to a swap chain giving them a lifetime of the device
1350 * or does the swap chain notify the device of its destruction.
1351 *******************************/
1353 /* Check the params */
1354 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1355 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1356 return WINED3DERR_INVALIDCALL;
1357 } else if (pPresentationParameters->BackBufferCount > 1) {
1358 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");
1361 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1363 /*********************
1364 * Lookup the window Handle and the relating X window handle
1365 ********************/
1367 /* Setup hwnd we are using, plus which display this equates to */
1368 object->win_handle = pPresentationParameters->hDeviceWindow;
1369 if (!object->win_handle) {
1370 object->win_handle = This->createParms.hFocusWindow;
1373 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1374 hDc = GetDC(object->win_handle);
1375 TRACE("Using hDc %p\n", hDc);
1378 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1379 return WINED3DERR_NOTAVAILABLE;
1382 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1383 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1384 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1385 ReleaseDC(object->win_handle, hDc);
1387 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1388 * then the corresponding dimension of the client area of the hDeviceWindow
1389 * (or the focus window, if hDeviceWindow is NULL) is taken.
1390 **********************/
1392 if (pPresentationParameters->Windowed &&
1393 ((pPresentationParameters->BackBufferWidth == 0) ||
1394 (pPresentationParameters->BackBufferHeight == 0) ||
1395 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1398 GetClientRect(object->win_handle, &Rect);
1400 if (pPresentationParameters->BackBufferWidth == 0) {
1401 pPresentationParameters->BackBufferWidth = Rect.right;
1402 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1404 if (pPresentationParameters->BackBufferHeight == 0) {
1405 pPresentationParameters->BackBufferHeight = Rect.bottom;
1406 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1408 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1409 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1410 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1414 /* Put the correct figures in the presentation parameters */
1415 TRACE("Copying across presentation parameters\n");
1416 object->presentParms = *pPresentationParameters;
1418 TRACE("calling rendertarget CB\n");
1419 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1421 object->presentParms.BackBufferWidth,
1422 object->presentParms.BackBufferHeight,
1423 object->presentParms.BackBufferFormat,
1424 object->presentParms.MultiSampleType,
1425 object->presentParms.MultiSampleQuality,
1426 TRUE /* Lockable */,
1427 &object->frontBuffer,
1428 NULL /* pShared (always null)*/);
1429 if (object->frontBuffer != NULL) {
1430 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1432 ERR("Failed to create the front buffer\n");
1437 * Create an opengl context for the display visual
1438 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1439 * use different properties after that point in time. FIXME: How to handle when requested format
1440 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1441 * it chooses is identical to the one already being used!
1442 **********************************/
1443 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1445 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1446 if(!object->context)
1447 return E_OUTOFMEMORY;
1448 object->num_contexts = 1;
1451 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1454 if (!object->context[0]) {
1455 ERR("Failed to create a new context\n");
1456 hr = WINED3DERR_NOTAVAILABLE;
1459 TRACE("Context created (HWND=%p, glContext=%p)\n",
1460 object->win_handle, object->context[0]->glCtx);
1463 /*********************
1464 * Windowed / Fullscreen
1465 *******************/
1468 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1469 * so we should really check to see if there is a fullscreen swapchain already
1470 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1471 **************************************/
1473 if (!pPresentationParameters->Windowed) {
1480 /* Get info on the current display setup */
1482 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1485 /* Change the display settings */
1486 memset(&devmode, 0, sizeof(devmode));
1487 devmode.dmSize = sizeof(devmode);
1488 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1489 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1490 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1491 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1492 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1494 /* For GetDisplayMode */
1495 This->ddraw_width = devmode.dmPelsWidth;
1496 This->ddraw_height = devmode.dmPelsHeight;
1497 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1499 IWineD3DDevice_SetFullscreen(iface, TRUE);
1501 /* And finally clip mouse to our screen */
1502 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1503 ClipCursor(&clip_rc);
1506 /*********************
1507 * Create the back, front and stencil buffers
1508 *******************/
1509 if(object->presentParms.BackBufferCount > 0) {
1512 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1513 if(!object->backBuffer) {
1514 ERR("Out of memory\n");
1519 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1520 TRACE("calling rendertarget CB\n");
1521 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1523 object->presentParms.BackBufferWidth,
1524 object->presentParms.BackBufferHeight,
1525 object->presentParms.BackBufferFormat,
1526 object->presentParms.MultiSampleType,
1527 object->presentParms.MultiSampleQuality,
1528 TRUE /* Lockable */,
1529 &object->backBuffer[i],
1530 NULL /* pShared (always null)*/);
1531 if(hr == WINED3D_OK && object->backBuffer[i]) {
1532 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1534 ERR("Cannot create new back buffer\n");
1538 glDrawBuffer(GL_BACK);
1539 checkGLcall("glDrawBuffer(GL_BACK)");
1543 object->backBuffer = NULL;
1545 /* Single buffering - draw to front buffer */
1547 glDrawBuffer(GL_FRONT);
1548 checkGLcall("glDrawBuffer(GL_FRONT)");
1552 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1553 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1554 TRACE("Creating depth stencil buffer\n");
1555 if (This->depthStencilBuffer == NULL ) {
1556 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1558 object->presentParms.BackBufferWidth,
1559 object->presentParms.BackBufferHeight,
1560 object->presentParms.AutoDepthStencilFormat,
1561 object->presentParms.MultiSampleType,
1562 object->presentParms.MultiSampleQuality,
1563 FALSE /* FIXME: Discard */,
1564 &This->depthStencilBuffer,
1565 NULL /* pShared (always null)*/ );
1566 if (This->depthStencilBuffer != NULL)
1567 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1570 /** TODO: A check on width, height and multisample types
1571 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1572 ****************************/
1573 object->wantsDepthStencilBuffer = TRUE;
1575 object->wantsDepthStencilBuffer = FALSE;
1578 TRACE("Created swapchain %p\n", object);
1579 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1583 if (object->backBuffer) {
1585 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1586 if(object->backBuffer[i]) {
1587 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1588 IUnknown_Release(bufferParent); /* once for the get parent */
1589 if (IUnknown_Release(bufferParent) > 0) {
1590 FIXME("(%p) Something's still holding the back buffer\n",This);
1594 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1595 object->backBuffer = NULL;
1597 if(object->context[0])
1598 DestroyContext(This, object->context[0]);
1599 if(object->frontBuffer) {
1600 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1601 IUnknown_Release(bufferParent); /* once for the get parent */
1602 if (IUnknown_Release(bufferParent) > 0) {
1603 FIXME("(%p) Something's still holding the front buffer\n",This);
1606 HeapFree(GetProcessHeap(), 0, object);
1610 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1611 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1613 TRACE("(%p)\n", This);
1615 return This->NumberOfSwapChains;
1618 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1620 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1622 if(iSwapChain < This->NumberOfSwapChains) {
1623 *pSwapChain = This->swapchains[iSwapChain];
1624 IWineD3DSwapChain_AddRef(*pSwapChain);
1625 TRACE("(%p) returning %p\n", This, *pSwapChain);
1628 TRACE("Swapchain out of range\n");
1630 return WINED3DERR_INVALIDCALL;
1635 * Vertex Declaration
1637 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1638 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 IWineD3DVertexDeclarationImpl *object = NULL;
1641 HRESULT hr = WINED3D_OK;
1643 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1644 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1646 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1648 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1653 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1655 unsigned int idx, idx2;
1656 unsigned int offset;
1657 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1658 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1659 BOOL has_blend_idx = has_blend &&
1660 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1661 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1662 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1663 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1664 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1665 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1666 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1668 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1669 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1671 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1672 WINED3DVERTEXELEMENT *elements = NULL;
1675 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1676 if (has_blend_idx) num_blends--;
1678 /* Compute declaration size */
1679 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1680 has_psize + has_diffuse + has_specular + num_textures + 1;
1682 /* convert the declaration */
1683 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1687 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1690 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1691 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1692 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1695 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1696 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1698 elements[idx].UsageIndex = 0;
1701 if (has_blend && (num_blends > 0)) {
1702 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1703 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1705 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1706 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1707 elements[idx].UsageIndex = 0;
1710 if (has_blend_idx) {
1711 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1712 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1713 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1714 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1715 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1717 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1718 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1719 elements[idx].UsageIndex = 0;
1723 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1724 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1725 elements[idx].UsageIndex = 0;
1729 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1730 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1731 elements[idx].UsageIndex = 0;
1735 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1736 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1737 elements[idx].UsageIndex = 0;
1741 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1742 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1743 elements[idx].UsageIndex = 1;
1746 for (idx2 = 0; idx2 < num_textures; idx2++) {
1747 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1748 switch (numcoords) {
1749 case WINED3DFVF_TEXTUREFORMAT1:
1750 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1752 case WINED3DFVF_TEXTUREFORMAT2:
1753 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1755 case WINED3DFVF_TEXTUREFORMAT3:
1756 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1758 case WINED3DFVF_TEXTUREFORMAT4:
1759 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1762 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1763 elements[idx].UsageIndex = idx2;
1767 /* Now compute offsets, and initialize the rest of the fields */
1768 for (idx = 0, offset = 0; idx < size-1; idx++) {
1769 elements[idx].Stream = 0;
1770 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1771 elements[idx].Offset = offset;
1772 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1775 *ppVertexElements = elements;
1779 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1780 WINED3DVERTEXELEMENT* elements = NULL;
1784 size = ConvertFvfToDeclaration(Fvf, &elements);
1785 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1787 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1788 HeapFree(GetProcessHeap(), 0, elements);
1789 if (hr != S_OK) return hr;
1794 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1795 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1797 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1798 HRESULT hr = WINED3D_OK;
1799 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1800 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1802 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1804 if (vertex_declaration) {
1805 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1808 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1810 if (WINED3D_OK != hr) {
1811 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1812 IWineD3DVertexShader_Release(*ppVertexShader);
1813 return WINED3DERR_INVALIDCALL;
1819 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1821 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1822 HRESULT hr = WINED3D_OK;
1824 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1825 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1826 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1827 if (WINED3D_OK == hr) {
1828 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1830 WARN("(%p) : Failed to create pixel shader\n", This);
1836 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1838 IWineD3DPaletteImpl *object;
1840 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1842 /* Create the new object */
1843 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1845 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1846 return E_OUTOFMEMORY;
1849 object->lpVtbl = &IWineD3DPalette_Vtbl;
1851 object->Flags = Flags;
1852 object->parent = Parent;
1853 object->wineD3DDevice = This;
1854 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1856 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1859 HeapFree( GetProcessHeap(), 0, object);
1860 return E_OUTOFMEMORY;
1863 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1865 IWineD3DPalette_Release((IWineD3DPalette *) object);
1869 *Palette = (IWineD3DPalette *) object;
1874 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1878 HDC dcb = NULL, dcs = NULL;
1879 WINEDDCOLORKEY colorkey;
1881 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1884 GetObjectA(hbm, sizeof(BITMAP), &bm);
1885 dcb = CreateCompatibleDC(NULL);
1887 SelectObject(dcb, hbm);
1891 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1892 * couldn't be loaded
1894 memset(&bm, 0, sizeof(bm));
1899 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1900 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1901 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1903 ERR("Wine logo requested, but failed to create surface\n");
1908 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1909 if(FAILED(hr)) goto out;
1910 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1911 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1913 colorkey.dwColorSpaceLowValue = 0;
1914 colorkey.dwColorSpaceHighValue = 0;
1915 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1917 /* Fill the surface with a white color to show that wined3d is there */
1918 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1931 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1933 IWineD3DSwapChainImpl *swapchain;
1937 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1938 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1940 /* TODO: Test if OpenGL is compiled in and loaded */
1942 TRACE("(%p) : Creating stateblock\n", This);
1943 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1944 hr = IWineD3DDevice_CreateStateBlock(iface,
1946 (IWineD3DStateBlock **)&This->stateBlock,
1948 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1949 WARN("Failed to create stateblock\n");
1952 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1953 This->updateStateBlock = This->stateBlock;
1954 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1956 hr = allocate_shader_constants(This->updateStateBlock);
1957 if (WINED3D_OK != hr)
1960 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1961 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1962 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1964 /* Initialize the texture unit mapping to a 1:1 mapping */
1965 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1966 if (state < GL_LIMITS(fragment_samplers)) {
1967 This->texUnitMap[state] = state;
1968 This->rev_tex_unit_map[state] = state;
1970 This->texUnitMap[state] = -1;
1971 This->rev_tex_unit_map[state] = -1;
1975 /* Setup the implicit swapchain */
1976 TRACE("Creating implicit swapchain\n");
1977 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1978 if (FAILED(hr) || !swapchain) {
1979 WARN("Failed to create implicit swapchain\n");
1983 This->NumberOfSwapChains = 1;
1984 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1985 if(!This->swapchains) {
1986 ERR("Out of memory!\n");
1987 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1988 return E_OUTOFMEMORY;
1990 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1992 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1994 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1995 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1996 This->render_targets[0] = swapchain->backBuffer[0];
1997 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2000 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2001 This->render_targets[0] = swapchain->frontBuffer;
2002 This->lastActiveRenderTarget = swapchain->frontBuffer;
2004 IWineD3DSurface_AddRef(This->render_targets[0]);
2005 This->activeContext = swapchain->context[0];
2006 This->lastThread = GetCurrentThreadId();
2008 /* Depth Stencil support */
2009 This->stencilBufferTarget = This->depthStencilBuffer;
2010 if (NULL != This->stencilBufferTarget) {
2011 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2014 /* Set up some starting GL setup */
2017 /* Setup all the devices defaults */
2018 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2020 IWineD3DImpl_CheckGraphicsMemory();
2023 { /* Set a default viewport */
2027 vp.Width = pPresentationParameters->BackBufferWidth;
2028 vp.Height = pPresentationParameters->BackBufferHeight;
2031 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2034 /* Initialize the current view state */
2035 This->view_ident = 1;
2036 This->contexts[0]->last_was_rhw = 0;
2037 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2038 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2040 switch(wined3d_settings.offscreen_rendering_mode) {
2043 This->offscreenBuffer = GL_BACK;
2046 case ORM_BACKBUFFER:
2048 if(GL_LIMITS(aux_buffers) > 0) {
2049 TRACE("Using auxilliary buffer for offscreen rendering\n");
2050 This->offscreenBuffer = GL_AUX0;
2052 TRACE("Using back buffer for offscreen rendering\n");
2053 This->offscreenBuffer = GL_BACK;
2058 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2061 /* Clear the screen */
2062 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2063 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2066 This->d3d_initialized = TRUE;
2068 if(wined3d_settings.logo) {
2069 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2074 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2078 TRACE("(%p)\n", This);
2080 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2082 /* I don't think that the interface guarants that the device is destroyed from the same thread
2083 * it was created. Thus make sure a context is active for the glDelete* calls
2085 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2087 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2089 TRACE("Deleting high order patches\n");
2090 for(i = 0; i < PATCHMAP_SIZE; i++) {
2091 struct list *e1, *e2;
2092 struct WineD3DRectPatch *patch;
2093 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2094 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2095 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2099 /* Delete the pbuffer context if there is any */
2100 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2102 /* Delete the mouse cursor texture */
2103 if(This->cursorTexture) {
2105 glDeleteTextures(1, &This->cursorTexture);
2107 This->cursorTexture = 0;
2110 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2111 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2113 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2114 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2117 /* Release the update stateblock */
2118 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2119 if(This->updateStateBlock != This->stateBlock)
2120 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2122 This->updateStateBlock = NULL;
2124 { /* because were not doing proper internal refcounts releasing the primary state block
2125 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2126 to set this->stateBlock = NULL; first */
2127 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2128 This->stateBlock = NULL;
2130 /* Release the stateblock */
2131 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2132 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2136 /* Release the buffers (with sanity checks)*/
2137 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2138 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2139 if(This->depthStencilBuffer != This->stencilBufferTarget)
2140 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2142 This->stencilBufferTarget = NULL;
2144 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2145 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2146 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2148 TRACE("Setting rendertarget to NULL\n");
2149 This->render_targets[0] = NULL;
2151 if (This->depthStencilBuffer) {
2152 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2153 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2155 This->depthStencilBuffer = NULL;
2158 for(i=0; i < This->NumberOfSwapChains; i++) {
2159 TRACE("Releasing the implicit swapchain %d\n", i);
2160 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2161 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2165 HeapFree(GetProcessHeap(), 0, This->swapchains);
2166 This->swapchains = NULL;
2167 This->NumberOfSwapChains = 0;
2169 HeapFree(GetProcessHeap(), 0, This->render_targets);
2170 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2171 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2172 This->render_targets = NULL;
2173 This->fbo_color_attachments = NULL;
2174 This->draw_buffers = NULL;
2177 This->d3d_initialized = FALSE;
2181 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2183 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2185 /* Setup the window for fullscreen mode */
2186 if(fullscreen && !This->ddraw_fullscreen) {
2187 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2188 } else if(!fullscreen && This->ddraw_fullscreen) {
2189 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2192 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2193 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2194 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2197 This->ddraw_fullscreen = fullscreen;
2200 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2201 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2202 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2204 * There is no way to deactivate thread safety once it is enabled
2206 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2209 /*For now just store the flag(needed in case of ddraw) */
2210 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2215 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2219 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2222 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2224 /* Resize the screen even without a window:
2225 * The app could have unset it with SetCooperativeLevel, but not called
2226 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2227 * but we don't have any hwnd
2230 memset(&devmode, 0, sizeof(devmode));
2231 devmode.dmSize = sizeof(devmode);
2232 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2233 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2234 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2235 devmode.dmPelsWidth = pMode->Width;
2236 devmode.dmPelsHeight = pMode->Height;
2238 devmode.dmDisplayFrequency = pMode->RefreshRate;
2239 if (pMode->RefreshRate != 0) {
2240 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2243 /* Only change the mode if necessary */
2244 if( (This->ddraw_width == pMode->Width) &&
2245 (This->ddraw_height == pMode->Height) &&
2246 (This->ddraw_format == pMode->Format) &&
2247 (pMode->RefreshRate == 0) ) {
2251 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2252 if (ret != DISP_CHANGE_SUCCESSFUL) {
2253 if(devmode.dmDisplayFrequency != 0) {
2254 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2255 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2256 devmode.dmDisplayFrequency = 0;
2257 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2259 if(ret != DISP_CHANGE_SUCCESSFUL) {
2260 return WINED3DERR_NOTAVAILABLE;
2264 /* Store the new values */
2265 This->ddraw_width = pMode->Width;
2266 This->ddraw_height = pMode->Height;
2267 This->ddraw_format = pMode->Format;
2269 /* Only do this with a window of course */
2270 if(This->ddraw_window)
2271 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2273 /* And finally clip mouse to our screen */
2274 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2275 ClipCursor(&clip_rc);
2280 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2282 *ppD3D= This->wineD3D;
2283 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2284 IWineD3D_AddRef(*ppD3D);
2288 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2289 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2290 * into the video ram as possible and seeing how many fit
2291 * you can also get the correct initial value from nvidia and ATI's driver via X
2292 * texture memory is video memory + AGP memory
2293 *******************/
2294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2295 static BOOL showfixmes = TRUE;
2297 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2298 (wined3d_settings.emulated_textureram/(1024*1024)),
2299 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2302 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2303 (wined3d_settings.emulated_textureram/(1024*1024)),
2304 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2305 /* return simulated texture memory left */
2306 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2314 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2317 /* Update the current state block */
2318 This->updateStateBlock->changed.fvf = TRUE;
2320 if(This->updateStateBlock->fvf == fvf) {
2321 TRACE("Application is setting the old fvf over, nothing to do\n");
2325 This->updateStateBlock->fvf = fvf;
2326 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2332 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2334 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2335 *pfvf = This->stateBlock->fvf;
2340 * Get / Set Stream Source
2342 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2344 IWineD3DVertexBuffer *oldSrc;
2346 if (StreamNumber >= MAX_STREAMS) {
2347 WARN("Stream out of range %d\n", StreamNumber);
2348 return WINED3DERR_INVALIDCALL;
2351 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2352 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2354 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2356 if(oldSrc == pStreamData &&
2357 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2358 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2359 TRACE("Application is setting the old values over, nothing to do\n");
2363 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2365 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2366 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2369 /* Handle recording of state blocks */
2370 if (This->isRecordingState) {
2371 TRACE("Recording... not performing anything\n");
2372 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2373 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2377 /* Need to do a getParent and pass the reffs up */
2378 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2379 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2380 so for now, just count internally */
2381 if (pStreamData != NULL) {
2382 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2383 InterlockedIncrement(&vbImpl->bindCount);
2384 IWineD3DVertexBuffer_AddRef(pStreamData);
2386 if (oldSrc != NULL) {
2387 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2388 IWineD3DVertexBuffer_Release(oldSrc);
2391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2396 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2399 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2400 This->stateBlock->streamSource[StreamNumber],
2401 This->stateBlock->streamOffset[StreamNumber],
2402 This->stateBlock->streamStride[StreamNumber]);
2404 if (StreamNumber >= MAX_STREAMS) {
2405 WARN("Stream out of range %d\n", StreamNumber);
2406 return WINED3DERR_INVALIDCALL;
2408 *pStream = This->stateBlock->streamSource[StreamNumber];
2409 *pStride = This->stateBlock->streamStride[StreamNumber];
2411 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2414 if (*pStream != NULL) {
2415 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2420 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2422 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2423 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2425 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2426 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2428 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2429 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2431 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2432 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2439 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2442 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2443 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2445 TRACE("(%p) : returning %d\n", This, *Divider);
2451 * Get / Set & Multiply Transform
2453 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2456 /* Most of this routine, comments included copied from ddraw tree initially: */
2457 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2459 /* Handle recording of state blocks */
2460 if (This->isRecordingState) {
2461 TRACE("Recording... not performing anything\n");
2462 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2463 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2468 * If the new matrix is the same as the current one,
2469 * we cut off any further processing. this seems to be a reasonable
2470 * optimization because as was noticed, some apps (warcraft3 for example)
2471 * tend towards setting the same matrix repeatedly for some reason.
2473 * From here on we assume that the new matrix is different, wherever it matters.
2475 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2476 TRACE("The app is setting the same matrix over again\n");
2479 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2483 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2484 where ViewMat = Camera space, WorldMat = world space.
2486 In OpenGL, camera and world space is combined into GL_MODELVIEW
2487 matrix. The Projection matrix stay projection matrix.
2490 /* Capture the times we can just ignore the change for now */
2491 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2492 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2493 /* Handled by the state manager */
2496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2500 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2502 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2503 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2507 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2508 WINED3DMATRIX *mat = NULL;
2511 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2512 * below means it will be recorded in a state block change, but it
2513 * works regardless where it is recorded.
2514 * If this is found to be wrong, change to StateBlock.
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2519 if (State < HIGHEST_TRANSFORMSTATE)
2521 mat = &This->updateStateBlock->transforms[State];
2523 FIXME("Unhandled transform state!!\n");
2526 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2528 /* Apply change via set transform - will reapply to eg. lights this way */
2529 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2535 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2536 you can reference any indexes you want as long as that number max are enabled at any
2537 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2538 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2539 but when recording, just build a chain pretty much of commands to be replayed. */
2541 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2543 PLIGHTINFOEL *object = NULL;
2544 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2548 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2550 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2554 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2555 return WINED3DERR_INVALIDCALL;
2558 switch(pLight->Type) {
2559 case WINED3DLIGHT_POINT:
2560 case WINED3DLIGHT_SPOT:
2561 case WINED3DLIGHT_PARALLELPOINT:
2562 case WINED3DLIGHT_GLSPOT:
2563 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2566 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2567 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2568 return WINED3DERR_INVALIDCALL;
2572 case WINED3DLIGHT_DIRECTIONAL:
2573 /* Ignores attenuation */
2577 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2578 return WINED3DERR_INVALIDCALL;
2581 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2582 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2583 if(object->OriginalIndex == Index) break;
2588 TRACE("Adding new light\n");
2589 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2591 ERR("Out of memory error when allocating a light\n");
2592 return E_OUTOFMEMORY;
2594 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2595 object->glIndex = -1;
2596 object->OriginalIndex = Index;
2597 object->changed = TRUE;
2600 /* Initialize the object */
2601 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,
2602 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2603 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2604 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2605 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2606 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2607 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2609 /* Save away the information */
2610 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2612 switch (pLight->Type) {
2613 case WINED3DLIGHT_POINT:
2615 object->lightPosn[0] = pLight->Position.x;
2616 object->lightPosn[1] = pLight->Position.y;
2617 object->lightPosn[2] = pLight->Position.z;
2618 object->lightPosn[3] = 1.0f;
2619 object->cutoff = 180.0f;
2623 case WINED3DLIGHT_DIRECTIONAL:
2625 object->lightPosn[0] = -pLight->Direction.x;
2626 object->lightPosn[1] = -pLight->Direction.y;
2627 object->lightPosn[2] = -pLight->Direction.z;
2628 object->lightPosn[3] = 0.0;
2629 object->exponent = 0.0f;
2630 object->cutoff = 180.0f;
2633 case WINED3DLIGHT_SPOT:
2635 object->lightPosn[0] = pLight->Position.x;
2636 object->lightPosn[1] = pLight->Position.y;
2637 object->lightPosn[2] = pLight->Position.z;
2638 object->lightPosn[3] = 1.0;
2641 object->lightDirn[0] = pLight->Direction.x;
2642 object->lightDirn[1] = pLight->Direction.y;
2643 object->lightDirn[2] = pLight->Direction.z;
2644 object->lightDirn[3] = 1.0;
2647 * opengl-ish and d3d-ish spot lights use too different models for the
2648 * light "intensity" as a function of the angle towards the main light direction,
2649 * so we only can approximate very roughly.
2650 * however spot lights are rather rarely used in games (if ever used at all).
2651 * furthermore if still used, probably nobody pays attention to such details.
2653 if (pLight->Falloff == 0) {
2654 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2655 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2656 * will always be 1.0 for both of them, and we don't have to care for the
2657 * rest of the rather complex calculation
2659 object->exponent = 0;
2661 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2662 if (rho < 0.0001) rho = 0.0001f;
2663 object->exponent = -0.3/log(cos(rho/2));
2665 if (object->exponent > 128.0) {
2666 object->exponent = 128.0;
2668 object->cutoff = pLight->Phi*90/M_PI;
2674 FIXME("Unrecognized light type %d\n", pLight->Type);
2677 /* Update the live definitions if the light is currently assigned a glIndex */
2678 if (object->glIndex != -1 && !This->isRecordingState) {
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2684 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2685 PLIGHTINFOEL *lightInfo = NULL;
2686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2687 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2689 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2691 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2692 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2693 if(lightInfo->OriginalIndex == Index) break;
2697 if (lightInfo == NULL) {
2698 TRACE("Light information requested but light not defined\n");
2699 return WINED3DERR_INVALIDCALL;
2702 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2707 * Get / Set Light Enable
2708 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2710 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2711 PLIGHTINFOEL *lightInfo = NULL;
2712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2713 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2715 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2717 /* Tests show true = 128...not clear why */
2718 Enable = Enable? 128: 0;
2720 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2721 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2722 if(lightInfo->OriginalIndex == Index) break;
2725 TRACE("Found light: %p\n", lightInfo);
2727 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2728 if (lightInfo == NULL) {
2730 TRACE("Light enabled requested but light not defined, so defining one!\n");
2731 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2733 /* Search for it again! Should be fairly quick as near head of list */
2734 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2735 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2736 if(lightInfo->OriginalIndex == Index) break;
2739 if (lightInfo == NULL) {
2740 FIXME("Adding default lights has failed dismally\n");
2741 return WINED3DERR_INVALIDCALL;
2745 lightInfo->enabledChanged = TRUE;
2747 if(lightInfo->glIndex != -1) {
2748 if(!This->isRecordingState) {
2749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2752 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2753 lightInfo->glIndex = -1;
2755 TRACE("Light already disabled, nothing to do\n");
2758 if (lightInfo->glIndex != -1) {
2760 TRACE("Nothing to do as light was enabled\n");
2763 /* Find a free gl light */
2764 for(i = 0; i < This->maxConcurrentLights; i++) {
2765 if(This->stateBlock->activeLights[i] == NULL) {
2766 This->stateBlock->activeLights[i] = lightInfo;
2767 lightInfo->glIndex = i;
2771 if(lightInfo->glIndex == -1) {
2772 ERR("Too many concurrently active lights\n");
2773 return WINED3DERR_INVALIDCALL;
2776 /* i == lightInfo->glIndex */
2777 if(!This->isRecordingState) {
2778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2786 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2788 PLIGHTINFOEL *lightInfo = NULL;
2789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2791 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2792 TRACE("(%p) : for idx(%d)\n", This, Index);
2794 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2795 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2796 if(lightInfo->OriginalIndex == Index) break;
2800 if (lightInfo == NULL) {
2801 TRACE("Light enabled state requested but light not defined\n");
2802 return WINED3DERR_INVALIDCALL;
2804 /* true is 128 according to SetLightEnable */
2805 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2810 * Get / Set Clip Planes
2812 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2814 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2816 /* Validate Index */
2817 if (Index >= GL_LIMITS(clipplanes)) {
2818 TRACE("Application has requested clipplane this device doesn't support\n");
2819 return WINED3DERR_INVALIDCALL;
2822 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2824 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2825 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2826 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2827 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2828 TRACE("Application is setting old values over, nothing to do\n");
2832 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2833 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2834 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2835 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2837 /* Handle recording of state blocks */
2838 if (This->isRecordingState) {
2839 TRACE("Recording... not performing anything\n");
2843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2848 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850 TRACE("(%p) : for idx %d\n", This, Index);
2852 /* Validate Index */
2853 if (Index >= GL_LIMITS(clipplanes)) {
2854 TRACE("Application has requested clipplane this device doesn't support\n");
2855 return WINED3DERR_INVALIDCALL;
2858 pPlane[0] = This->stateBlock->clipplane[Index][0];
2859 pPlane[1] = This->stateBlock->clipplane[Index][1];
2860 pPlane[2] = This->stateBlock->clipplane[Index][2];
2861 pPlane[3] = This->stateBlock->clipplane[Index][3];
2866 * Get / Set Clip Plane Status
2867 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2869 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2871 FIXME("(%p) : stub\n", This);
2872 if (NULL == pClipStatus) {
2873 return WINED3DERR_INVALIDCALL;
2875 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2876 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2880 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882 FIXME("(%p) : stub\n", This);
2883 if (NULL == pClipStatus) {
2884 return WINED3DERR_INVALIDCALL;
2886 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2887 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2892 * Get / Set Material
2894 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 This->updateStateBlock->changed.material = TRUE;
2898 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2900 /* Handle recording of state blocks */
2901 if (This->isRecordingState) {
2902 TRACE("Recording... not performing anything\n");
2906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2910 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2913 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2914 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2915 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2916 pMaterial->Ambient.b, pMaterial->Ambient.a);
2917 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2918 pMaterial->Specular.b, pMaterial->Specular.a);
2919 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2920 pMaterial->Emissive.b, pMaterial->Emissive.a);
2921 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2929 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2931 IWineD3DIndexBuffer *oldIdxs;
2933 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2934 oldIdxs = This->updateStateBlock->pIndexData;
2936 This->updateStateBlock->changed.indices = TRUE;
2937 This->updateStateBlock->pIndexData = pIndexData;
2939 /* Handle recording of state blocks */
2940 if (This->isRecordingState) {
2941 TRACE("Recording... not performing anything\n");
2942 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2943 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2947 if(oldIdxs != pIndexData) {
2948 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2949 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2950 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2955 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2958 *ppIndexData = This->stateBlock->pIndexData;
2960 /* up ref count on ppindexdata */
2962 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2963 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2965 TRACE("(%p) No index data set\n", This);
2967 TRACE("Returning %p\n", *ppIndexData);
2972 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2973 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 TRACE("(%p)->(%d)\n", This, BaseIndex);
2977 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2978 TRACE("Application is setting the old value over, nothing to do\n");
2982 This->updateStateBlock->baseVertexIndex = BaseIndex;
2984 if (This->isRecordingState) {
2985 TRACE("Recording... not performing anything\n");
2988 /* The base vertex index affects the stream sources */
2989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2993 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 TRACE("(%p) : base_index %p\n", This, base_index);
2997 *base_index = This->stateBlock->baseVertexIndex;
2999 TRACE("Returning %u\n", *base_index);
3005 * Get / Set Viewports
3007 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 TRACE("(%p)\n", This);
3011 This->updateStateBlock->changed.viewport = TRUE;
3012 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3014 /* Handle recording of state blocks */
3015 if (This->isRecordingState) {
3016 TRACE("Recording... not performing anything\n");
3020 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3021 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3028 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030 TRACE("(%p)\n", This);
3031 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3036 * Get / Set Render States
3037 * TODO: Verify against dx9 definitions
3039 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 DWORD oldValue = This->stateBlock->renderState[State];
3044 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3046 This->updateStateBlock->changed.renderState[State] = TRUE;
3047 This->updateStateBlock->renderState[State] = Value;
3049 /* Handle recording of state blocks */
3050 if (This->isRecordingState) {
3051 TRACE("Recording... not performing anything\n");
3055 /* Compared here and not before the assignment to allow proper stateblock recording */
3056 if(Value == oldValue) {
3057 TRACE("Application is setting the old value over, nothing to do\n");
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3065 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3068 *pValue = This->stateBlock->renderState[State];
3073 * Get / Set Sampler States
3074 * TODO: Verify against dx9 definitions
3077 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3081 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3082 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3084 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3085 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3089 * SetSampler is designed to allow for more than the standard up to 8 textures
3090 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3091 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3093 * http://developer.nvidia.com/object/General_FAQ.html#t6
3095 * There are two new settings for GForce
3097 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3098 * and the texture one:
3099 * GL_MAX_TEXTURE_COORDS_ARB.
3100 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3103 oldValue = This->stateBlock->samplerState[Sampler][Type];
3104 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3105 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3107 /* Handle recording of state blocks */
3108 if (This->isRecordingState) {
3109 TRACE("Recording... not performing anything\n");
3113 if(oldValue == Value) {
3114 TRACE("Application is setting the old value over, nothing to do\n");
3118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3123 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3126 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3127 This, Sampler, debug_d3dsamplerstate(Type), Type);
3129 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3130 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3133 *Value = This->stateBlock->samplerState[Sampler][Type];
3134 TRACE("(%p) : Returning %#x\n", This, *Value);
3139 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 This->updateStateBlock->changed.scissorRect = TRUE;
3143 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3144 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3147 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3149 if(This->isRecordingState) {
3150 TRACE("Recording... not performing anything\n");
3154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3159 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3163 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3167 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3169 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3171 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3173 This->updateStateBlock->vertexDecl = pDecl;
3174 This->updateStateBlock->changed.vertexDecl = TRUE;
3176 if (This->isRecordingState) {
3177 TRACE("Recording... not performing anything\n");
3179 } else if(pDecl == oldDecl) {
3180 /* Checked after the assignment to allow proper stateblock recording */
3181 TRACE("Application is setting the old declaration over, nothing to do\n");
3185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3189 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3194 *ppDecl = This->stateBlock->vertexDecl;
3195 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3199 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3203 This->updateStateBlock->vertexShader = pShader;
3204 This->updateStateBlock->changed.vertexShader = TRUE;
3206 if (This->isRecordingState) {
3207 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3208 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3209 TRACE("Recording... not performing anything\n");
3211 } else if(oldShader == pShader) {
3212 /* Checked here to allow proper stateblock recording */
3213 TRACE("App is setting the old shader over, nothing to do\n");
3217 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3218 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3219 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 if (NULL == ppShader) {
3230 return WINED3DERR_INVALIDCALL;
3232 *ppShader = This->stateBlock->vertexShader;
3233 if( NULL != *ppShader)
3234 IWineD3DVertexShader_AddRef(*ppShader);
3236 TRACE("(%p) : returning %p\n", This, *ppShader);
3240 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3241 IWineD3DDevice *iface,
3243 CONST BOOL *srcData,
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3247 int i, cnt = min(count, MAX_CONST_B - start);
3249 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3250 iface, srcData, start, count);
3252 if (srcData == NULL || cnt < 0)
3253 return WINED3DERR_INVALIDCALL;
3255 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3256 for (i = 0; i < cnt; i++)
3257 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3259 for (i = start; i < cnt + start; ++i) {
3260 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3268 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3269 IWineD3DDevice *iface,
3274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 int cnt = min(count, MAX_CONST_B - start);
3277 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3278 iface, dstData, start, count);
3280 if (dstData == NULL || cnt < 0)
3281 return WINED3DERR_INVALIDCALL;
3283 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3287 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3288 IWineD3DDevice *iface,
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 int i, cnt = min(count, MAX_CONST_I - start);
3296 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3297 iface, srcData, start, count);
3299 if (srcData == NULL || cnt < 0)
3300 return WINED3DERR_INVALIDCALL;
3302 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3303 for (i = 0; i < cnt; i++)
3304 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3305 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3307 for (i = start; i < cnt + start; ++i) {
3308 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3316 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3317 IWineD3DDevice *iface,
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3323 int cnt = min(count, MAX_CONST_I - start);
3325 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3326 iface, dstData, start, count);
3328 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3329 return WINED3DERR_INVALIDCALL;
3331 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3335 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3336 IWineD3DDevice *iface,
3338 CONST float *srcData,
3341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3345 iface, srcData, start, count);
3347 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3348 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3349 return WINED3DERR_INVALIDCALL;
3351 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3353 for (i = 0; i < count; i++)
3354 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3355 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3358 for (i = start; i < count + start; ++i) {
3359 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3360 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3361 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3362 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3363 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3365 ptr->idx[ptr->count++] = i;
3366 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3375 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3376 IWineD3DDevice *iface,
3381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3384 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3385 iface, dstData, start, count);
3387 if (dstData == NULL || cnt < 0)
3388 return WINED3DERR_INVALIDCALL;
3390 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3394 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3396 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3397 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3401 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3402 int i = This->rev_tex_unit_map[unit];
3403 int j = This->texUnitMap[stage];
3405 This->texUnitMap[stage] = unit;
3406 if (i != -1 && i != stage) {
3407 This->texUnitMap[i] = -1;
3410 This->rev_tex_unit_map[unit] = stage;
3411 if (j != -1 && j != unit) {
3412 This->rev_tex_unit_map[j] = -1;
3416 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3419 for (i = 0; i < MAX_TEXTURES; ++i) {
3420 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3421 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3422 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3423 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3424 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3425 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3426 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3427 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3429 if (color_op == WINED3DTOP_DISABLE) {
3430 /* Not used, and disable higher stages */
3431 while (i < MAX_TEXTURES) {
3432 This->fixed_function_usage_map[i] = FALSE;
3438 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3439 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3440 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3441 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3442 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3443 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3444 This->fixed_function_usage_map[i] = TRUE;
3446 This->fixed_function_usage_map[i] = FALSE;
3449 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3450 This->fixed_function_usage_map[i+1] = TRUE;
3455 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3458 device_update_fixed_function_usage_map(This);
3460 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3461 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3462 if (!This->fixed_function_usage_map[i]) continue;
3464 if (This->texUnitMap[i] != i) {
3465 device_map_stage(This, i, i);
3466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3467 markTextureStagesDirty(This, i);
3473 /* Now work out the mapping */
3475 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3476 if (!This->fixed_function_usage_map[i]) continue;
3478 if (This->texUnitMap[i] != tex) {
3479 device_map_stage(This, i, tex);
3480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3481 markTextureStagesDirty(This, i);
3488 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3489 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3492 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3493 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3494 device_map_stage(This, i, i);
3495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3496 if (i < MAX_TEXTURES) {
3497 markTextureStagesDirty(This, i);
3503 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3504 int current_mapping = This->rev_tex_unit_map[unit];
3506 if (current_mapping == -1) {
3507 /* Not currently used */
3511 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3512 /* Used by a fragment sampler */
3514 if (!pshader_sampler_tokens) {
3515 /* No pixel shader, check fixed function */
3516 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3519 /* Pixel shader, check the shader's sampler map */
3520 return !pshader_sampler_tokens[current_mapping];
3523 /* Used by a vertex sampler */
3524 return !vshader_sampler_tokens[current_mapping];
3527 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3528 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3529 DWORD *pshader_sampler_tokens = NULL;
3530 int start = GL_LIMITS(combined_samplers) - 1;
3534 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3536 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3537 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3538 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3541 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3542 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3543 if (vshader_sampler_tokens[i]) {
3544 if (This->texUnitMap[vsampler_idx] != -1) {
3545 /* Already mapped somewhere */
3549 while (start >= 0) {
3550 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3551 device_map_stage(This, vsampler_idx, start);
3552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3564 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3565 BOOL vs = use_vs(This);
3566 BOOL ps = use_ps(This);
3569 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3570 * that would be really messy and require shader recompilation
3571 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3572 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3575 device_map_psamplers(This);
3577 device_map_fixed_function_samplers(This);
3581 device_map_vsamplers(This, ps);
3585 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3587 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3588 This->updateStateBlock->pixelShader = pShader;
3589 This->updateStateBlock->changed.pixelShader = TRUE;
3591 /* Handle recording of state blocks */
3592 if (This->isRecordingState) {
3593 TRACE("Recording... not performing anything\n");
3596 if (This->isRecordingState) {
3597 TRACE("Recording... not performing anything\n");
3598 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3599 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3603 if(pShader == oldShader) {
3604 TRACE("App is setting the old pixel shader over, nothing to do\n");
3608 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3609 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3611 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3617 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3620 if (NULL == ppShader) {
3621 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3622 return WINED3DERR_INVALIDCALL;
3625 *ppShader = This->stateBlock->pixelShader;
3626 if (NULL != *ppShader) {
3627 IWineD3DPixelShader_AddRef(*ppShader);
3629 TRACE("(%p) : returning %p\n", This, *ppShader);
3633 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3634 IWineD3DDevice *iface,
3636 CONST BOOL *srcData,
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 int i, cnt = min(count, MAX_CONST_B - start);
3642 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3643 iface, srcData, start, count);
3645 if (srcData == NULL || cnt < 0)
3646 return WINED3DERR_INVALIDCALL;
3648 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3649 for (i = 0; i < cnt; i++)
3650 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3652 for (i = start; i < cnt + start; ++i) {
3653 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3656 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3661 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3662 IWineD3DDevice *iface,
3667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3668 int cnt = min(count, MAX_CONST_B - start);
3670 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3671 iface, dstData, start, count);
3673 if (dstData == NULL || cnt < 0)
3674 return WINED3DERR_INVALIDCALL;
3676 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3680 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3681 IWineD3DDevice *iface,
3686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3687 int i, cnt = min(count, MAX_CONST_I - start);
3689 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3690 iface, srcData, start, count);
3692 if (srcData == NULL || cnt < 0)
3693 return WINED3DERR_INVALIDCALL;
3695 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3696 for (i = 0; i < cnt; i++)
3697 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3698 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3700 for (i = start; i < cnt + start; ++i) {
3701 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3709 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3710 IWineD3DDevice *iface,
3715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3716 int cnt = min(count, MAX_CONST_I - start);
3718 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3719 iface, dstData, start, count);
3721 if (dstData == NULL || cnt < 0)
3722 return WINED3DERR_INVALIDCALL;
3724 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3728 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3729 IWineD3DDevice *iface,
3731 CONST float *srcData,
3734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3737 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3738 iface, srcData, start, count);
3740 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3741 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3742 return WINED3DERR_INVALIDCALL;
3744 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3746 for (i = 0; i < count; i++)
3747 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3748 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3751 for (i = start; i < count + start; ++i) {
3752 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3753 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3754 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3755 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3756 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3758 ptr->idx[ptr->count++] = i;
3759 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3768 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3769 IWineD3DDevice *iface,
3774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3775 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3777 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3778 iface, dstData, start, count);
3780 if (dstData == NULL || cnt < 0)
3781 return WINED3DERR_INVALIDCALL;
3783 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3787 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3789 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3790 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3792 DWORD DestFVF = dest->fvf;
3794 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3798 if (lpStrideData->u.s.normal.lpData) {
3799 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3802 if (lpStrideData->u.s.position.lpData == NULL) {
3803 ERR("Source has no position mask\n");
3804 return WINED3DERR_INVALIDCALL;
3807 /* We might access VBOs from this code, so hold the lock */
3810 if (dest->resource.allocatedMemory == NULL) {
3811 /* This may happen if we do direct locking into a vbo. Unlikely,
3812 * but theoretically possible(ddraw processvertices test)
3814 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3815 if(!dest->resource.allocatedMemory) {
3817 ERR("Out of memory\n");
3818 return E_OUTOFMEMORY;
3822 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3823 checkGLcall("glBindBufferARB");
3824 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3826 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3828 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3829 checkGLcall("glUnmapBufferARB");
3833 /* Get a pointer into the destination vbo(create one if none exists) and
3834 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3836 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3841 unsigned char extrabytes = 0;
3842 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3843 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3844 * this may write 4 extra bytes beyond the area that should be written
3846 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3847 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3848 if(!dest_conv_addr) {
3849 ERR("Out of memory\n");
3850 /* Continue without storing converted vertices */
3852 dest_conv = dest_conv_addr;
3856 * a) WINED3DRS_CLIPPING is enabled
3857 * b) WINED3DVOP_CLIP is passed
3859 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3860 static BOOL warned = FALSE;
3862 * The clipping code is not quite correct. Some things need
3863 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3864 * so disable clipping for now.
3865 * (The graphics in Half-Life are broken, and my processvertices
3866 * test crashes with IDirect3DDevice3)
3872 FIXME("Clipping is broken and disabled for now\n");
3874 } else doClip = FALSE;
3875 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3877 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3880 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3881 WINED3DTS_PROJECTION,
3883 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3884 WINED3DTS_WORLDMATRIX(0),
3887 TRACE("View mat:\n");
3888 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);
3889 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);
3890 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);
3891 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);
3893 TRACE("Proj mat:\n");
3894 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);
3895 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);
3896 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);
3897 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);
3899 TRACE("World mat:\n");
3900 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);
3901 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);
3902 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);
3903 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);
3905 /* Get the viewport */
3906 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3907 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3908 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3910 multiply_matrix(&mat,&view_mat,&world_mat);
3911 multiply_matrix(&mat,&proj_mat,&mat);
3913 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3915 for (i = 0; i < dwCount; i+= 1) {
3916 unsigned int tex_index;
3918 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3919 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3920 /* The position first */
3922 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3924 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3926 /* Multiplication with world, view and projection matrix */
3927 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);
3928 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);
3929 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);
3930 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);
3932 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3934 /* WARNING: The following things are taken from d3d7 and were not yet checked
3935 * against d3d8 or d3d9!
3938 /* Clipping conditions: From
3939 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3941 * A vertex is clipped if it does not match the following requirements
3945 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3947 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3948 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3953 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3954 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3957 /* "Normal" viewport transformation (not clipped)
3958 * 1) The values are divided by rhw
3959 * 2) The y axis is negative, so multiply it with -1
3960 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3961 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3962 * 4) Multiply x with Width/2 and add Width/2
3963 * 5) The same for the height
3964 * 6) Add the viewpoint X and Y to the 2D coordinates and
3965 * The minimum Z value to z
3966 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3968 * Well, basically it's simply a linear transformation into viewport
3980 z *= vp.MaxZ - vp.MinZ;
3982 x += vp.Width / 2 + vp.X;
3983 y += vp.Height / 2 + vp.Y;
3988 /* That vertex got clipped
3989 * Contrary to OpenGL it is not dropped completely, it just
3990 * undergoes a different calculation.
3992 TRACE("Vertex got clipped\n");
3999 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4000 * outside of the main vertex buffer memory. That needs some more
4005 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4008 ( (float *) dest_ptr)[0] = x;
4009 ( (float *) dest_ptr)[1] = y;
4010 ( (float *) dest_ptr)[2] = z;
4011 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4013 dest_ptr += 3 * sizeof(float);
4015 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4016 dest_ptr += sizeof(float);
4021 ( (float *) dest_conv)[0] = x * w;
4022 ( (float *) dest_conv)[1] = y * w;
4023 ( (float *) dest_conv)[2] = z * w;
4024 ( (float *) dest_conv)[3] = w;
4026 dest_conv += 3 * sizeof(float);
4028 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4029 dest_conv += sizeof(float);
4033 if (DestFVF & WINED3DFVF_PSIZE) {
4034 dest_ptr += sizeof(DWORD);
4035 if(dest_conv) dest_conv += sizeof(DWORD);
4037 if (DestFVF & WINED3DFVF_NORMAL) {
4039 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4040 /* AFAIK this should go into the lighting information */
4041 FIXME("Didn't expect the destination to have a normal\n");
4042 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4044 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4048 if (DestFVF & WINED3DFVF_DIFFUSE) {
4050 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4052 static BOOL warned = FALSE;
4055 ERR("No diffuse color in source, but destination has one\n");
4059 *( (DWORD *) dest_ptr) = 0xffffffff;
4060 dest_ptr += sizeof(DWORD);
4063 *( (DWORD *) dest_conv) = 0xffffffff;
4064 dest_conv += sizeof(DWORD);
4068 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4070 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4071 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4072 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4073 dest_conv += sizeof(DWORD);
4078 if (DestFVF & WINED3DFVF_SPECULAR) {
4079 /* What's the color value in the feedback buffer? */
4081 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4083 static BOOL warned = FALSE;
4086 ERR("No specular color in source, but destination has one\n");
4090 *( (DWORD *) dest_ptr) = 0xFF000000;
4091 dest_ptr += sizeof(DWORD);
4094 *( (DWORD *) dest_conv) = 0xFF000000;
4095 dest_conv += sizeof(DWORD);
4099 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4101 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4102 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4103 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4104 dest_conv += sizeof(DWORD);
4109 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4111 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4112 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4114 ERR("No source texture, but destination requests one\n");
4115 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4116 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4119 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4121 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4128 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4129 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4130 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4131 dwCount * get_flexible_vertex_size(DestFVF),
4133 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4134 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4141 #undef copy_and_next
4143 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4145 WineDirect3DVertexStridedData strided;
4146 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4147 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4150 ERR("Output vertex declaration not implemented yet\n");
4153 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4154 * and this call is quite performance critical, so don't call needlessly
4156 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4157 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4160 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4161 * control the streamIsUP flag, thus restore it afterwards.
4163 This->stateBlock->streamIsUP = FALSE;
4164 memset(&strided, 0, sizeof(strided));
4165 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4166 This->stateBlock->streamIsUP = streamWasUP;
4168 if(vbo || SrcStartIndex) {
4170 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4171 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4173 * Also get the start index in, but only loop over all elements if there's something to add at all.
4175 #define FIXSRC(type) \
4176 if(strided.u.s.type.VBO) { \
4177 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4178 strided.u.s.type.VBO = 0; \
4179 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4181 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4185 if(strided.u.s.type.lpData) { \
4186 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4189 FIXSRC(blendWeights);
4190 FIXSRC(blendMatrixIndices);
4195 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4196 FIXSRC(texCoords[i]);
4209 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4213 * Get / Set Texture Stage States
4214 * TODO: Verify against dx9 definitions
4216 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4218 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4220 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4222 if (Stage >= MAX_TEXTURES) {
4223 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4227 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4228 This->updateStateBlock->textureState[Stage][Type] = Value;
4230 if (This->isRecordingState) {
4231 TRACE("Recording... not performing anything\n");
4235 /* Checked after the assignments to allow proper stateblock recording */
4236 if(oldValue == Value) {
4237 TRACE("App is setting the old value over, nothing to do\n");
4241 if(Stage > This->stateBlock->lowest_disabled_stage &&
4242 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4243 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4244 * Changes in other states are important on disabled stages too
4249 if(Type == WINED3DTSS_COLOROP) {
4252 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4253 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4254 * they have to be disabled
4256 * The current stage is dirtified below.
4258 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4259 TRACE("Additionally dirtifying stage %d\n", i);
4260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4262 This->stateBlock->lowest_disabled_stage = Stage;
4263 TRACE("New lowest disabled: %d\n", Stage);
4264 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4265 /* Previously disabled stage enabled. Stages above it may need enabling
4266 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4267 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4269 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4272 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4273 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4276 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4277 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4279 This->stateBlock->lowest_disabled_stage = i;
4280 TRACE("New lowest disabled: %d\n", i);
4282 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4283 /* TODO: Built a stage -> texture unit mapping for register combiners */
4287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4292 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4294 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4295 *pValue = This->updateStateBlock->textureState[Stage][Type];
4302 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4304 IWineD3DBaseTexture *oldTexture;
4306 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4308 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4309 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4312 oldTexture = This->updateStateBlock->textures[Stage];
4314 if(pTexture != NULL) {
4315 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4317 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4318 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4319 return WINED3DERR_INVALIDCALL;
4321 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4324 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4325 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4327 This->updateStateBlock->changed.textures[Stage] = TRUE;
4328 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4329 This->updateStateBlock->textures[Stage] = pTexture;
4331 /* Handle recording of state blocks */
4332 if (This->isRecordingState) {
4333 TRACE("Recording... not performing anything\n");
4337 if(oldTexture == pTexture) {
4338 TRACE("App is setting the same texture again, nothing to do\n");
4342 /** NOTE: MSDN says that setTexture increases the reference count,
4343 * and the the application must set the texture back to null (or have a leaky application),
4344 * This means we should pass the refcount up to the parent
4345 *******************************/
4346 if (NULL != This->updateStateBlock->textures[Stage]) {
4347 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4348 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4350 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4351 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4352 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4353 * so the COLOROP and ALPHAOP have to be dirtified.
4355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4358 if(bindCount == 1) {
4359 new->baseTexture.sampler = Stage;
4361 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4365 if (NULL != oldTexture) {
4366 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4367 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4369 IWineD3DBaseTexture_Release(oldTexture);
4370 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4375 if(bindCount && old->baseTexture.sampler == Stage) {
4377 /* Have to do a search for the other sampler(s) where the texture is bound to
4378 * Shouldn't happen as long as apps bind a texture only to one stage
4380 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4381 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4382 if(This->updateStateBlock->textures[i] == oldTexture) {
4383 old->baseTexture.sampler = i;
4390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4395 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4398 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4400 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4401 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4404 *ppTexture=This->stateBlock->textures[Stage];
4406 IWineD3DBaseTexture_AddRef(*ppTexture);
4408 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4416 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4417 IWineD3DSurface **ppBackBuffer) {
4418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4419 IWineD3DSwapChain *swapChain;
4422 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4424 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4425 if (hr == WINED3D_OK) {
4426 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4427 IWineD3DSwapChain_Release(swapChain);
4429 *ppBackBuffer = NULL;
4434 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436 WARN("(%p) : stub, calling idirect3d for now\n", This);
4437 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4440 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4442 IWineD3DSwapChain *swapChain;
4445 if(iSwapChain > 0) {
4446 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4447 if (hr == WINED3D_OK) {
4448 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4449 IWineD3DSwapChain_Release(swapChain);
4451 FIXME("(%p) Error getting display mode\n", This);
4454 /* Don't read the real display mode,
4455 but return the stored mode instead. X11 can't change the color
4456 depth, and some apps are pretty angry if they SetDisplayMode from
4457 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4459 Also don't relay to the swapchain because with ddraw it's possible
4460 that there isn't a swapchain at all */
4461 pMode->Width = This->ddraw_width;
4462 pMode->Height = This->ddraw_height;
4463 pMode->Format = This->ddraw_format;
4464 pMode->RefreshRate = 0;
4471 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4473 TRACE("(%p)->(%p)\n", This, hWnd);
4475 if(This->ddraw_fullscreen) {
4476 if(This->ddraw_window && This->ddraw_window != hWnd) {
4477 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4479 if(hWnd && This->ddraw_window != hWnd) {
4480 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4484 This->ddraw_window = hWnd;
4488 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 TRACE("(%p)->(%p)\n", This, hWnd);
4492 *hWnd = This->ddraw_window;
4497 * Stateblock related functions
4500 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4502 IWineD3DStateBlockImpl *object;
4503 HRESULT temp_result;
4506 TRACE("(%p)\n", This);
4508 if (This->isRecordingState) {
4509 return WINED3DERR_INVALIDCALL;
4512 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4513 if (NULL == object ) {
4514 FIXME("(%p)Error allocating memory for stateblock\n", This);
4515 return E_OUTOFMEMORY;
4517 TRACE("(%p) created object %p\n", This, object);
4518 object->wineD3DDevice= This;
4519 /** FIXME: object->parent = parent; **/
4520 object->parent = NULL;
4521 object->blockType = WINED3DSBT_RECORDED;
4523 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4525 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4526 list_init(&object->lightMap[i]);
4529 temp_result = allocate_shader_constants(object);
4530 if (WINED3D_OK != temp_result)
4533 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4534 This->updateStateBlock = object;
4535 This->isRecordingState = TRUE;
4537 TRACE("(%p) recording stateblock %p\n",This , object);
4541 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4544 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4546 if (!This->isRecordingState) {
4547 FIXME("(%p) not recording! returning error\n", This);
4548 *ppStateBlock = NULL;
4549 return WINED3DERR_INVALIDCALL;
4552 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4553 if(object->changed.renderState[i]) {
4554 object->contained_render_states[object->num_contained_render_states] = i;
4555 object->num_contained_render_states++;
4558 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4559 if(object->changed.transform[i]) {
4560 object->contained_transform_states[object->num_contained_transform_states] = i;
4561 object->num_contained_transform_states++;
4564 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4565 if(object->changed.vertexShaderConstantsF[i]) {
4566 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4567 object->num_contained_vs_consts_f++;
4570 for(i = 0; i < MAX_CONST_I; i++) {
4571 if(object->changed.vertexShaderConstantsI[i]) {
4572 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4573 object->num_contained_vs_consts_i++;
4576 for(i = 0; i < MAX_CONST_B; i++) {
4577 if(object->changed.vertexShaderConstantsB[i]) {
4578 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4579 object->num_contained_vs_consts_b++;
4582 for(i = 0; i < MAX_CONST_I; i++) {
4583 if(object->changed.pixelShaderConstantsI[i]) {
4584 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4585 object->num_contained_ps_consts_i++;
4588 for(i = 0; i < MAX_CONST_B; i++) {
4589 if(object->changed.pixelShaderConstantsB[i]) {
4590 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4591 object->num_contained_ps_consts_b++;
4594 for(i = 0; i < MAX_TEXTURES; i++) {
4595 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4596 if(object->changed.textureState[i][j]) {
4597 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4598 object->contained_tss_states[object->num_contained_tss_states].state = j;
4599 object->num_contained_tss_states++;
4603 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4604 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4605 if(object->changed.samplerState[i][j]) {
4606 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4607 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4608 object->num_contained_sampler_states++;
4613 *ppStateBlock = (IWineD3DStateBlock*) object;
4614 This->isRecordingState = FALSE;
4615 This->updateStateBlock = This->stateBlock;
4616 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4617 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4618 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4623 * Scene related functions
4625 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4626 /* At the moment we have no need for any functionality at the beginning
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 TRACE("(%p)\n", This);
4632 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4633 return WINED3DERR_INVALIDCALL;
4635 This->inScene = TRUE;
4639 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4641 TRACE("(%p)\n", This);
4643 if(!This->inScene) {
4644 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4645 return WINED3DERR_INVALIDCALL;
4648 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4649 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4651 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4654 checkGLcall("glFlush");
4657 This->inScene = FALSE;
4661 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4662 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4663 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4665 IWineD3DSwapChain *swapChain = NULL;
4667 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4669 TRACE("(%p) Presenting the frame\n", This);
4671 for(i = 0 ; i < swapchains ; i ++) {
4673 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4674 TRACE("presentinng chain %d, %p\n", i, swapChain);
4675 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4676 IWineD3DSwapChain_Release(swapChain);
4682 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4683 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4687 GLbitfield glMask = 0;
4689 CONST WINED3DRECT* curRect;
4691 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4692 Count, pRects, Flags, Color, Z, Stencil);
4694 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4695 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4696 /* TODO: What about depth stencil buffers without stencil bits? */
4697 return WINED3DERR_INVALIDCALL;
4700 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4701 * and not the last active one.
4703 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4706 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4707 apply_fbo_state(iface);
4710 if (Count > 0 && pRects) {
4716 /* Only set the values up once, as they are not changing */
4717 if (Flags & WINED3DCLEAR_STENCIL) {
4718 glClearStencil(Stencil);
4719 checkGLcall("glClearStencil");
4720 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4721 glStencilMask(0xFFFFFFFF);
4724 if (Flags & WINED3DCLEAR_ZBUFFER) {
4725 glDepthMask(GL_TRUE);
4727 checkGLcall("glClearDepth");
4728 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4732 if (Flags & WINED3DCLEAR_TARGET) {
4733 TRACE("Clearing screen with glClear to color %x\n", Color);
4734 glClearColor(D3DCOLOR_R(Color),
4738 checkGLcall("glClearColor");
4740 /* Clear ALL colors! */
4741 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4742 glMask = glMask | GL_COLOR_BUFFER_BIT;
4746 /* In drawable flag is set below */
4748 if (This->render_offscreen) {
4749 glScissor(This->stateBlock->viewport.X,
4750 This->stateBlock->viewport.Y,
4751 This->stateBlock->viewport.Width,
4752 This->stateBlock->viewport.Height);
4754 glScissor(This->stateBlock->viewport.X,
4755 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4756 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4757 This->stateBlock->viewport.Width,
4758 This->stateBlock->viewport.Height);
4760 checkGLcall("glScissor");
4762 checkGLcall("glClear");
4764 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4765 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4767 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4768 curRect[0].x2 < target->currentDesc.Width ||
4769 curRect[0].y2 < target->currentDesc.Height) {
4770 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4771 blt_to_drawable(This, target);
4775 /* Now process each rect in turn */
4776 for (i = 0; i < Count; i++) {
4777 /* Note gl uses lower left, width/height */
4778 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4779 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4780 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4781 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4783 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4784 * The rectangle is not cleared, no error is returned, but further rectanlges are
4785 * still cleared if they are valid
4787 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4788 TRACE("Rectangle with negative dimensions, ignoring\n");
4792 if(This->render_offscreen) {
4793 glScissor(curRect[i].x1, curRect[i].y1,
4794 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4796 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4797 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4799 checkGLcall("glScissor");
4802 checkGLcall("glClear");
4806 /* Restore the old values (why..?) */
4807 if (Flags & WINED3DCLEAR_STENCIL) {
4808 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4810 if (Flags & WINED3DCLEAR_TARGET) {
4811 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4812 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4813 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4814 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4815 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4820 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4821 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4823 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4824 target->Flags |= SFLAG_INTEXTURE;
4825 target->Flags &= ~SFLAG_INSYSMEM;
4827 target->Flags |= SFLAG_INDRAWABLE;
4828 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4836 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4837 UINT PrimitiveCount) {
4839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4842 debug_d3dprimitivetype(PrimitiveType),
4843 StartVertex, PrimitiveCount);
4845 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4846 if(This->stateBlock->streamIsUP) {
4847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4848 This->stateBlock->streamIsUP = FALSE;
4851 if(This->stateBlock->loadBaseVertexIndex != 0) {
4852 This->stateBlock->loadBaseVertexIndex = 0;
4853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4855 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4856 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4857 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4861 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4862 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4863 WINED3DPRIMITIVETYPE PrimitiveType,
4864 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4868 IWineD3DIndexBuffer *pIB;
4869 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4872 pIB = This->stateBlock->pIndexData;
4874 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4875 * without an index buffer set. (The first time at least...)
4876 * D3D8 simply dies, but I doubt it can do much harm to return
4877 * D3DERR_INVALIDCALL there as well. */
4878 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4879 return WINED3DERR_INVALIDCALL;
4882 if(This->stateBlock->streamIsUP) {
4883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4884 This->stateBlock->streamIsUP = FALSE;
4886 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4888 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4889 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4890 minIndex, NumVertices, startIndex, primCount);
4892 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4893 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4899 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4900 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4904 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4905 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4910 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4911 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4912 UINT VertexStreamZeroStride) {
4913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4914 IWineD3DVertexBuffer *vb;
4916 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4917 debug_d3dprimitivetype(PrimitiveType),
4918 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4920 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4921 vb = This->stateBlock->streamSource[0];
4922 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4923 if(vb) IWineD3DVertexBuffer_Release(vb);
4924 This->stateBlock->streamOffset[0] = 0;
4925 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4926 This->stateBlock->streamIsUP = TRUE;
4927 This->stateBlock->loadBaseVertexIndex = 0;
4929 /* TODO: Only mark dirty if drawing from a different UP address */
4930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4932 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4933 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4935 /* MSDN specifies stream zero settings must be set to NULL */
4936 This->stateBlock->streamStride[0] = 0;
4937 This->stateBlock->streamSource[0] = NULL;
4939 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4940 * the new stream sources or use UP drawing again
4945 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4946 UINT MinVertexIndex, UINT NumVertices,
4947 UINT PrimitiveCount, CONST void* pIndexData,
4948 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4949 UINT VertexStreamZeroStride) {
4951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4952 IWineD3DVertexBuffer *vb;
4953 IWineD3DIndexBuffer *ib;
4955 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4956 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4957 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4958 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4960 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4966 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4967 vb = This->stateBlock->streamSource[0];
4968 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4969 if(vb) IWineD3DVertexBuffer_Release(vb);
4970 This->stateBlock->streamIsUP = TRUE;
4971 This->stateBlock->streamOffset[0] = 0;
4972 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4974 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4975 This->stateBlock->baseVertexIndex = 0;
4976 This->stateBlock->loadBaseVertexIndex = 0;
4977 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4981 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4983 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4984 This->stateBlock->streamSource[0] = NULL;
4985 This->stateBlock->streamStride[0] = 0;
4986 ib = This->stateBlock->pIndexData;
4988 IWineD3DIndexBuffer_Release(ib);
4989 This->stateBlock->pIndexData = NULL;
4991 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4992 * SetStreamSource to specify a vertex buffer
4998 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5001 /* Mark the state dirty until we have nicer tracking
5002 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5006 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5007 This->stateBlock->baseVertexIndex = 0;
5008 This->up_strided = DrawPrimStrideData;
5009 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5010 This->up_strided = NULL;
5014 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5016 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5018 /* Mark the state dirty until we have nicer tracking
5019 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5022 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5024 This->stateBlock->streamIsUP = TRUE;
5025 This->stateBlock->baseVertexIndex = 0;
5026 This->up_strided = DrawPrimStrideData;
5027 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5028 This->up_strided = NULL;
5032 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5033 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5034 * not callable by the app directly no parameter validation checks are needed here.
5036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5037 WINED3DLOCKED_BOX src;
5038 WINED3DLOCKED_BOX dst;
5040 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5042 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5043 * dirtification to improve loading performance.
5045 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5046 if(FAILED(hr)) return hr;
5047 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5049 IWineD3DVolume_UnlockBox(pSourceVolume);
5053 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5055 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5057 IWineD3DVolume_UnlockBox(pSourceVolume);
5059 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5064 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5065 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5067 HRESULT hr = WINED3D_OK;
5068 WINED3DRESOURCETYPE sourceType;
5069 WINED3DRESOURCETYPE destinationType;
5072 /* TODO: think about moving the code into IWineD3DBaseTexture */
5074 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5076 /* verify that the source and destination textures aren't NULL */
5077 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5078 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5079 This, pSourceTexture, pDestinationTexture);
5080 hr = WINED3DERR_INVALIDCALL;
5083 if (pSourceTexture == pDestinationTexture) {
5084 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5085 This, pSourceTexture, pDestinationTexture);
5086 hr = WINED3DERR_INVALIDCALL;
5088 /* Verify that the source and destination textures are the same type */
5089 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5090 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5092 if (sourceType != destinationType) {
5093 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5095 hr = WINED3DERR_INVALIDCALL;
5098 /* check that both textures have the identical numbers of levels */
5099 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5100 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5101 hr = WINED3DERR_INVALIDCALL;
5104 if (WINED3D_OK == hr) {
5106 /* Make sure that the destination texture is loaded */
5107 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5109 /* Update every surface level of the texture */
5110 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5112 switch (sourceType) {
5113 case WINED3DRTYPE_TEXTURE:
5115 IWineD3DSurface *srcSurface;
5116 IWineD3DSurface *destSurface;
5118 for (i = 0 ; i < levels ; ++i) {
5119 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5120 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5121 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5122 IWineD3DSurface_Release(srcSurface);
5123 IWineD3DSurface_Release(destSurface);
5124 if (WINED3D_OK != hr) {
5125 WARN("(%p) : Call to update surface failed\n", This);
5131 case WINED3DRTYPE_CUBETEXTURE:
5133 IWineD3DSurface *srcSurface;
5134 IWineD3DSurface *destSurface;
5135 WINED3DCUBEMAP_FACES faceType;
5137 for (i = 0 ; i < levels ; ++i) {
5138 /* Update each cube face */
5139 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5140 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5141 if (WINED3D_OK != hr) {
5142 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5144 TRACE("Got srcSurface %p\n", srcSurface);
5146 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5147 if (WINED3D_OK != hr) {
5148 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5150 TRACE("Got desrSurface %p\n", destSurface);
5152 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5153 IWineD3DSurface_Release(srcSurface);
5154 IWineD3DSurface_Release(destSurface);
5155 if (WINED3D_OK != hr) {
5156 WARN("(%p) : Call to update surface failed\n", This);
5164 case WINED3DRTYPE_VOLUMETEXTURE:
5166 IWineD3DVolume *srcVolume = NULL;
5167 IWineD3DVolume *destVolume = NULL;
5169 for (i = 0 ; i < levels ; ++i) {
5170 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5171 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5172 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5173 IWineD3DVolume_Release(srcVolume);
5174 IWineD3DVolume_Release(destVolume);
5175 if (WINED3D_OK != hr) {
5176 WARN("(%p) : Call to update volume failed\n", This);
5184 FIXME("(%p) : Unsupported source and destination type\n", This);
5185 hr = WINED3DERR_INVALIDCALL;
5192 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5193 IWineD3DSwapChain *swapChain;
5195 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5196 if(hr == WINED3D_OK) {
5197 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5198 IWineD3DSwapChain_Release(swapChain);
5203 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5205 /* return a sensible default */
5207 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5208 FIXME("(%p) : stub\n", This);
5212 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5215 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5216 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5217 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5218 return WINED3DERR_INVALIDCALL;
5220 for (j = 0; j < 256; ++j) {
5221 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5222 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5223 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5224 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5226 TRACE("(%p) : returning\n", This);
5230 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5233 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5234 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5235 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5236 return WINED3DERR_INVALIDCALL;
5238 for (j = 0; j < 256; ++j) {
5239 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5240 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5241 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5242 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5244 TRACE("(%p) : returning\n", This);
5248 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5249 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5250 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5251 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5252 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5253 return WINED3DERR_INVALIDCALL;
5255 /*TODO: stateblocks */
5256 This->currentPalette = PaletteNumber;
5257 TRACE("(%p) : returning\n", This);
5261 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5263 if (PaletteNumber == NULL) {
5264 WARN("(%p) : returning Invalid Call\n", This);
5265 return WINED3DERR_INVALIDCALL;
5267 /*TODO: stateblocks */
5268 *PaletteNumber = This->currentPalette;
5269 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5273 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5275 static BOOL showFixmes = TRUE;
5277 FIXME("(%p) : stub\n", This);
5281 This->softwareVertexProcessing = bSoftware;
5286 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5288 static BOOL showFixmes = TRUE;
5290 FIXME("(%p) : stub\n", This);
5293 return This->softwareVertexProcessing;
5297 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5299 IWineD3DSwapChain *swapChain;
5302 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5304 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5305 if(hr == WINED3D_OK){
5306 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5307 IWineD3DSwapChain_Release(swapChain);
5309 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5315 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5317 static BOOL showfixmes = TRUE;
5318 if(nSegments != 0.0f) {
5320 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5327 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329 static BOOL showfixmes = TRUE;
5331 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5337 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5339 /** TODO: remove casts to IWineD3DSurfaceImpl
5340 * NOTE: move code to surface to accomplish this
5341 ****************************************/
5342 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5343 int srcWidth, srcHeight;
5344 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5345 WINED3DFORMAT destFormat, srcFormat;
5347 int srcLeft, destLeft, destTop;
5348 WINED3DPOOL srcPool, destPool;
5350 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5351 glDescriptor *glDescription = NULL;
5354 CONVERT_TYPES convert = NO_CONVERSION;
5356 WINED3DSURFACE_DESC winedesc;
5358 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5359 memset(&winedesc, 0, sizeof(winedesc));
5360 winedesc.Width = &srcSurfaceWidth;
5361 winedesc.Height = &srcSurfaceHeight;
5362 winedesc.Pool = &srcPool;
5363 winedesc.Format = &srcFormat;
5365 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5367 winedesc.Width = &destSurfaceWidth;
5368 winedesc.Height = &destSurfaceHeight;
5369 winedesc.Pool = &destPool;
5370 winedesc.Format = &destFormat;
5371 winedesc.Size = &destSize;
5373 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5375 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5376 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5377 return WINED3DERR_INVALIDCALL;
5380 /* This call loads the opengl surface directly, instead of copying the surface to the
5381 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5382 * copy in sysmem and use regular surface loading.
5384 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5385 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5386 if(convert != NO_CONVERSION) {
5387 return IWineD3DSurface_BltFast(pDestinationSurface,
5388 pDestPoint ? pDestPoint->x : 0,
5389 pDestPoint ? pDestPoint->y : 0,
5390 pSourceSurface, (RECT *) pSourceRect, 0);
5393 if (destFormat == WINED3DFMT_UNKNOWN) {
5394 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5395 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5397 /* Get the update surface description */
5398 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5401 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5405 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5406 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5407 checkGLcall("glActiveTextureARB");
5410 /* Make sure the surface is loaded and up to date */
5411 IWineD3DSurface_PreLoad(pDestinationSurface);
5413 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5415 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5416 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5417 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5418 srcLeft = pSourceRect ? pSourceRect->left : 0;
5419 destLeft = pDestPoint ? pDestPoint->x : 0;
5420 destTop = pDestPoint ? pDestPoint->y : 0;
5423 /* This function doesn't support compressed textures
5424 the pitch is just bytesPerPixel * width */
5425 if(srcWidth != srcSurfaceWidth || srcLeft ){
5426 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5427 offset += srcLeft * pSrcSurface->bytesPerPixel;
5428 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5430 /* TODO DXT formats */
5432 if(pSourceRect != NULL && pSourceRect->top != 0){
5433 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5435 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5437 ,glDescription->level
5442 ,glDescription->glFormat
5443 ,glDescription->glType
5444 ,IWineD3DSurface_GetData(pSourceSurface)
5448 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5450 /* need to lock the surface to get the data */
5451 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5454 /* TODO: Cube and volume support */
5456 /* not a whole row so we have to do it a line at a time */
5459 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5460 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5462 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5464 glTexSubImage2D(glDescription->target
5465 ,glDescription->level
5470 ,glDescription->glFormat
5471 ,glDescription->glType
5472 ,data /* could be quicker using */
5477 } else { /* Full width, so just write out the whole texture */
5479 if (WINED3DFMT_DXT1 == destFormat ||
5480 WINED3DFMT_DXT2 == destFormat ||
5481 WINED3DFMT_DXT3 == destFormat ||
5482 WINED3DFMT_DXT4 == destFormat ||
5483 WINED3DFMT_DXT5 == destFormat) {
5484 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5485 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5486 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5487 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5488 } if (destFormat != srcFormat) {
5489 FIXME("Updating mixed format compressed texture is not curretly support\n");
5491 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5492 glDescription->level,
5493 glDescription->glFormatInternal,
5498 IWineD3DSurface_GetData(pSourceSurface));
5501 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5506 glTexSubImage2D(glDescription->target
5507 ,glDescription->level
5512 ,glDescription->glFormat
5513 ,glDescription->glType
5514 ,IWineD3DSurface_GetData(pSourceSurface)
5518 checkGLcall("glTexSubImage2D");
5522 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5523 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5529 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5531 struct WineD3DRectPatch *patch;
5535 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5537 if(!(Handle || pRectPatchInfo)) {
5538 /* TODO: Write a test for the return value, thus the FIXME */
5539 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5540 return WINED3DERR_INVALIDCALL;
5544 i = PATCHMAP_HASHFUNC(Handle);
5546 LIST_FOR_EACH(e, &This->patches[i]) {
5547 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5548 if(patch->Handle == Handle) {
5555 TRACE("Patch does not exist. Creating a new one\n");
5556 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5557 patch->Handle = Handle;
5558 list_add_head(&This->patches[i], &patch->entry);
5560 TRACE("Found existing patch %p\n", patch);
5563 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5564 * attributes we have to tesselate, read back, and draw. This needs a patch
5565 * management structure instance. Create one.
5567 * A possible improvement is to check if a vertex shader is used, and if not directly
5570 FIXME("Drawing an uncached patch. This is slow\n");
5571 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5574 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5575 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5576 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5578 TRACE("Tesselation density or patch info changed, retesselating\n");
5580 if(pRectPatchInfo) {
5581 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5583 patch->numSegs[0] = pNumSegs[0];
5584 patch->numSegs[1] = pNumSegs[1];
5585 patch->numSegs[2] = pNumSegs[2];
5586 patch->numSegs[3] = pNumSegs[3];
5588 hr = tesselate_rectpatch(This, patch);
5590 WARN("Patch tesselation failed\n");
5592 /* Do not release the handle to store the params of the patch */
5594 HeapFree(GetProcessHeap(), 0, patch);
5600 This->currentPatch = patch;
5601 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5602 This->currentPatch = NULL;
5604 /* Destroy uncached patches */
5606 HeapFree(GetProcessHeap(), 0, patch->mem);
5607 HeapFree(GetProcessHeap(), 0, patch);
5612 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5613 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5615 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5616 FIXME("(%p) : Stub\n", This);
5620 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5623 struct WineD3DRectPatch *patch;
5625 TRACE("(%p) Handle(%d)\n", This, Handle);
5627 i = PATCHMAP_HASHFUNC(Handle);
5628 LIST_FOR_EACH(e, &This->patches[i]) {
5629 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5630 if(patch->Handle == Handle) {
5631 TRACE("Deleting patch %p\n", patch);
5632 list_remove(&patch->entry);
5633 HeapFree(GetProcessHeap(), 0, patch->mem);
5634 HeapFree(GetProcessHeap(), 0, patch);
5639 /* TODO: Write a test for the return value */
5640 FIXME("Attempt to destroy nonexistant patch\n");
5641 return WINED3DERR_INVALIDCALL;
5644 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5646 IWineD3DSwapChain *swapchain;
5648 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5649 if (SUCCEEDED(hr)) {
5650 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5657 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5662 checkGLcall("glGenFramebuffersEXT()");
5664 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5665 checkGLcall("glBindFramebuffer()");
5668 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5669 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5670 IWineD3DBaseTextureImpl *texture_impl;
5671 GLenum texttarget, target;
5674 texttarget = surface_impl->glDescription.target;
5675 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5676 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5678 IWineD3DSurface_PreLoad(surface);
5680 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5681 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5682 glBindTexture(target, old_binding);
5684 /* Update base texture states array */
5685 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5686 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5687 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5688 if (texture_impl->baseTexture.bindCount) {
5689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5692 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5695 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5696 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5698 checkGLcall("attach_surface_fbo");
5701 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5703 IWineD3DSwapChain *swapchain;
5705 swapchain = get_swapchain(surface);
5709 TRACE("Surface %p is onscreen\n", surface);
5711 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5712 buffer = surface_get_gl_buffer(surface, swapchain);
5713 glDrawBuffer(buffer);
5714 checkGLcall("glDrawBuffer()");
5716 TRACE("Surface %p is offscreen\n", surface);
5717 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5718 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5722 glEnable(GL_SCISSOR_TEST);
5724 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5726 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5727 rect->x2 - rect->x1, rect->y2 - rect->y1);
5729 checkGLcall("glScissor");
5731 glDisable(GL_SCISSOR_TEST);
5733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5735 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5738 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5739 glClear(GL_COLOR_BUFFER_BIT);
5740 checkGLcall("glClear");
5742 if (This->render_offscreen) {
5743 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5745 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5746 checkGLcall("glBindFramebuffer()");
5749 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5750 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5751 glDrawBuffer(GL_BACK);
5752 checkGLcall("glDrawBuffer()");
5756 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5757 unsigned int r, g, b, a;
5760 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5761 destfmt == WINED3DFMT_R8G8B8)
5764 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5766 a = (color & 0xff000000) >> 24;
5767 r = (color & 0x00ff0000) >> 16;
5768 g = (color & 0x0000ff00) >> 8;
5769 b = (color & 0x000000ff) >> 0;
5773 case WINED3DFMT_R5G6B5:
5774 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5781 TRACE("Returning %08x\n", ret);
5784 case WINED3DFMT_X1R5G5B5:
5785 case WINED3DFMT_A1R5G5B5:
5794 TRACE("Returning %08x\n", ret);
5798 TRACE("Returning %08x\n", a);
5801 case WINED3DFMT_X4R4G4B4:
5802 case WINED3DFMT_A4R4G4B4:
5811 TRACE("Returning %08x\n", ret);
5814 case WINED3DFMT_R3G3B2:
5821 TRACE("Returning %08x\n", ret);
5824 case WINED3DFMT_X8B8G8R8:
5825 case WINED3DFMT_A8B8G8R8:
5830 TRACE("Returning %08x\n", ret);
5833 case WINED3DFMT_A2R10G10B10:
5835 r = (r * 1024) / 256;
5836 g = (g * 1024) / 256;
5837 b = (b * 1024) / 256;
5842 TRACE("Returning %08x\n", ret);
5845 case WINED3DFMT_A2B10G10R10:
5847 r = (r * 1024) / 256;
5848 g = (g * 1024) / 256;
5849 b = (b * 1024) / 256;
5854 TRACE("Returning %08x\n", ret);
5858 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5863 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5865 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5867 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5869 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5870 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5871 return WINED3DERR_INVALIDCALL;
5874 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5875 color_fill_fbo(iface, pSurface, pRect, color);
5878 /* Just forward this to the DirectDraw blitting engine */
5879 memset(&BltFx, 0, sizeof(BltFx));
5880 BltFx.dwSize = sizeof(BltFx);
5881 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5882 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5886 /* rendertarget and deptth stencil functions */
5887 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5890 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5891 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5892 return WINED3DERR_INVALIDCALL;
5895 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5896 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5897 /* Note inc ref on returned surface */
5898 if(*ppRenderTarget != NULL)
5899 IWineD3DSurface_AddRef(*ppRenderTarget);
5903 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5905 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5906 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5907 IWineD3DSwapChainImpl *Swapchain;
5910 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5912 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5913 if(hr != WINED3D_OK) {
5914 ERR("Can't get the swapchain\n");
5918 /* Make sure to release the swapchain */
5919 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5921 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5922 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5923 return WINED3DERR_INVALIDCALL;
5925 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5926 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5927 return WINED3DERR_INVALIDCALL;
5930 if(Swapchain->frontBuffer != Front) {
5931 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5933 if(Swapchain->frontBuffer)
5934 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5935 Swapchain->frontBuffer = Front;
5937 if(Swapchain->frontBuffer) {
5938 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5942 if(Back && !Swapchain->backBuffer) {
5943 /* We need memory for the back buffer array - only one back buffer this way */
5944 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5945 if(!Swapchain->backBuffer) {
5946 ERR("Out of memory\n");
5947 return E_OUTOFMEMORY;
5951 if(Swapchain->backBuffer[0] != Back) {
5952 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5954 /* What to do about the context here in the case of multithreading? Not sure.
5955 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5958 if(!Swapchain->backBuffer[0]) {
5959 /* GL was told to draw to the front buffer at creation,
5962 glDrawBuffer(GL_BACK);
5963 checkGLcall("glDrawBuffer(GL_BACK)");
5964 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5965 Swapchain->presentParms.BackBufferCount = 1;
5967 /* That makes problems - disable for now */
5968 /* glDrawBuffer(GL_FRONT); */
5969 checkGLcall("glDrawBuffer(GL_FRONT)");
5970 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5971 Swapchain->presentParms.BackBufferCount = 0;
5975 if(Swapchain->backBuffer[0])
5976 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5977 Swapchain->backBuffer[0] = Back;
5979 if(Swapchain->backBuffer[0]) {
5980 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5982 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5990 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5992 *ppZStencilSurface = This->depthStencilBuffer;
5993 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5995 if(*ppZStencilSurface != NULL) {
5996 /* Note inc ref on returned surface */
5997 IWineD3DSurface_AddRef(*ppZStencilSurface);
6000 return WINED3DERR_NOTFOUND;
6004 /* TODO: Handle stencil attachments */
6005 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6007 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6009 TRACE("Set depth stencil to %p\n", depth_stencil);
6011 if (depth_stencil_impl) {
6012 if (depth_stencil_impl->current_renderbuffer) {
6013 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6014 checkGLcall("glFramebufferRenderbufferEXT()");
6016 IWineD3DBaseTextureImpl *texture_impl;
6017 GLenum texttarget, target;
6018 GLint old_binding = 0;
6020 texttarget = depth_stencil_impl->glDescription.target;
6021 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6022 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6024 IWineD3DSurface_PreLoad(depth_stencil);
6026 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6027 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6028 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6029 glBindTexture(target, old_binding);
6031 /* Update base texture states array */
6032 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6033 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6034 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6035 if (texture_impl->baseTexture.bindCount) {
6036 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6039 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6042 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6043 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6044 checkGLcall("glFramebufferTexture2DEXT()");
6047 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6048 checkGLcall("glFramebufferTexture2DEXT()");
6052 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6054 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6056 TRACE("Set render target %u to %p\n", idx, render_target);
6059 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6060 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6062 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6063 checkGLcall("glFramebufferTexture2DEXT()");
6065 This->draw_buffers[idx] = GL_NONE;
6069 static void check_fbo_status(IWineD3DDevice *iface) {
6070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6073 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6074 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6075 TRACE("FBO complete\n");
6077 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6079 /* Dump the FBO attachments */
6080 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6081 IWineD3DSurfaceImpl *attachment;
6084 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6085 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6087 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6088 attachment->pow2Width, attachment->pow2Height);
6091 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6093 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6094 attachment->pow2Width, attachment->pow2Height);
6100 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6102 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6103 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6105 if (!ds_impl) return FALSE;
6107 if (ds_impl->current_renderbuffer) {
6108 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6109 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6112 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6113 rt_impl->pow2Height != ds_impl->pow2Height);
6116 void apply_fbo_state(IWineD3DDevice *iface) {
6117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6120 if (This->render_offscreen) {
6121 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6123 /* Apply render targets */
6124 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6125 IWineD3DSurface *render_target = This->render_targets[i];
6126 if (This->fbo_color_attachments[i] != render_target) {
6127 set_render_target_fbo(iface, i, render_target);
6128 This->fbo_color_attachments[i] = render_target;
6132 /* Apply depth targets */
6133 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6134 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6135 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6137 if (This->stencilBufferTarget) {
6138 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6140 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6141 This->fbo_depth_attachment = This->stencilBufferTarget;
6144 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6145 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6146 checkGLcall("glDrawBuffers()");
6148 glDrawBuffer(This->draw_buffers[0]);
6149 checkGLcall("glDrawBuffer()");
6152 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6155 check_fbo_status(iface);
6158 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6159 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6161 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6162 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6165 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6166 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6167 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6168 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6171 case WINED3DTEXF_LINEAR:
6172 gl_filter = GL_LINEAR;
6176 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6177 case WINED3DTEXF_NONE:
6178 case WINED3DTEXF_POINT:
6179 gl_filter = GL_NEAREST;
6183 /* Attach src surface to src fbo */
6184 src_swapchain = get_swapchain(src_surface);
6185 if (src_swapchain) {
6188 TRACE("Source surface %p is onscreen\n", src_surface);
6189 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6192 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6193 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6194 glReadBuffer(buffer);
6195 checkGLcall("glReadBuffer()");
6197 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6198 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6200 TRACE("Source surface %p is offscreen\n", src_surface);
6202 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6203 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6204 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6205 checkGLcall("glReadBuffer()");
6209 /* Attach dst surface to dst fbo */
6210 dst_swapchain = get_swapchain(dst_surface);
6211 if (dst_swapchain) {
6214 TRACE("Destination surface %p is onscreen\n", dst_surface);
6215 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6218 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6219 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6220 glDrawBuffer(buffer);
6221 checkGLcall("glDrawBuffer()");
6223 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6224 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6226 TRACE("Destination surface %p is offscreen\n", dst_surface);
6228 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6229 if(!src_swapchain) {
6230 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6234 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6235 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6236 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6237 checkGLcall("glDrawBuffer()");
6239 glDisable(GL_SCISSOR_TEST);
6240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6243 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6244 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6245 checkGLcall("glBlitFramebuffer()");
6247 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6248 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6249 checkGLcall("glBlitFramebuffer()");
6252 if (This->render_offscreen) {
6253 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6255 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6256 checkGLcall("glBindFramebuffer()");
6259 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6260 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6261 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6262 glDrawBuffer(GL_BACK);
6263 checkGLcall("glDrawBuffer()");
6268 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6270 WINED3DVIEWPORT viewport;
6272 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6274 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6275 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6276 return WINED3DERR_INVALIDCALL;
6279 /* MSDN says that null disables the render target
6280 but a device must always be associated with a render target
6281 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6283 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6286 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6287 FIXME("Trying to set render target 0 to NULL\n");
6288 return WINED3DERR_INVALIDCALL;
6290 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6291 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);
6292 return WINED3DERR_INVALIDCALL;
6295 /* If we are trying to set what we already have, don't bother */
6296 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6297 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6300 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6301 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6302 This->render_targets[RenderTargetIndex] = pRenderTarget;
6304 /* Render target 0 is special */
6305 if(RenderTargetIndex == 0) {
6306 /* Finally, reset the viewport as the MSDN states. */
6307 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6308 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6311 viewport.MaxZ = 1.0f;
6312 viewport.MinZ = 0.0f;
6313 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6314 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6315 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6319 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6321 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6322 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6324 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6329 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6331 HRESULT hr = WINED3D_OK;
6332 IWineD3DSurface *tmp;
6334 TRACE("(%p) Swapping z-buffer\n",This);
6336 if (pNewZStencil == This->stencilBufferTarget) {
6337 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6339 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6340 * depending on the renter target implementation being used.
6341 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6342 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6343 * stencil buffer and incure an extra memory overhead
6344 ******************************************************/
6346 tmp = This->stencilBufferTarget;
6347 This->stencilBufferTarget = pNewZStencil;
6348 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6349 /* should we be calling the parent or the wined3d surface? */
6350 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6351 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6354 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6355 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6365 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6366 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6368 /* TODO: the use of Impl is deprecated. */
6369 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6370 WINED3DLOCKED_RECT lockedRect;
6372 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6374 /* some basic validation checks */
6375 if(This->cursorTexture) {
6376 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6378 glDeleteTextures(1, &This->cursorTexture);
6380 This->cursorTexture = 0;
6383 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6384 This->haveHardwareCursor = TRUE;
6386 This->haveHardwareCursor = FALSE;
6389 WINED3DLOCKED_RECT rect;
6391 /* MSDN: Cursor must be A8R8G8B8 */
6392 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6393 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6394 return WINED3DERR_INVALIDCALL;
6397 /* MSDN: Cursor must be smaller than the display mode */
6398 if(pSur->currentDesc.Width > This->ddraw_width ||
6399 pSur->currentDesc.Height > This->ddraw_height) {
6400 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);
6401 return WINED3DERR_INVALIDCALL;
6404 if (!This->haveHardwareCursor) {
6405 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6407 /* Do not store the surface's pointer because the application may
6408 * release it after setting the cursor image. Windows doesn't
6409 * addref the set surface, so we can't do this either without
6410 * creating circular refcount dependencies. Copy out the gl texture
6413 This->cursorWidth = pSur->currentDesc.Width;
6414 This->cursorHeight = pSur->currentDesc.Height;
6415 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6417 const GlPixelFormatDesc *glDesc;
6418 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6419 char *mem, *bits = (char *)rect.pBits;
6420 GLint intfmt = glDesc->glInternal;
6421 GLint format = glDesc->glFormat;
6422 GLint type = glDesc->glType;
6423 INT height = This->cursorHeight;
6424 INT width = This->cursorWidth;
6425 INT bpp = tableEntry->bpp;
6428 /* Reformat the texture memory (pitch and width can be
6430 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6431 for(i = 0; i < height; i++)
6432 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6433 IWineD3DSurface_UnlockRect(pCursorBitmap);
6436 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6437 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6438 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6441 /* Make sure that a proper texture unit is selected */
6442 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6443 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6444 checkGLcall("glActiveTextureARB");
6446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6447 /* Create a new cursor texture */
6448 glGenTextures(1, &This->cursorTexture);
6449 checkGLcall("glGenTextures");
6450 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6451 checkGLcall("glBindTexture");
6452 /* Copy the bitmap memory into the cursor texture */
6453 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6454 HeapFree(GetProcessHeap(), 0, mem);
6455 checkGLcall("glTexImage2D");
6457 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6458 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6459 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6466 FIXME("A cursor texture was not returned.\n");
6467 This->cursorTexture = 0;
6472 /* Draw a hardware cursor */
6473 ICONINFO cursorInfo;
6475 /* Create and clear maskBits because it is not needed for
6476 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6478 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6479 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6480 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6481 WINED3DLOCK_NO_DIRTY_UPDATE |
6482 WINED3DLOCK_READONLY
6484 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6485 pSur->currentDesc.Height);
6487 cursorInfo.fIcon = FALSE;
6488 cursorInfo.xHotspot = XHotSpot;
6489 cursorInfo.yHotspot = YHotSpot;
6490 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6491 pSur->currentDesc.Height, 1,
6493 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6494 pSur->currentDesc.Height, 1,
6495 32, lockedRect.pBits);
6496 IWineD3DSurface_UnlockRect(pCursorBitmap);
6497 /* Create our cursor and clean up. */
6498 cursor = CreateIconIndirect(&cursorInfo);
6500 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6501 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6502 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6503 This->hardwareCursor = cursor;
6504 HeapFree(GetProcessHeap(), 0, maskBits);
6508 This->xHotSpot = XHotSpot;
6509 This->yHotSpot = YHotSpot;
6513 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6515 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6517 This->xScreenSpace = XScreenSpace;
6518 This->yScreenSpace = YScreenSpace;
6524 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6526 BOOL oldVisible = This->bCursorVisible;
6529 TRACE("(%p) : visible(%d)\n", This, bShow);
6532 * When ShowCursor is first called it should make the cursor appear at the OS's last
6533 * known cursor position. Because of this, some applications just repetitively call
6534 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6537 This->xScreenSpace = pt.x;
6538 This->yScreenSpace = pt.y;
6540 if (This->haveHardwareCursor) {
6541 This->bCursorVisible = bShow;
6543 SetCursor(This->hardwareCursor);
6549 if (This->cursorTexture)
6550 This->bCursorVisible = bShow;
6556 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6558 TRACE("(%p) : state (%u)\n", This, This->state);
6559 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6560 switch (This->state) {
6563 case WINED3DERR_DEVICELOST:
6565 ResourceList *resourceList = This->resources;
6566 while (NULL != resourceList) {
6567 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6568 return WINED3DERR_DEVICENOTRESET;
6569 resourceList = resourceList->next;
6571 return WINED3DERR_DEVICELOST;
6573 case WINED3DERR_DRIVERINTERNALERROR:
6574 return WINED3DERR_DRIVERINTERNALERROR;
6578 return WINED3DERR_DRIVERINTERNALERROR;
6582 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6584 /** FIXME: Resource tracking needs to be done,
6585 * The closes we can do to this is set the priorities of all managed textures low
6586 * and then reset them.
6587 ***********************************************************/
6588 FIXME("(%p) : stub\n", This);
6592 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6593 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6595 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6596 if(surface->Flags & SFLAG_DIBSECTION) {
6597 /* Release the DC */
6598 SelectObject(surface->hDC, surface->dib.holdbitmap);
6599 DeleteDC(surface->hDC);
6600 /* Release the DIB section */
6601 DeleteObject(surface->dib.DIBsection);
6602 surface->dib.bitmap_data = NULL;
6603 surface->resource.allocatedMemory = NULL;
6604 surface->Flags &= ~SFLAG_DIBSECTION;
6606 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6607 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6608 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6609 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6610 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6612 surface->pow2Width = surface->pow2Height = 1;
6613 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6614 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6616 if(surface->glDescription.textureName) {
6617 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6619 glDeleteTextures(1, &surface->glDescription.textureName);
6621 surface->glDescription.textureName = 0;
6622 surface->Flags &= ~SFLAG_CLIENT;
6624 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6625 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6626 surface->Flags |= SFLAG_NONPOW2;
6628 surface->Flags &= ~SFLAG_NONPOW2;
6630 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6631 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6634 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6636 IWineD3DSwapChainImpl *swapchain;
6638 BOOL DisplayModeChanged = FALSE;
6639 WINED3DDISPLAYMODE mode;
6640 TRACE("(%p)\n", This);
6642 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6644 ERR("Failed to get the first implicit swapchain\n");
6648 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6649 * on an existing gl context, so there's no real need for recreation.
6651 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6653 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6655 TRACE("New params:\n");
6656 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6657 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6658 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6659 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6660 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6661 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6662 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6663 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6664 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6665 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6666 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6667 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6668 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6670 /* No special treatment of these parameters. Just store them */
6671 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6672 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6673 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6674 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6676 /* What to do about these? */
6677 if(pPresentationParameters->BackBufferCount != 0 &&
6678 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6679 ERR("Cannot change the back buffer count yet\n");
6681 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6682 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6683 ERR("Cannot change the back buffer format yet\n");
6685 if(pPresentationParameters->hDeviceWindow != NULL &&
6686 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6687 ERR("Cannot change the device window yet\n");
6689 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6690 ERR("What do do about a changed auto depth stencil parameter?\n");
6693 if(pPresentationParameters->Windowed) {
6694 mode.Width = swapchain->orig_width;
6695 mode.Height = swapchain->orig_height;
6696 mode.RefreshRate = 0;
6697 mode.Format = swapchain->presentParms.BackBufferFormat;
6699 mode.Width = pPresentationParameters->BackBufferWidth;
6700 mode.Height = pPresentationParameters->BackBufferHeight;
6701 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6702 mode.Format = swapchain->presentParms.BackBufferFormat;
6705 /* Should Width == 800 && Height == 0 set 800x600? */
6706 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6707 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6708 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6715 vp.Width = pPresentationParameters->BackBufferWidth;
6716 vp.Height = pPresentationParameters->BackBufferHeight;
6720 if(!pPresentationParameters->Windowed) {
6721 DisplayModeChanged = TRUE;
6723 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6724 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6726 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6727 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6728 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6731 /* Now set the new viewport */
6732 IWineD3DDevice_SetViewport(iface, &vp);
6735 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6736 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6737 DisplayModeChanged) {
6739 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6740 if(!pPresentationParameters->Windowed) {
6741 IWineD3DDevice_SetFullscreen(iface, TRUE);
6744 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6746 /* Switching out of fullscreen mode? First set the original res, then change the window */
6747 if(pPresentationParameters->Windowed) {
6748 IWineD3DDevice_SetFullscreen(iface, FALSE);
6750 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6753 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6757 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6759 /** FIXME: always true at the moment **/
6760 if(!bEnableDialogs) {
6761 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6767 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6769 TRACE("(%p) : pParameters %p\n", This, pParameters);
6771 *pParameters = This->createParms;
6775 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6776 IWineD3DSwapChain *swapchain;
6777 HRESULT hrc = WINED3D_OK;
6779 TRACE("Relaying to swapchain\n");
6781 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6782 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6783 IWineD3DSwapChain_Release(swapchain);
6788 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6789 IWineD3DSwapChain *swapchain;
6790 HRESULT hrc = WINED3D_OK;
6792 TRACE("Relaying to swapchain\n");
6794 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6795 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6796 IWineD3DSwapChain_Release(swapchain);
6802 /** ********************************************************
6803 * Notification functions
6804 ** ********************************************************/
6805 /** This function must be called in the release of a resource when ref == 0,
6806 * the contents of resource must still be correct,
6807 * any handels to other resource held by the caller must be closed
6808 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6809 *****************************************************/
6810 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6812 ResourceList* resourceList;
6814 TRACE("(%p) : resource %p\n", This, resource);
6815 /* add a new texture to the frot of the linked list */
6816 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6817 resourceList->resource = resource;
6819 /* Get the old head */
6820 resourceList->next = This->resources;
6822 This->resources = resourceList;
6823 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6828 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6830 ResourceList* resourceList = NULL;
6831 ResourceList* previousResourceList = NULL;
6833 TRACE("(%p) : resource %p\n", This, resource);
6835 resourceList = This->resources;
6837 while (resourceList != NULL) {
6838 if(resourceList->resource == resource) break;
6839 previousResourceList = resourceList;
6840 resourceList = resourceList->next;
6843 if (resourceList == NULL) {
6844 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6847 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6849 /* make sure we don't leave a hole in the list */
6850 if (previousResourceList != NULL) {
6851 previousResourceList->next = resourceList->next;
6853 This->resources = resourceList->next;
6860 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6864 TRACE("(%p) : resource %p\n", This, resource);
6865 switch(IWineD3DResource_GetType(resource)){
6866 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6867 case WINED3DRTYPE_SURFACE: {
6870 /* Cleanup any FBO attachments if d3d is enabled */
6871 if(This->d3d_initialized) {
6872 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6873 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6874 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6875 set_render_target_fbo(iface, i, NULL);
6876 This->fbo_color_attachments[i] = NULL;
6879 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6880 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6881 set_depth_stencil_fbo(iface, NULL);
6882 This->fbo_depth_attachment = NULL;
6888 case WINED3DRTYPE_TEXTURE:
6889 case WINED3DRTYPE_CUBETEXTURE:
6890 case WINED3DRTYPE_VOLUMETEXTURE:
6891 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6892 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6893 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6894 This->stateBlock->textures[counter] = NULL;
6896 if (This->updateStateBlock != This->stateBlock ){
6897 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6898 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6899 This->updateStateBlock->textures[counter] = NULL;
6904 case WINED3DRTYPE_VOLUME:
6905 /* TODO: nothing really? */
6907 case WINED3DRTYPE_VERTEXBUFFER:
6908 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6911 TRACE("Cleaning up stream pointers\n");
6913 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6914 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6915 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6917 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6918 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6919 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6920 This->updateStateBlock->streamSource[streamNumber] = 0;
6921 /* Set changed flag? */
6924 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) */
6925 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6926 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6927 This->stateBlock->streamSource[streamNumber] = 0;
6930 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6931 else { /* This shouldn't happen */
6932 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6939 case WINED3DRTYPE_INDEXBUFFER:
6940 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6941 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6942 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6943 This->updateStateBlock->pIndexData = NULL;
6946 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6947 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6948 This->stateBlock->pIndexData = NULL;
6954 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6959 /* Remove the resoruce from the resourceStore */
6960 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6962 TRACE("Resource released\n");
6966 /**********************************************************
6967 * IWineD3DDevice VTbl follows
6968 **********************************************************/
6970 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6972 /*** IUnknown methods ***/
6973 IWineD3DDeviceImpl_QueryInterface,
6974 IWineD3DDeviceImpl_AddRef,
6975 IWineD3DDeviceImpl_Release,
6976 /*** IWineD3DDevice methods ***/
6977 IWineD3DDeviceImpl_GetParent,
6978 /*** Creation methods**/
6979 IWineD3DDeviceImpl_CreateVertexBuffer,
6980 IWineD3DDeviceImpl_CreateIndexBuffer,
6981 IWineD3DDeviceImpl_CreateStateBlock,
6982 IWineD3DDeviceImpl_CreateSurface,
6983 IWineD3DDeviceImpl_CreateTexture,
6984 IWineD3DDeviceImpl_CreateVolumeTexture,
6985 IWineD3DDeviceImpl_CreateVolume,
6986 IWineD3DDeviceImpl_CreateCubeTexture,
6987 IWineD3DDeviceImpl_CreateQuery,
6988 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6989 IWineD3DDeviceImpl_CreateVertexDeclaration,
6990 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6991 IWineD3DDeviceImpl_CreateVertexShader,
6992 IWineD3DDeviceImpl_CreatePixelShader,
6993 IWineD3DDeviceImpl_CreatePalette,
6994 /*** Odd functions **/
6995 IWineD3DDeviceImpl_Init3D,
6996 IWineD3DDeviceImpl_Uninit3D,
6997 IWineD3DDeviceImpl_SetFullscreen,
6998 IWineD3DDeviceImpl_SetMultithreaded,
6999 IWineD3DDeviceImpl_EvictManagedResources,
7000 IWineD3DDeviceImpl_GetAvailableTextureMem,
7001 IWineD3DDeviceImpl_GetBackBuffer,
7002 IWineD3DDeviceImpl_GetCreationParameters,
7003 IWineD3DDeviceImpl_GetDeviceCaps,
7004 IWineD3DDeviceImpl_GetDirect3D,
7005 IWineD3DDeviceImpl_GetDisplayMode,
7006 IWineD3DDeviceImpl_SetDisplayMode,
7007 IWineD3DDeviceImpl_GetHWND,
7008 IWineD3DDeviceImpl_SetHWND,
7009 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7010 IWineD3DDeviceImpl_GetRasterStatus,
7011 IWineD3DDeviceImpl_GetSwapChain,
7012 IWineD3DDeviceImpl_Reset,
7013 IWineD3DDeviceImpl_SetDialogBoxMode,
7014 IWineD3DDeviceImpl_SetCursorProperties,
7015 IWineD3DDeviceImpl_SetCursorPosition,
7016 IWineD3DDeviceImpl_ShowCursor,
7017 IWineD3DDeviceImpl_TestCooperativeLevel,
7018 /*** Getters and setters **/
7019 IWineD3DDeviceImpl_SetClipPlane,
7020 IWineD3DDeviceImpl_GetClipPlane,
7021 IWineD3DDeviceImpl_SetClipStatus,
7022 IWineD3DDeviceImpl_GetClipStatus,
7023 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7024 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7025 IWineD3DDeviceImpl_SetDepthStencilSurface,
7026 IWineD3DDeviceImpl_GetDepthStencilSurface,
7027 IWineD3DDeviceImpl_SetFVF,
7028 IWineD3DDeviceImpl_GetFVF,
7029 IWineD3DDeviceImpl_SetGammaRamp,
7030 IWineD3DDeviceImpl_GetGammaRamp,
7031 IWineD3DDeviceImpl_SetIndices,
7032 IWineD3DDeviceImpl_GetIndices,
7033 IWineD3DDeviceImpl_SetBaseVertexIndex,
7034 IWineD3DDeviceImpl_GetBaseVertexIndex,
7035 IWineD3DDeviceImpl_SetLight,
7036 IWineD3DDeviceImpl_GetLight,
7037 IWineD3DDeviceImpl_SetLightEnable,
7038 IWineD3DDeviceImpl_GetLightEnable,
7039 IWineD3DDeviceImpl_SetMaterial,
7040 IWineD3DDeviceImpl_GetMaterial,
7041 IWineD3DDeviceImpl_SetNPatchMode,
7042 IWineD3DDeviceImpl_GetNPatchMode,
7043 IWineD3DDeviceImpl_SetPaletteEntries,
7044 IWineD3DDeviceImpl_GetPaletteEntries,
7045 IWineD3DDeviceImpl_SetPixelShader,
7046 IWineD3DDeviceImpl_GetPixelShader,
7047 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7048 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7049 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7050 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7051 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7052 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7053 IWineD3DDeviceImpl_SetRenderState,
7054 IWineD3DDeviceImpl_GetRenderState,
7055 IWineD3DDeviceImpl_SetRenderTarget,
7056 IWineD3DDeviceImpl_GetRenderTarget,
7057 IWineD3DDeviceImpl_SetFrontBackBuffers,
7058 IWineD3DDeviceImpl_SetSamplerState,
7059 IWineD3DDeviceImpl_GetSamplerState,
7060 IWineD3DDeviceImpl_SetScissorRect,
7061 IWineD3DDeviceImpl_GetScissorRect,
7062 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7063 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7064 IWineD3DDeviceImpl_SetStreamSource,
7065 IWineD3DDeviceImpl_GetStreamSource,
7066 IWineD3DDeviceImpl_SetStreamSourceFreq,
7067 IWineD3DDeviceImpl_GetStreamSourceFreq,
7068 IWineD3DDeviceImpl_SetTexture,
7069 IWineD3DDeviceImpl_GetTexture,
7070 IWineD3DDeviceImpl_SetTextureStageState,
7071 IWineD3DDeviceImpl_GetTextureStageState,
7072 IWineD3DDeviceImpl_SetTransform,
7073 IWineD3DDeviceImpl_GetTransform,
7074 IWineD3DDeviceImpl_SetVertexDeclaration,
7075 IWineD3DDeviceImpl_GetVertexDeclaration,
7076 IWineD3DDeviceImpl_SetVertexShader,
7077 IWineD3DDeviceImpl_GetVertexShader,
7078 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7079 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7080 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7081 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7082 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7083 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7084 IWineD3DDeviceImpl_SetViewport,
7085 IWineD3DDeviceImpl_GetViewport,
7086 IWineD3DDeviceImpl_MultiplyTransform,
7087 IWineD3DDeviceImpl_ValidateDevice,
7088 IWineD3DDeviceImpl_ProcessVertices,
7089 /*** State block ***/
7090 IWineD3DDeviceImpl_BeginStateBlock,
7091 IWineD3DDeviceImpl_EndStateBlock,
7092 /*** Scene management ***/
7093 IWineD3DDeviceImpl_BeginScene,
7094 IWineD3DDeviceImpl_EndScene,
7095 IWineD3DDeviceImpl_Present,
7096 IWineD3DDeviceImpl_Clear,
7098 IWineD3DDeviceImpl_DrawPrimitive,
7099 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7100 IWineD3DDeviceImpl_DrawPrimitiveUP,
7101 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7102 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7103 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7104 IWineD3DDeviceImpl_DrawRectPatch,
7105 IWineD3DDeviceImpl_DrawTriPatch,
7106 IWineD3DDeviceImpl_DeletePatch,
7107 IWineD3DDeviceImpl_ColorFill,
7108 IWineD3DDeviceImpl_UpdateTexture,
7109 IWineD3DDeviceImpl_UpdateSurface,
7110 IWineD3DDeviceImpl_GetFrontBufferData,
7111 /*** object tracking ***/
7112 IWineD3DDeviceImpl_ResourceReleased
7116 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7117 WINED3DRS_ALPHABLENDENABLE ,
7118 WINED3DRS_ALPHAFUNC ,
7119 WINED3DRS_ALPHAREF ,
7120 WINED3DRS_ALPHATESTENABLE ,
7122 WINED3DRS_COLORWRITEENABLE ,
7123 WINED3DRS_DESTBLEND ,
7124 WINED3DRS_DITHERENABLE ,
7125 WINED3DRS_FILLMODE ,
7126 WINED3DRS_FOGDENSITY ,
7128 WINED3DRS_FOGSTART ,
7129 WINED3DRS_LASTPIXEL ,
7130 WINED3DRS_SHADEMODE ,
7131 WINED3DRS_SRCBLEND ,
7132 WINED3DRS_STENCILENABLE ,
7133 WINED3DRS_STENCILFAIL ,
7134 WINED3DRS_STENCILFUNC ,
7135 WINED3DRS_STENCILMASK ,
7136 WINED3DRS_STENCILPASS ,
7137 WINED3DRS_STENCILREF ,
7138 WINED3DRS_STENCILWRITEMASK ,
7139 WINED3DRS_STENCILZFAIL ,
7140 WINED3DRS_TEXTUREFACTOR ,
7151 WINED3DRS_ZWRITEENABLE
7154 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7155 WINED3DTSS_ADDRESSW ,
7156 WINED3DTSS_ALPHAARG0 ,
7157 WINED3DTSS_ALPHAARG1 ,
7158 WINED3DTSS_ALPHAARG2 ,
7159 WINED3DTSS_ALPHAOP ,
7160 WINED3DTSS_BUMPENVLOFFSET ,
7161 WINED3DTSS_BUMPENVLSCALE ,
7162 WINED3DTSS_BUMPENVMAT00 ,
7163 WINED3DTSS_BUMPENVMAT01 ,
7164 WINED3DTSS_BUMPENVMAT10 ,
7165 WINED3DTSS_BUMPENVMAT11 ,
7166 WINED3DTSS_COLORARG0 ,
7167 WINED3DTSS_COLORARG1 ,
7168 WINED3DTSS_COLORARG2 ,
7169 WINED3DTSS_COLOROP ,
7170 WINED3DTSS_RESULTARG ,
7171 WINED3DTSS_TEXCOORDINDEX ,
7172 WINED3DTSS_TEXTURETRANSFORMFLAGS
7175 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7176 WINED3DSAMP_ADDRESSU ,
7177 WINED3DSAMP_ADDRESSV ,
7178 WINED3DSAMP_ADDRESSW ,
7179 WINED3DSAMP_BORDERCOLOR ,
7180 WINED3DSAMP_MAGFILTER ,
7181 WINED3DSAMP_MINFILTER ,
7182 WINED3DSAMP_MIPFILTER ,
7183 WINED3DSAMP_MIPMAPLODBIAS ,
7184 WINED3DSAMP_MAXMIPLEVEL ,
7185 WINED3DSAMP_MAXANISOTROPY ,
7186 WINED3DSAMP_SRGBTEXTURE ,
7187 WINED3DSAMP_ELEMENTINDEX
7190 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7192 WINED3DRS_AMBIENTMATERIALSOURCE ,
7193 WINED3DRS_CLIPPING ,
7194 WINED3DRS_CLIPPLANEENABLE ,
7195 WINED3DRS_COLORVERTEX ,
7196 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7197 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7198 WINED3DRS_FOGDENSITY ,
7200 WINED3DRS_FOGSTART ,
7201 WINED3DRS_FOGTABLEMODE ,
7202 WINED3DRS_FOGVERTEXMODE ,
7203 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7204 WINED3DRS_LIGHTING ,
7205 WINED3DRS_LOCALVIEWER ,
7206 WINED3DRS_MULTISAMPLEANTIALIAS ,
7207 WINED3DRS_MULTISAMPLEMASK ,
7208 WINED3DRS_NORMALIZENORMALS ,
7209 WINED3DRS_PATCHEDGESTYLE ,
7210 WINED3DRS_POINTSCALE_A ,
7211 WINED3DRS_POINTSCALE_B ,
7212 WINED3DRS_POINTSCALE_C ,
7213 WINED3DRS_POINTSCALEENABLE ,
7214 WINED3DRS_POINTSIZE ,
7215 WINED3DRS_POINTSIZE_MAX ,
7216 WINED3DRS_POINTSIZE_MIN ,
7217 WINED3DRS_POINTSPRITEENABLE ,
7218 WINED3DRS_RANGEFOGENABLE ,
7219 WINED3DRS_SPECULARMATERIALSOURCE ,
7220 WINED3DRS_TWEENFACTOR ,
7221 WINED3DRS_VERTEXBLEND ,
7222 WINED3DRS_CULLMODE ,
7226 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7227 WINED3DTSS_TEXCOORDINDEX ,
7228 WINED3DTSS_TEXTURETRANSFORMFLAGS
7231 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7232 WINED3DSAMP_DMAPOFFSET
7235 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7236 DWORD rep = StateTable[state].representative;
7240 WineD3DContext *context;
7243 for(i = 0; i < This->numContexts; i++) {
7244 context = This->contexts[i];
7245 if(isStateDirty(context, rep)) continue;
7247 context->dirtyArray[context->numDirtyEntries++] = rep;
7250 context->isStateDirty[idx] |= (1 << shift);