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);
526 } else if (Type == WINED3DSBT_PIXELSTATE) {
528 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
529 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
531 object->changed.pixelShader = TRUE;
533 /* Pixel Shader Constants */
534 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
535 object->contained_ps_consts_f[i] = i;
536 object->changed.pixelShaderConstantsF[i] = TRUE;
538 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
539 for (i = 0; i < MAX_CONST_B; ++i) {
540 object->contained_ps_consts_b[i] = i;
541 object->changed.pixelShaderConstantsB[i] = TRUE;
543 object->num_contained_ps_consts_b = MAX_CONST_B;
544 for (i = 0; i < MAX_CONST_I; ++i) {
545 object->contained_ps_consts_i[i] = i;
546 object->changed.pixelShaderConstantsI[i] = TRUE;
548 object->num_contained_ps_consts_i = MAX_CONST_I;
550 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
551 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
552 object->contained_render_states[i] = SavedPixelStates_R[i];
554 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
555 for (j = 0; j < MAX_TEXTURES; j++) {
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
557 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
558 object->contained_tss_states[object->num_contained_tss_states].stage = j;
559 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
560 object->num_contained_tss_states++;
563 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
564 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
565 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
566 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
567 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
568 object->num_contained_sampler_states++;
572 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
573 * on them. This makes releasing the buffer easier
575 for(i = 0; i < MAX_STREAMS; i++) {
576 object->streamSource[i] = NULL;
578 object->pIndexData = NULL;
580 } else if (Type == WINED3DSBT_VERTEXSTATE) {
582 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
583 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
585 object->changed.vertexShader = TRUE;
587 /* Vertex Shader Constants */
588 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
589 object->changed.vertexShaderConstantsF[i] = TRUE;
590 object->contained_vs_consts_f[i] = i;
592 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
593 for (i = 0; i < MAX_CONST_B; ++i) {
594 object->changed.vertexShaderConstantsB[i] = TRUE;
595 object->contained_vs_consts_b[i] = i;
597 object->num_contained_vs_consts_b = MAX_CONST_B;
598 for (i = 0; i < MAX_CONST_I; ++i) {
599 object->changed.vertexShaderConstantsI[i] = TRUE;
600 object->contained_vs_consts_i[i] = i;
602 object->num_contained_vs_consts_i = MAX_CONST_I;
603 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
604 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
605 object->contained_render_states[i] = SavedVertexStates_R[i];
607 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
608 for (j = 0; j < MAX_TEXTURES; j++) {
609 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
610 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
611 object->contained_tss_states[object->num_contained_tss_states].stage = j;
612 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
613 object->num_contained_tss_states++;
616 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
617 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
618 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
619 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
620 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
621 object->num_contained_sampler_states++;
625 for(j = 0; j < LIGHTMAP_SIZE; j++) {
627 LIST_FOR_EACH(e, &object->lightMap[j]) {
628 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
629 light->changed = TRUE;
630 light->enabledChanged = TRUE;
634 for(i = 0; i < MAX_STREAMS; i++) {
635 if(object->streamSource[i]) {
636 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
639 object->pIndexData = NULL;
641 FIXME("Unrecognized state block type %d\n", Type);
644 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
648 /* ************************************
650 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
653 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
655 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.
657 ******************************** */
659 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) {
660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
661 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
662 unsigned int Size = 1;
663 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
664 TRACE("(%p) Create surface\n",This);
666 /** FIXME: Check ranges on the inputs are valid
669 * [in] Quality level. The valid range is between zero and one less than the level
670 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
671 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
672 * values of paired render targets, depth stencil surfaces, and the MultiSample type
674 *******************************/
679 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
681 * If this flag is set, the contents of the depth stencil buffer will be
682 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
683 * with a different depth surface.
685 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
686 ***************************/
688 if(MultisampleQuality < 0) {
689 FIXME("Invalid multisample level %d\n", MultisampleQuality);
690 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
693 if(MultisampleQuality > 0) {
694 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
695 MultisampleQuality=0;
698 /** FIXME: Check that the format is supported
700 *******************************/
702 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
703 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
705 *********************************/
706 if (WINED3DFMT_UNKNOWN == Format) {
708 } else if (Format == WINED3DFMT_DXT1) {
709 /* DXT1 is half byte per pixel */
710 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
712 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
713 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
714 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
716 /* The pitch is a multiple of 4 bytes */
717 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
721 /** Create and initialise the surface resource **/
722 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
723 /* "Standalone" surface */
724 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
726 object->currentDesc.Width = Width;
727 object->currentDesc.Height = Height;
728 object->currentDesc.MultiSampleType = MultiSample;
729 object->currentDesc.MultiSampleQuality = MultisampleQuality;
730 object->glDescription.level = Level;
734 object->Flags |= Discard ? SFLAG_DISCARD : 0;
735 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
736 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
739 if (WINED3DFMT_UNKNOWN != Format) {
740 object->bytesPerPixel = tableEntry->bpp;
742 object->bytesPerPixel = 0;
745 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
747 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
749 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
750 * this function is too deep to need to care about things like this.
751 * Levels need to be checked too, and possibly Type since they all affect what can be done.
752 * ****************************************/
754 case WINED3DPOOL_SCRATCH:
756 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
757 "which are mutually exclusive, setting lockable to TRUE\n");
760 case WINED3DPOOL_SYSTEMMEM:
761 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
762 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
763 case WINED3DPOOL_MANAGED:
764 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
765 "Usage of DYNAMIC which are mutually exclusive, not doing "
766 "anything just telling you.\n");
768 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
769 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
770 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
771 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
774 FIXME("(%p) Unknown pool %d\n", This, Pool);
778 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
779 FIXME("Trying to create a render target that isn't in the default pool\n");
782 /* mark the texture as dirty so that it gets loaded first time around*/
783 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
784 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
785 This, Width, Height, Format, debug_d3dformat(Format),
786 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
788 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
789 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
790 This->ddraw_primary = (IWineD3DSurface *) object;
792 /* Look at the implementation and set the correct Vtable */
795 /* Check if a 3D adapter is available when creating gl surfaces */
797 ERR("OpenGL surfaces are not available without opengl\n");
798 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
799 HeapFree(GetProcessHeap(), 0, object);
800 return WINED3DERR_NOTAVAILABLE;
805 object->lpVtbl = &IWineGDISurface_Vtbl;
809 /* To be sure to catch this */
810 ERR("Unknown requested surface implementation %d!\n", Impl);
811 IWineD3DSurface_Release((IWineD3DSurface *) object);
812 return WINED3DERR_INVALIDCALL;
815 list_init(&object->renderbuffers);
817 /* Call the private setup routine */
818 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
822 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
823 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
824 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
825 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
828 IWineD3DTextureImpl *object;
833 unsigned int pow2Width;
834 unsigned int pow2Height;
837 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
838 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
839 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
841 /* TODO: It should only be possible to create textures for formats
842 that are reported as supported */
843 if (WINED3DFMT_UNKNOWN >= Format) {
844 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
845 return WINED3DERR_INVALIDCALL;
848 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
849 D3DINITIALIZEBASETEXTURE(object->baseTexture);
850 object->width = Width;
851 object->height = Height;
853 /** Non-power2 support **/
854 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
858 /* Find the nearest pow2 match */
859 pow2Width = pow2Height = 1;
860 while (pow2Width < Width) pow2Width <<= 1;
861 while (pow2Height < Height) pow2Height <<= 1;
864 /** FIXME: add support for real non-power-two if it's provided by the video card **/
865 /* Precalculated scaling for 'faked' non power of two texture coords */
866 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
867 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
868 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
870 /* Calculate levels for mip mapping */
872 TRACE("calculating levels %d\n", object->baseTexture.levels);
873 object->baseTexture.levels++;
876 while (tmpW > 1 || tmpH > 1) {
877 tmpW = max(1, tmpW >> 1);
878 tmpH = max(1, tmpH >> 1);
879 object->baseTexture.levels++;
881 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
884 /* Generate all the surfaces */
887 for (i = 0; i < object->baseTexture.levels; i++)
889 /* use the callback to create the texture surface */
890 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
891 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
892 FIXME("Failed to create surface %p\n", object);
894 object->surfaces[i] = NULL;
895 IWineD3DTexture_Release((IWineD3DTexture *)object);
901 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
902 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
903 /* calculate the next mipmap level */
904 tmpW = max(1, tmpW >> 1);
905 tmpH = max(1, tmpH >> 1);
908 TRACE("(%p) : Created texture %p\n", This, object);
912 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
913 UINT Width, UINT Height, UINT Depth,
914 UINT Levels, DWORD Usage,
915 WINED3DFORMAT Format, WINED3DPOOL Pool,
916 IWineD3DVolumeTexture **ppVolumeTexture,
917 HANDLE *pSharedHandle, IUnknown *parent,
918 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
921 IWineD3DVolumeTextureImpl *object;
927 /* TODO: It should only be possible to create textures for formats
928 that are reported as supported */
929 if (WINED3DFMT_UNKNOWN >= Format) {
930 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
931 return WINED3DERR_INVALIDCALL;
934 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
935 D3DINITIALIZEBASETEXTURE(object->baseTexture);
937 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
938 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
940 object->width = Width;
941 object->height = Height;
942 object->depth = Depth;
944 /* Calculate levels for mip mapping */
946 object->baseTexture.levels++;
950 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
951 tmpW = max(1, tmpW >> 1);
952 tmpH = max(1, tmpH >> 1);
953 tmpD = max(1, tmpD >> 1);
954 object->baseTexture.levels++;
956 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
959 /* Generate all the surfaces */
964 for (i = 0; i < object->baseTexture.levels; i++)
967 /* Create the volume */
968 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
969 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
972 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
973 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
974 *ppVolumeTexture = NULL;
978 /* Set its container to this object */
979 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
981 /* calcualte the next mipmap level */
982 tmpW = max(1, tmpW >> 1);
983 tmpH = max(1, tmpH >> 1);
984 tmpD = max(1, tmpD >> 1);
987 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
988 TRACE("(%p) : Created volume texture %p\n", This, object);
992 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
993 UINT Width, UINT Height, UINT Depth,
995 WINED3DFORMAT Format, WINED3DPOOL Pool,
996 IWineD3DVolume** ppVolume,
997 HANDLE* pSharedHandle, IUnknown *parent) {
999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1000 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1001 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1003 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1005 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1006 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1008 object->currentDesc.Width = Width;
1009 object->currentDesc.Height = Height;
1010 object->currentDesc.Depth = Depth;
1011 object->bytesPerPixel = formatDesc->bpp;
1013 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1014 object->lockable = TRUE;
1015 object->locked = FALSE;
1016 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1017 object->dirty = TRUE;
1019 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1022 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1023 UINT Levels, DWORD Usage,
1024 WINED3DFORMAT Format, WINED3DPOOL Pool,
1025 IWineD3DCubeTexture **ppCubeTexture,
1026 HANDLE *pSharedHandle, IUnknown *parent,
1027 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1030 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1034 unsigned int pow2EdgeLength = EdgeLength;
1036 /* TODO: It should only be possible to create textures for formats
1037 that are reported as supported */
1038 if (WINED3DFMT_UNKNOWN >= Format) {
1039 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1040 return WINED3DERR_INVALIDCALL;
1043 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1044 WARN("(%p) : Tried to create not supported cube texture\n", This);
1045 return WINED3DERR_INVALIDCALL;
1048 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1049 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1051 TRACE("(%p) Create Cube Texture\n", This);
1053 /** Non-power2 support **/
1055 /* Find the nearest pow2 match */
1057 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1059 object->edgeLength = EdgeLength;
1060 /* TODO: support for native non-power 2 */
1061 /* Precalculated scaling for 'faked' non power of two texture coords */
1062 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1064 /* Calculate levels for mip mapping */
1066 object->baseTexture.levels++;
1069 tmpW = max(1, tmpW >> 1);
1070 object->baseTexture.levels++;
1072 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1075 /* Generate all the surfaces */
1077 for (i = 0; i < object->baseTexture.levels; i++) {
1079 /* Create the 6 faces */
1080 for (j = 0; j < 6; j++) {
1082 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1083 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1085 if(hr!= WINED3D_OK) {
1089 for (l = 0; l < j; l++) {
1090 IWineD3DSurface_Release(object->surfaces[j][i]);
1092 for (k = 0; k < i; k++) {
1093 for (l = 0; l < 6; l++) {
1094 IWineD3DSurface_Release(object->surfaces[l][j]);
1098 FIXME("(%p) Failed to create surface\n",object);
1099 HeapFree(GetProcessHeap(),0,object);
1100 *ppCubeTexture = NULL;
1103 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1104 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1106 tmpW = max(1, tmpW >> 1);
1109 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1110 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1114 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1115 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1116 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1117 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1119 /* Just a check to see if we support this type of query */
1121 case WINED3DQUERYTYPE_OCCLUSION:
1122 TRACE("(%p) occlusion query\n", This);
1123 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1126 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1129 case WINED3DQUERYTYPE_EVENT:
1130 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1131 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1132 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1134 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1139 case WINED3DQUERYTYPE_VCACHE:
1140 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1141 case WINED3DQUERYTYPE_VERTEXSTATS:
1142 case WINED3DQUERYTYPE_TIMESTAMP:
1143 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1144 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1145 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1146 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1147 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1148 case WINED3DQUERYTYPE_PIXELTIMINGS:
1149 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1150 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1152 FIXME("(%p) Unhandled query type %d\n", This, Type);
1154 if(NULL == ppQuery || hr != WINED3D_OK) {
1158 D3DCREATEOBJECTINSTANCE(object, Query)
1159 object->type = Type;
1160 /* allocated the 'extended' data based on the type of query requested */
1162 case WINED3DQUERYTYPE_OCCLUSION:
1163 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1164 TRACE("(%p) Allocating data for an occlusion query\n", This);
1165 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1166 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1167 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1170 case WINED3DQUERYTYPE_EVENT:
1171 if(GL_SUPPORT(APPLE_FENCE)) {
1172 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1173 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1174 checkGLcall("glGenFencesAPPLE");
1175 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1176 } else if(GL_SUPPORT(NV_FENCE)) {
1177 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1178 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1179 checkGLcall("glGenFencesNV");
1180 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1184 case WINED3DQUERYTYPE_VCACHE:
1185 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1186 case WINED3DQUERYTYPE_VERTEXSTATS:
1187 case WINED3DQUERYTYPE_TIMESTAMP:
1188 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1189 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1190 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1191 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1192 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1193 case WINED3DQUERYTYPE_PIXELTIMINGS:
1194 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1195 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1197 object->extendedData = 0;
1198 FIXME("(%p) Unhandled query type %d\n",This , Type);
1200 TRACE("(%p) : Created Query %p\n", This, object);
1204 /*****************************************************************************
1205 * IWineD3DDeviceImpl_SetupFullscreenWindow
1207 * Helper function that modifies a HWND's Style and ExStyle for proper
1211 * iface: Pointer to the IWineD3DDevice interface
1212 * window: Window to setup
1214 *****************************************************************************/
1215 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1218 LONG style, exStyle;
1219 /* Don't do anything if an original style is stored.
1220 * That shouldn't happen
1222 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1223 if (This->style || This->exStyle) {
1224 ERR("(%p): Want to change the window parameters of HWND %p, but "
1225 "another style is stored for restoration afterwards\n", This, window);
1228 /* Get the parameters and save them */
1229 style = GetWindowLongW(window, GWL_STYLE);
1230 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1231 This->style = style;
1232 This->exStyle = exStyle;
1234 /* Filter out window decorations */
1235 style &= ~WS_CAPTION;
1236 style &= ~WS_THICKFRAME;
1237 exStyle &= ~WS_EX_WINDOWEDGE;
1238 exStyle &= ~WS_EX_CLIENTEDGE;
1240 /* Make sure the window is managed, otherwise we won't get keyboard input */
1241 style |= WS_POPUP | WS_SYSMENU;
1243 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1244 This->style, This->exStyle, style, exStyle);
1246 SetWindowLongW(window, GWL_STYLE, style);
1247 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1249 /* Inform the window about the update. */
1250 SetWindowPos(window, HWND_TOP, 0, 0,
1251 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1252 ShowWindow(window, SW_NORMAL);
1255 /*****************************************************************************
1256 * IWineD3DDeviceImpl_RestoreWindow
1258 * Helper function that restores a windows' properties when taking it out
1259 * of fullscreen mode
1262 * iface: Pointer to the IWineD3DDevice interface
1263 * window: Window to setup
1265 *****************************************************************************/
1266 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1269 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1270 * switch, do nothing
1272 if (!This->style && !This->exStyle) return;
1274 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1275 This, window, This->style, This->exStyle);
1277 SetWindowLongW(window, GWL_STYLE, This->style);
1278 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1280 /* Delete the old values */
1284 /* Inform the window about the update */
1285 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1286 0, 0, 0, 0, /* Pos, Size, ignored */
1287 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1290 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1291 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1293 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1294 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1299 HRESULT hr = WINED3D_OK;
1300 IUnknown *bufferParent;
1302 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1304 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1305 * does a device hold a reference to a swap chain giving them a lifetime of the device
1306 * or does the swap chain notify the device of its destruction.
1307 *******************************/
1309 /* Check the params */
1310 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1311 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1312 return WINED3DERR_INVALIDCALL;
1313 } else if (pPresentationParameters->BackBufferCount > 1) {
1314 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");
1317 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1319 /*********************
1320 * Lookup the window Handle and the relating X window handle
1321 ********************/
1323 /* Setup hwnd we are using, plus which display this equates to */
1324 object->win_handle = pPresentationParameters->hDeviceWindow;
1325 if (!object->win_handle) {
1326 object->win_handle = This->createParms.hFocusWindow;
1329 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1330 hDc = GetDC(object->win_handle);
1331 TRACE("Using hDc %p\n", hDc);
1334 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1335 return WINED3DERR_NOTAVAILABLE;
1338 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1339 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1340 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1341 ReleaseDC(object->win_handle, hDc);
1343 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1344 * then the corresponding dimension of the client area of the hDeviceWindow
1345 * (or the focus window, if hDeviceWindow is NULL) is taken.
1346 **********************/
1348 if (pPresentationParameters->Windowed &&
1349 ((pPresentationParameters->BackBufferWidth == 0) ||
1350 (pPresentationParameters->BackBufferHeight == 0))) {
1353 GetClientRect(object->win_handle, &Rect);
1355 if (pPresentationParameters->BackBufferWidth == 0) {
1356 pPresentationParameters->BackBufferWidth = Rect.right;
1357 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1359 if (pPresentationParameters->BackBufferHeight == 0) {
1360 pPresentationParameters->BackBufferHeight = Rect.bottom;
1361 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1363 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1364 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1365 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1369 /* Put the correct figures in the presentation parameters */
1370 TRACE("Copying across presentation parameters\n");
1371 object->presentParms = *pPresentationParameters;
1373 TRACE("calling rendertarget CB\n");
1374 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1376 object->presentParms.BackBufferWidth,
1377 object->presentParms.BackBufferHeight,
1378 object->presentParms.BackBufferFormat,
1379 object->presentParms.MultiSampleType,
1380 object->presentParms.MultiSampleQuality,
1381 TRUE /* Lockable */,
1382 &object->frontBuffer,
1383 NULL /* pShared (always null)*/);
1384 if (object->frontBuffer != NULL) {
1385 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1387 ERR("Failed to create the front buffer\n");
1392 * Create an opengl context for the display visual
1393 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1394 * use different properties after that point in time. FIXME: How to handle when requested format
1395 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1396 * it chooses is identical to the one already being used!
1397 **********************************/
1398 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1400 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1401 if(!object->context)
1402 return E_OUTOFMEMORY;
1403 object->num_contexts = 1;
1406 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1409 if (!object->context[0]) {
1410 ERR("Failed to create a new context\n");
1411 hr = WINED3DERR_NOTAVAILABLE;
1414 TRACE("Context created (HWND=%p, glContext=%p)\n",
1415 object->win_handle, object->context[0]->glCtx);
1418 /*********************
1419 * Windowed / Fullscreen
1420 *******************/
1423 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1424 * so we should really check to see if there is a fullscreen swapchain already
1425 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1426 **************************************/
1428 if (!pPresentationParameters->Windowed) {
1435 /* Get info on the current display setup */
1437 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1440 /* Change the display settings */
1441 memset(&devmode, 0, sizeof(devmode));
1442 devmode.dmSize = sizeof(devmode);
1443 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1444 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1445 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1446 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1447 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1449 /* For GetDisplayMode */
1450 This->ddraw_width = devmode.dmPelsWidth;
1451 This->ddraw_height = devmode.dmPelsHeight;
1452 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1454 IWineD3DDevice_SetFullscreen(iface, TRUE);
1456 /* And finally clip mouse to our screen */
1457 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1458 ClipCursor(&clip_rc);
1461 /*********************
1462 * Create the back, front and stencil buffers
1463 *******************/
1464 if(object->presentParms.BackBufferCount > 0) {
1467 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1468 if(!object->backBuffer) {
1469 ERR("Out of memory\n");
1474 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1475 TRACE("calling rendertarget CB\n");
1476 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1478 object->presentParms.BackBufferWidth,
1479 object->presentParms.BackBufferHeight,
1480 object->presentParms.BackBufferFormat,
1481 object->presentParms.MultiSampleType,
1482 object->presentParms.MultiSampleQuality,
1483 TRUE /* Lockable */,
1484 &object->backBuffer[i],
1485 NULL /* pShared (always null)*/);
1486 if(hr == WINED3D_OK && object->backBuffer[i]) {
1487 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1489 ERR("Cannot create new back buffer\n");
1493 glDrawBuffer(GL_BACK);
1494 checkGLcall("glDrawBuffer(GL_BACK)");
1498 object->backBuffer = NULL;
1500 /* Single buffering - draw to front buffer */
1502 glDrawBuffer(GL_FRONT);
1503 checkGLcall("glDrawBuffer(GL_FRONT)");
1507 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1508 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1509 TRACE("Creating depth stencil buffer\n");
1510 if (This->depthStencilBuffer == NULL ) {
1511 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1513 object->presentParms.BackBufferWidth,
1514 object->presentParms.BackBufferHeight,
1515 object->presentParms.AutoDepthStencilFormat,
1516 object->presentParms.MultiSampleType,
1517 object->presentParms.MultiSampleQuality,
1518 FALSE /* FIXME: Discard */,
1519 &This->depthStencilBuffer,
1520 NULL /* pShared (always null)*/ );
1521 if (This->depthStencilBuffer != NULL)
1522 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1525 /** TODO: A check on width, height and multisample types
1526 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1527 ****************************/
1528 object->wantsDepthStencilBuffer = TRUE;
1530 object->wantsDepthStencilBuffer = FALSE;
1533 TRACE("Created swapchain %p\n", object);
1534 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1538 if (object->backBuffer) {
1540 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1541 if(object->backBuffer[i]) {
1542 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1543 IUnknown_Release(bufferParent); /* once for the get parent */
1544 if (IUnknown_Release(bufferParent) > 0) {
1545 FIXME("(%p) Something's still holding the back buffer\n",This);
1549 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1550 object->backBuffer = NULL;
1552 if(object->context[0])
1553 DestroyContext(This, object->context[0]);
1554 if(object->frontBuffer) {
1555 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1556 IUnknown_Release(bufferParent); /* once for the get parent */
1557 if (IUnknown_Release(bufferParent) > 0) {
1558 FIXME("(%p) Something's still holding the front buffer\n",This);
1561 HeapFree(GetProcessHeap(), 0, object);
1565 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1566 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1568 TRACE("(%p)\n", This);
1570 return This->NumberOfSwapChains;
1573 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1575 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1577 if(iSwapChain < This->NumberOfSwapChains) {
1578 *pSwapChain = This->swapchains[iSwapChain];
1579 IWineD3DSwapChain_AddRef(*pSwapChain);
1580 TRACE("(%p) returning %p\n", This, *pSwapChain);
1583 TRACE("Swapchain out of range\n");
1585 return WINED3DERR_INVALIDCALL;
1590 * Vertex Declaration
1592 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1593 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1595 IWineD3DVertexDeclarationImpl *object = NULL;
1596 HRESULT hr = WINED3D_OK;
1598 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1599 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1601 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1603 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1608 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1610 unsigned int idx, idx2;
1611 unsigned int offset;
1612 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1613 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1614 BOOL has_blend_idx = has_blend &&
1615 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1616 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1617 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1618 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1619 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1620 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1621 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1623 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1624 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1626 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1627 WINED3DVERTEXELEMENT *elements = NULL;
1630 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1631 if (has_blend_idx) num_blends--;
1633 /* Compute declaration size */
1634 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1635 has_psize + has_diffuse + has_specular + num_textures + 1;
1637 /* convert the declaration */
1638 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1642 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1645 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1646 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1647 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1650 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1651 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1653 elements[idx].UsageIndex = 0;
1656 if (has_blend && (num_blends > 0)) {
1657 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1658 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1660 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1661 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1662 elements[idx].UsageIndex = 0;
1665 if (has_blend_idx) {
1666 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1667 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1668 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1669 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1670 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1672 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1673 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1674 elements[idx].UsageIndex = 0;
1678 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1679 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1680 elements[idx].UsageIndex = 0;
1684 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1685 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1686 elements[idx].UsageIndex = 0;
1690 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1691 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1692 elements[idx].UsageIndex = 0;
1696 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1697 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1698 elements[idx].UsageIndex = 1;
1701 for (idx2 = 0; idx2 < num_textures; idx2++) {
1702 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1703 switch (numcoords) {
1704 case WINED3DFVF_TEXTUREFORMAT1:
1705 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1707 case WINED3DFVF_TEXTUREFORMAT2:
1708 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1710 case WINED3DFVF_TEXTUREFORMAT3:
1711 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1713 case WINED3DFVF_TEXTUREFORMAT4:
1714 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1717 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1718 elements[idx].UsageIndex = idx2;
1722 /* Now compute offsets, and initialize the rest of the fields */
1723 for (idx = 0, offset = 0; idx < size-1; idx++) {
1724 elements[idx].Stream = 0;
1725 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1726 elements[idx].Offset = offset;
1727 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1730 *ppVertexElements = elements;
1734 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1735 WINED3DVERTEXELEMENT* elements = NULL;
1739 size = ConvertFvfToDeclaration(Fvf, &elements);
1740 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1742 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1743 HeapFree(GetProcessHeap(), 0, elements);
1744 if (hr != S_OK) return hr;
1749 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1750 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1752 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1753 HRESULT hr = WINED3D_OK;
1754 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1755 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1757 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1759 if (vertex_declaration) {
1760 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1763 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1765 if (WINED3D_OK != hr) {
1766 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1767 IWineD3DVertexShader_Release(*ppVertexShader);
1768 return WINED3DERR_INVALIDCALL;
1774 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1776 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1777 HRESULT hr = WINED3D_OK;
1779 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1780 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1781 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1782 if (WINED3D_OK == hr) {
1783 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1785 WARN("(%p) : Failed to create pixel shader\n", This);
1791 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1793 IWineD3DPaletteImpl *object;
1795 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1797 /* Create the new object */
1798 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1800 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1801 return E_OUTOFMEMORY;
1804 object->lpVtbl = &IWineD3DPalette_Vtbl;
1806 object->Flags = Flags;
1807 object->parent = Parent;
1808 object->wineD3DDevice = This;
1809 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1811 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1814 HeapFree( GetProcessHeap(), 0, object);
1815 return E_OUTOFMEMORY;
1818 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1820 IWineD3DPalette_Release((IWineD3DPalette *) object);
1824 *Palette = (IWineD3DPalette *) object;
1829 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1831 IWineD3DSwapChainImpl *swapchain;
1835 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1836 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1838 /* TODO: Test if OpenGL is compiled in and loaded */
1840 TRACE("(%p) : Creating stateblock\n", This);
1841 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1842 hr = IWineD3DDevice_CreateStateBlock(iface,
1844 (IWineD3DStateBlock **)&This->stateBlock,
1846 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1847 WARN("Failed to create stateblock\n");
1850 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1851 This->updateStateBlock = This->stateBlock;
1852 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1854 hr = allocate_shader_constants(This->updateStateBlock);
1855 if (WINED3D_OK != hr)
1858 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1859 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1860 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1862 /* Initialize the texture unit mapping to a 1:1 mapping */
1863 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1864 if (state < GL_LIMITS(fragment_samplers)) {
1865 This->texUnitMap[state] = state;
1866 This->rev_tex_unit_map[state] = state;
1868 This->texUnitMap[state] = -1;
1869 This->rev_tex_unit_map[state] = -1;
1873 /* Setup the implicit swapchain */
1874 TRACE("Creating implicit swapchain\n");
1875 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1876 if (FAILED(hr) || !swapchain) {
1877 WARN("Failed to create implicit swapchain\n");
1881 This->NumberOfSwapChains = 1;
1882 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1883 if(!This->swapchains) {
1884 ERR("Out of memory!\n");
1885 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1886 return E_OUTOFMEMORY;
1888 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1890 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1892 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1893 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1894 This->render_targets[0] = swapchain->backBuffer[0];
1895 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1898 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1899 This->render_targets[0] = swapchain->frontBuffer;
1900 This->lastActiveRenderTarget = swapchain->frontBuffer;
1902 IWineD3DSurface_AddRef(This->render_targets[0]);
1903 This->activeContext = swapchain->context[0];
1904 This->lastThread = GetCurrentThreadId();
1906 /* Depth Stencil support */
1907 This->stencilBufferTarget = This->depthStencilBuffer;
1908 if (NULL != This->stencilBufferTarget) {
1909 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1912 /* Set up some starting GL setup */
1915 /* Setup all the devices defaults */
1916 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1918 IWineD3DImpl_CheckGraphicsMemory();
1921 { /* Set a default viewport */
1925 vp.Width = pPresentationParameters->BackBufferWidth;
1926 vp.Height = pPresentationParameters->BackBufferHeight;
1929 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1932 /* Initialize the current view state */
1933 This->view_ident = 1;
1934 This->contexts[0]->last_was_rhw = 0;
1935 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1936 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1938 switch(wined3d_settings.offscreen_rendering_mode) {
1941 This->offscreenBuffer = GL_BACK;
1944 case ORM_BACKBUFFER:
1946 if(GL_LIMITS(aux_buffers) > 0) {
1947 TRACE("Using auxilliary buffer for offscreen rendering\n");
1948 This->offscreenBuffer = GL_AUX0;
1950 TRACE("Using back buffer for offscreen rendering\n");
1951 This->offscreenBuffer = GL_BACK;
1956 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1959 /* Clear the screen */
1960 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1961 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1964 This->d3d_initialized = TRUE;
1968 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1972 TRACE("(%p)\n", This);
1974 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1976 /* I don't think that the interface guarants that the device is destroyed from the same thread
1977 * it was created. Thus make sure a context is active for the glDelete* calls
1979 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1981 TRACE("Deleting high order patches\n");
1982 for(i = 0; i < PATCHMAP_SIZE; i++) {
1983 struct list *e1, *e2;
1984 struct WineD3DRectPatch *patch;
1985 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1986 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1987 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1991 /* Delete the pbuffer context if there is any */
1992 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1994 /* Delete the mouse cursor texture */
1995 if(This->cursorTexture) {
1997 glDeleteTextures(1, &This->cursorTexture);
1999 This->cursorTexture = 0;
2002 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2003 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2005 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2006 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2009 /* Release the update stateblock */
2010 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2011 if(This->updateStateBlock != This->stateBlock)
2012 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2014 This->updateStateBlock = NULL;
2016 { /* because were not doing proper internal refcounts releasing the primary state block
2017 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2018 to set this->stateBlock = NULL; first */
2019 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2020 This->stateBlock = NULL;
2022 /* Release the stateblock */
2023 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2024 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2028 /* Release the buffers (with sanity checks)*/
2029 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2030 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2031 if(This->depthStencilBuffer != This->stencilBufferTarget)
2032 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2034 This->stencilBufferTarget = NULL;
2036 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2037 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2038 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2040 TRACE("Setting rendertarget to NULL\n");
2041 This->render_targets[0] = NULL;
2043 if (This->depthStencilBuffer) {
2044 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2045 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2047 This->depthStencilBuffer = NULL;
2050 for(i=0; i < This->NumberOfSwapChains; i++) {
2051 TRACE("Releasing the implicit swapchain %d\n", i);
2052 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2053 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2057 HeapFree(GetProcessHeap(), 0, This->swapchains);
2058 This->swapchains = NULL;
2059 This->NumberOfSwapChains = 0;
2061 HeapFree(GetProcessHeap(), 0, This->render_targets);
2062 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2063 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2064 This->render_targets = NULL;
2065 This->fbo_color_attachments = NULL;
2066 This->draw_buffers = NULL;
2069 This->d3d_initialized = FALSE;
2073 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2074 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2075 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2077 /* Setup the window for fullscreen mode */
2078 if(fullscreen && !This->ddraw_fullscreen) {
2079 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2080 } else if(!fullscreen && This->ddraw_fullscreen) {
2081 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2084 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2085 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2086 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2089 This->ddraw_fullscreen = fullscreen;
2092 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2093 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2094 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2096 * There is no way to deactivate thread safety once it is enabled
2098 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2101 /*For now just store the flag(needed in case of ddraw) */
2102 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2107 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2111 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2114 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2116 /* Resize the screen even without a window:
2117 * The app could have unset it with SetCooperativeLevel, but not called
2118 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2119 * but we don't have any hwnd
2122 memset(&devmode, 0, sizeof(devmode));
2123 devmode.dmSize = sizeof(devmode);
2124 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2125 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2126 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2127 devmode.dmPelsWidth = pMode->Width;
2128 devmode.dmPelsHeight = pMode->Height;
2130 devmode.dmDisplayFrequency = pMode->RefreshRate;
2131 if (pMode->RefreshRate != 0) {
2132 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2135 /* Only change the mode if necessary */
2136 if( (This->ddraw_width == pMode->Width) &&
2137 (This->ddraw_height == pMode->Height) &&
2138 (This->ddraw_format == pMode->Format) &&
2139 (pMode->RefreshRate == 0) ) {
2143 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2144 if (ret != DISP_CHANGE_SUCCESSFUL) {
2145 if(devmode.dmDisplayFrequency != 0) {
2146 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2147 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2148 devmode.dmDisplayFrequency = 0;
2149 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2151 if(ret != DISP_CHANGE_SUCCESSFUL) {
2152 return WINED3DERR_NOTAVAILABLE;
2156 /* Store the new values */
2157 This->ddraw_width = pMode->Width;
2158 This->ddraw_height = pMode->Height;
2159 This->ddraw_format = pMode->Format;
2161 /* Only do this with a window of course */
2162 if(This->ddraw_window)
2163 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2165 /* And finally clip mouse to our screen */
2166 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2167 ClipCursor(&clip_rc);
2172 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2174 *ppD3D= This->wineD3D;
2175 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2176 IWineD3D_AddRef(*ppD3D);
2180 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2181 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2182 * into the video ram as possible and seeing how many fit
2183 * you can also get the correct initial value from nvidia and ATI's driver via X
2184 * texture memory is video memory + AGP memory
2185 *******************/
2186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2187 static BOOL showfixmes = TRUE;
2189 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2190 (wined3d_settings.emulated_textureram/(1024*1024)),
2191 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2194 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2195 (wined3d_settings.emulated_textureram/(1024*1024)),
2196 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2197 /* return simulated texture memory left */
2198 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2206 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2209 /* Update the current state block */
2210 This->updateStateBlock->changed.fvf = TRUE;
2212 if(This->updateStateBlock->fvf == fvf) {
2213 TRACE("Application is setting the old fvf over, nothing to do\n");
2217 This->updateStateBlock->fvf = fvf;
2218 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2224 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2226 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2227 *pfvf = This->stateBlock->fvf;
2232 * Get / Set Stream Source
2234 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2236 IWineD3DVertexBuffer *oldSrc;
2238 if (StreamNumber >= MAX_STREAMS) {
2239 WARN("Stream out of range %d\n", StreamNumber);
2240 return WINED3DERR_INVALIDCALL;
2243 oldSrc = This->stateBlock->streamSource[StreamNumber];
2244 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2246 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2248 if(oldSrc == pStreamData &&
2249 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2250 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2251 TRACE("Application is setting the old values over, nothing to do\n");
2255 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2257 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2258 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2261 /* Handle recording of state blocks */
2262 if (This->isRecordingState) {
2263 TRACE("Recording... not performing anything\n");
2264 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2265 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2269 /* Need to do a getParent and pass the reffs up */
2270 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2271 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2272 so for now, just count internally */
2273 if (pStreamData != NULL) {
2274 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2275 InterlockedIncrement(&vbImpl->bindCount);
2276 IWineD3DVertexBuffer_AddRef(pStreamData);
2278 if (oldSrc != NULL) {
2279 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2280 IWineD3DVertexBuffer_Release(oldSrc);
2283 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2288 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2291 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2292 This->stateBlock->streamSource[StreamNumber],
2293 This->stateBlock->streamOffset[StreamNumber],
2294 This->stateBlock->streamStride[StreamNumber]);
2296 if (StreamNumber >= MAX_STREAMS) {
2297 WARN("Stream out of range %d\n", StreamNumber);
2298 return WINED3DERR_INVALIDCALL;
2300 *pStream = This->stateBlock->streamSource[StreamNumber];
2301 *pStride = This->stateBlock->streamStride[StreamNumber];
2303 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2306 if (*pStream != NULL) {
2307 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2312 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2314 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2315 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2317 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2318 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2320 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2321 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2323 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2324 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2325 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2331 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2334 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2335 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2337 TRACE("(%p) : returning %d\n", This, *Divider);
2343 * Get / Set & Multiply Transform
2345 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2348 /* Most of this routine, comments included copied from ddraw tree initially: */
2349 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2351 /* Handle recording of state blocks */
2352 if (This->isRecordingState) {
2353 TRACE("Recording... not performing anything\n");
2354 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2355 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2360 * If the new matrix is the same as the current one,
2361 * we cut off any further processing. this seems to be a reasonable
2362 * optimization because as was noticed, some apps (warcraft3 for example)
2363 * tend towards setting the same matrix repeatedly for some reason.
2365 * From here on we assume that the new matrix is different, wherever it matters.
2367 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2368 TRACE("The app is setting the same matrix over again\n");
2371 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2375 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2376 where ViewMat = Camera space, WorldMat = world space.
2378 In OpenGL, camera and world space is combined into GL_MODELVIEW
2379 matrix. The Projection matrix stay projection matrix.
2382 /* Capture the times we can just ignore the change for now */
2383 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2384 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2385 /* Handled by the state manager */
2388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2392 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2394 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2395 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2399 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2400 WINED3DMATRIX *mat = NULL;
2403 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2404 * below means it will be recorded in a state block change, but it
2405 * works regardless where it is recorded.
2406 * If this is found to be wrong, change to StateBlock.
2408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2409 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2411 if (State < HIGHEST_TRANSFORMSTATE)
2413 mat = &This->updateStateBlock->transforms[State];
2415 FIXME("Unhandled transform state!!\n");
2418 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2420 /* Apply change via set transform - will reapply to eg. lights this way */
2421 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2427 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2428 you can reference any indexes you want as long as that number max are enabled at any
2429 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2430 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2431 but when recording, just build a chain pretty much of commands to be replayed. */
2433 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2435 PLIGHTINFOEL *object = NULL;
2436 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2440 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2442 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2446 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2447 return WINED3DERR_INVALIDCALL;
2450 switch(pLight->Type) {
2451 case WINED3DLIGHT_POINT:
2452 case WINED3DLIGHT_SPOT:
2453 case WINED3DLIGHT_PARALLELPOINT:
2454 case WINED3DLIGHT_GLSPOT:
2455 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2458 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2459 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2460 return WINED3DERR_INVALIDCALL;
2464 case WINED3DLIGHT_DIRECTIONAL:
2465 /* Ignores attenuation */
2469 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2470 return WINED3DERR_INVALIDCALL;
2473 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2474 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2475 if(object->OriginalIndex == Index) break;
2480 TRACE("Adding new light\n");
2481 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2483 ERR("Out of memory error when allocating a light\n");
2484 return E_OUTOFMEMORY;
2486 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2487 object->glIndex = -1;
2488 object->OriginalIndex = Index;
2489 object->changed = TRUE;
2492 /* Initialize the object */
2493 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,
2494 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2495 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2496 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2497 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2498 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2499 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2501 /* Save away the information */
2502 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2504 switch (pLight->Type) {
2505 case WINED3DLIGHT_POINT:
2507 object->lightPosn[0] = pLight->Position.x;
2508 object->lightPosn[1] = pLight->Position.y;
2509 object->lightPosn[2] = pLight->Position.z;
2510 object->lightPosn[3] = 1.0f;
2511 object->cutoff = 180.0f;
2515 case WINED3DLIGHT_DIRECTIONAL:
2517 object->lightPosn[0] = -pLight->Direction.x;
2518 object->lightPosn[1] = -pLight->Direction.y;
2519 object->lightPosn[2] = -pLight->Direction.z;
2520 object->lightPosn[3] = 0.0;
2521 object->exponent = 0.0f;
2522 object->cutoff = 180.0f;
2525 case WINED3DLIGHT_SPOT:
2527 object->lightPosn[0] = pLight->Position.x;
2528 object->lightPosn[1] = pLight->Position.y;
2529 object->lightPosn[2] = pLight->Position.z;
2530 object->lightPosn[3] = 1.0;
2533 object->lightDirn[0] = pLight->Direction.x;
2534 object->lightDirn[1] = pLight->Direction.y;
2535 object->lightDirn[2] = pLight->Direction.z;
2536 object->lightDirn[3] = 1.0;
2539 * opengl-ish and d3d-ish spot lights use too different models for the
2540 * light "intensity" as a function of the angle towards the main light direction,
2541 * so we only can approximate very roughly.
2542 * however spot lights are rather rarely used in games (if ever used at all).
2543 * furthermore if still used, probably nobody pays attention to such details.
2545 if (pLight->Falloff == 0) {
2548 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2550 if (rho < 0.0001) rho = 0.0001f;
2551 object->exponent = -0.3/log(cos(rho/2));
2552 if (object->exponent > 128.0) {
2553 object->exponent = 128.0;
2555 object->cutoff = pLight->Phi*90/M_PI;
2561 FIXME("Unrecognized light type %d\n", pLight->Type);
2564 /* Update the live definitions if the light is currently assigned a glIndex */
2565 if (object->glIndex != -1 && !This->isRecordingState) {
2566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2571 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2572 PLIGHTINFOEL *lightInfo = NULL;
2573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2574 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2576 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2578 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2579 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2580 if(lightInfo->OriginalIndex == Index) break;
2584 if (lightInfo == NULL) {
2585 TRACE("Light information requested but light not defined\n");
2586 return WINED3DERR_INVALIDCALL;
2589 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2594 * Get / Set Light Enable
2595 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2597 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2598 PLIGHTINFOEL *lightInfo = NULL;
2599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2600 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2602 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2604 /* Tests show true = 128...not clear why */
2605 Enable = Enable? 128: 0;
2607 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2608 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2609 if(lightInfo->OriginalIndex == Index) break;
2612 TRACE("Found light: %p\n", lightInfo);
2614 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2615 if (lightInfo == NULL) {
2617 TRACE("Light enabled requested but light not defined, so defining one!\n");
2618 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2620 /* Search for it again! Should be fairly quick as near head of list */
2621 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2622 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2623 if(lightInfo->OriginalIndex == Index) break;
2626 if (lightInfo == NULL) {
2627 FIXME("Adding default lights has failed dismally\n");
2628 return WINED3DERR_INVALIDCALL;
2632 lightInfo->enabledChanged = TRUE;
2634 if(lightInfo->glIndex != -1) {
2635 if(!This->isRecordingState) {
2636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2639 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2640 lightInfo->glIndex = -1;
2642 TRACE("Light already disabled, nothing to do\n");
2645 if (lightInfo->glIndex != -1) {
2647 TRACE("Nothing to do as light was enabled\n");
2650 /* Find a free gl light */
2651 for(i = 0; i < This->maxConcurrentLights; i++) {
2652 if(This->stateBlock->activeLights[i] == NULL) {
2653 This->stateBlock->activeLights[i] = lightInfo;
2654 lightInfo->glIndex = i;
2658 if(lightInfo->glIndex == -1) {
2659 ERR("Too many concurrently active lights\n");
2660 return WINED3DERR_INVALIDCALL;
2663 /* i == lightInfo->glIndex */
2664 if(!This->isRecordingState) {
2665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2673 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2675 PLIGHTINFOEL *lightInfo = NULL;
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2678 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2679 TRACE("(%p) : for idx(%d)\n", This, Index);
2681 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2682 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2683 if(lightInfo->OriginalIndex == Index) break;
2687 if (lightInfo == NULL) {
2688 TRACE("Light enabled state requested but light not defined\n");
2689 return WINED3DERR_INVALIDCALL;
2691 /* true is 128 according to SetLightEnable */
2692 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2697 * Get / Set Clip Planes
2699 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2701 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2703 /* Validate Index */
2704 if (Index >= GL_LIMITS(clipplanes)) {
2705 TRACE("Application has requested clipplane this device doesn't support\n");
2706 return WINED3DERR_INVALIDCALL;
2709 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2711 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2712 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2713 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2714 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2715 TRACE("Application is setting old values over, nothing to do\n");
2719 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2720 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2721 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2722 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2724 /* Handle recording of state blocks */
2725 if (This->isRecordingState) {
2726 TRACE("Recording... not performing anything\n");
2730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2735 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 TRACE("(%p) : for idx %d\n", This, Index);
2739 /* Validate Index */
2740 if (Index >= GL_LIMITS(clipplanes)) {
2741 TRACE("Application has requested clipplane this device doesn't support\n");
2742 return WINED3DERR_INVALIDCALL;
2745 pPlane[0] = This->stateBlock->clipplane[Index][0];
2746 pPlane[1] = This->stateBlock->clipplane[Index][1];
2747 pPlane[2] = This->stateBlock->clipplane[Index][2];
2748 pPlane[3] = This->stateBlock->clipplane[Index][3];
2753 * Get / Set Clip Plane Status
2754 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2756 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 FIXME("(%p) : stub\n", This);
2759 if (NULL == pClipStatus) {
2760 return WINED3DERR_INVALIDCALL;
2762 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2763 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2767 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2769 FIXME("(%p) : stub\n", This);
2770 if (NULL == pClipStatus) {
2771 return WINED3DERR_INVALIDCALL;
2773 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2774 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2779 * Get / Set Material
2781 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 This->updateStateBlock->changed.material = TRUE;
2785 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2787 /* Handle recording of state blocks */
2788 if (This->isRecordingState) {
2789 TRACE("Recording... not performing anything\n");
2793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2797 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2800 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2801 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2802 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2803 pMaterial->Ambient.b, pMaterial->Ambient.a);
2804 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2805 pMaterial->Specular.b, pMaterial->Specular.a);
2806 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2807 pMaterial->Emissive.b, pMaterial->Emissive.a);
2808 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2816 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2818 IWineD3DIndexBuffer *oldIdxs;
2820 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2821 oldIdxs = This->updateStateBlock->pIndexData;
2823 This->updateStateBlock->changed.indices = TRUE;
2824 This->updateStateBlock->pIndexData = pIndexData;
2826 /* Handle recording of state blocks */
2827 if (This->isRecordingState) {
2828 TRACE("Recording... not performing anything\n");
2829 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2830 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2834 if(oldIdxs != pIndexData) {
2835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2836 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2837 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2842 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2845 *ppIndexData = This->stateBlock->pIndexData;
2847 /* up ref count on ppindexdata */
2849 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2850 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2852 TRACE("(%p) No index data set\n", This);
2854 TRACE("Returning %p\n", *ppIndexData);
2859 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2860 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2862 TRACE("(%p)->(%d)\n", This, BaseIndex);
2864 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2865 TRACE("Application is setting the old value over, nothing to do\n");
2869 This->updateStateBlock->baseVertexIndex = BaseIndex;
2871 if (This->isRecordingState) {
2872 TRACE("Recording... not performing anything\n");
2875 /* The base vertex index affects the stream sources */
2876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2880 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2882 TRACE("(%p) : base_index %p\n", This, base_index);
2884 *base_index = This->stateBlock->baseVertexIndex;
2886 TRACE("Returning %u\n", *base_index);
2892 * Get / Set Viewports
2894 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 TRACE("(%p)\n", This);
2898 This->updateStateBlock->changed.viewport = TRUE;
2899 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2901 /* Handle recording of state blocks */
2902 if (This->isRecordingState) {
2903 TRACE("Recording... not performing anything\n");
2907 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2908 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2915 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2917 TRACE("(%p)\n", This);
2918 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2923 * Get / Set Render States
2924 * TODO: Verify against dx9 definitions
2926 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2929 DWORD oldValue = This->stateBlock->renderState[State];
2931 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2933 This->updateStateBlock->changed.renderState[State] = TRUE;
2934 This->updateStateBlock->renderState[State] = Value;
2936 /* Handle recording of state blocks */
2937 if (This->isRecordingState) {
2938 TRACE("Recording... not performing anything\n");
2942 /* Compared here and not before the assignment to allow proper stateblock recording */
2943 if(Value == oldValue) {
2944 TRACE("Application is setting the old value over, nothing to do\n");
2946 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2952 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2954 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2955 *pValue = This->stateBlock->renderState[State];
2960 * Get / Set Sampler States
2961 * TODO: Verify against dx9 definitions
2964 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2968 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2969 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2971 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2972 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2976 * SetSampler is designed to allow for more than the standard up to 8 textures
2977 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2978 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2980 * http://developer.nvidia.com/object/General_FAQ.html#t6
2982 * There are two new settings for GForce
2984 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2985 * and the texture one:
2986 * GL_MAX_TEXTURE_COORDS_ARB.
2987 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2990 oldValue = This->stateBlock->samplerState[Sampler][Type];
2991 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2992 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2994 /* Handle recording of state blocks */
2995 if (This->isRecordingState) {
2996 TRACE("Recording... not performing anything\n");
3000 if(oldValue == Value) {
3001 TRACE("Application is setting the old value over, nothing to do\n");
3005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3010 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3013 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3014 This, Sampler, debug_d3dsamplerstate(Type), Type);
3016 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3017 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3020 *Value = This->stateBlock->samplerState[Sampler][Type];
3021 TRACE("(%p) : Returning %#x\n", This, *Value);
3026 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 This->updateStateBlock->changed.scissorRect = TRUE;
3030 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3031 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3034 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3036 if(This->isRecordingState) {
3037 TRACE("Recording... not performing anything\n");
3041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3050 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3054 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3056 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3058 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3060 This->updateStateBlock->vertexDecl = pDecl;
3061 This->updateStateBlock->changed.vertexDecl = TRUE;
3063 if (This->isRecordingState) {
3064 TRACE("Recording... not performing anything\n");
3066 } else if(pDecl == oldDecl) {
3067 /* Checked after the assignment to allow proper stateblock recording */
3068 TRACE("Application is setting the old declaration over, nothing to do\n");
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3081 *ppDecl = This->stateBlock->vertexDecl;
3082 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3086 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3090 This->updateStateBlock->vertexShader = pShader;
3091 This->updateStateBlock->changed.vertexShader = TRUE;
3093 if (This->isRecordingState) {
3094 TRACE("Recording... not performing anything\n");
3096 } else if(oldShader == pShader) {
3097 /* Checked here to allow proper stateblock recording */
3098 TRACE("App is setting the old shader over, nothing to do\n");
3102 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3109 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 if (NULL == ppShader) {
3113 return WINED3DERR_INVALIDCALL;
3115 *ppShader = This->stateBlock->vertexShader;
3116 if( NULL != *ppShader)
3117 IWineD3DVertexShader_AddRef(*ppShader);
3119 TRACE("(%p) : returning %p\n", This, *ppShader);
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3124 IWineD3DDevice *iface,
3126 CONST BOOL *srcData,
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 int i, cnt = min(count, MAX_CONST_B - start);
3132 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3133 iface, srcData, start, count);
3135 if (srcData == NULL || cnt < 0)
3136 return WINED3DERR_INVALIDCALL;
3138 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3139 for (i = 0; i < cnt; i++)
3140 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3142 for (i = start; i < cnt + start; ++i) {
3143 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3151 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3152 IWineD3DDevice *iface,
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 int cnt = min(count, MAX_CONST_B - start);
3160 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3161 iface, dstData, start, count);
3163 if (dstData == NULL || cnt < 0)
3164 return WINED3DERR_INVALIDCALL;
3166 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3170 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3171 IWineD3DDevice *iface,
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 int i, cnt = min(count, MAX_CONST_I - start);
3179 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3180 iface, srcData, start, count);
3182 if (srcData == NULL || cnt < 0)
3183 return WINED3DERR_INVALIDCALL;
3185 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3186 for (i = 0; i < cnt; i++)
3187 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3188 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3190 for (i = start; i < cnt + start; ++i) {
3191 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3199 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3200 IWineD3DDevice *iface,
3205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3206 int cnt = min(count, MAX_CONST_I - start);
3208 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3209 iface, dstData, start, count);
3211 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3212 return WINED3DERR_INVALIDCALL;
3214 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3218 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3219 IWineD3DDevice *iface,
3221 CONST float *srcData,
3224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3227 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3228 iface, srcData, start, count);
3230 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3231 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3232 return WINED3DERR_INVALIDCALL;
3234 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3236 for (i = 0; i < count; i++)
3237 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3238 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3241 for (i = start; i < count + start; ++i) {
3242 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3243 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3244 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3245 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3246 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3248 ptr->idx[ptr->count++] = i;
3249 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3253 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3258 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3259 IWineD3DDevice *iface,
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3267 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3268 iface, dstData, start, count);
3270 if (dstData == NULL || cnt < 0)
3271 return WINED3DERR_INVALIDCALL;
3273 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3277 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3279 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3284 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3285 int i = This->rev_tex_unit_map[unit];
3286 int j = This->texUnitMap[stage];
3288 This->texUnitMap[stage] = unit;
3289 if (i != -1 && i != stage) {
3290 This->texUnitMap[i] = -1;
3293 This->rev_tex_unit_map[unit] = stage;
3294 if (j != -1 && j != unit) {
3295 This->rev_tex_unit_map[j] = -1;
3299 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3302 for (i = 0; i < MAX_TEXTURES; ++i) {
3303 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3304 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3305 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3306 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3307 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3308 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3309 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3310 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3312 if (color_op == WINED3DTOP_DISABLE) {
3313 /* Not used, and disable higher stages */
3314 while (i < MAX_TEXTURES) {
3315 This->fixed_function_usage_map[i] = FALSE;
3321 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3322 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3323 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3324 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3325 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3326 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3327 This->fixed_function_usage_map[i] = TRUE;
3329 This->fixed_function_usage_map[i] = FALSE;
3332 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3333 This->fixed_function_usage_map[i+1] = TRUE;
3338 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3341 device_update_fixed_function_usage_map(This);
3343 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3344 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3345 if (!This->fixed_function_usage_map[i]) continue;
3347 if (This->texUnitMap[i] != i) {
3348 device_map_stage(This, i, i);
3349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3350 markTextureStagesDirty(This, i);
3356 /* Now work out the mapping */
3358 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3359 if (!This->fixed_function_usage_map[i]) continue;
3361 if (This->texUnitMap[i] != tex) {
3362 device_map_stage(This, i, tex);
3363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3364 markTextureStagesDirty(This, i);
3371 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3372 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3375 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3376 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3377 device_map_stage(This, i, i);
3378 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3379 if (i < MAX_TEXTURES) {
3380 markTextureStagesDirty(This, i);
3386 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3387 int current_mapping = This->rev_tex_unit_map[unit];
3389 if (current_mapping == -1) {
3390 /* Not currently used */
3394 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3395 /* Used by a fragment sampler */
3397 if (!pshader_sampler_tokens) {
3398 /* No pixel shader, check fixed function */
3399 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3402 /* Pixel shader, check the shader's sampler map */
3403 return !pshader_sampler_tokens[current_mapping];
3406 /* Used by a vertex sampler */
3407 return !vshader_sampler_tokens[current_mapping];
3410 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3411 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3412 DWORD *pshader_sampler_tokens = NULL;
3413 int start = GL_LIMITS(combined_samplers) - 1;
3417 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3419 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3420 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3421 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3424 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3425 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3426 if (vshader_sampler_tokens[i]) {
3427 if (This->texUnitMap[vsampler_idx] != -1) {
3428 /* Already mapped somewhere */
3432 while (start >= 0) {
3433 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3434 device_map_stage(This, vsampler_idx, start);
3435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3447 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3448 BOOL vs = use_vs(This);
3449 BOOL ps = use_ps(This);
3452 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3453 * that would be really messy and require shader recompilation
3454 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3455 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3458 device_map_psamplers(This);
3460 device_map_fixed_function_samplers(This);
3464 device_map_vsamplers(This, ps);
3468 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3470 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3471 This->updateStateBlock->pixelShader = pShader;
3472 This->updateStateBlock->changed.pixelShader = TRUE;
3474 /* Handle recording of state blocks */
3475 if (This->isRecordingState) {
3476 TRACE("Recording... not performing anything\n");
3479 if (This->isRecordingState) {
3480 TRACE("Recording... not performing anything\n");
3484 if(pShader == oldShader) {
3485 TRACE("App is setting the old pixel shader over, nothing to do\n");
3489 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3495 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3498 if (NULL == ppShader) {
3499 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3500 return WINED3DERR_INVALIDCALL;
3503 *ppShader = This->stateBlock->pixelShader;
3504 if (NULL != *ppShader) {
3505 IWineD3DPixelShader_AddRef(*ppShader);
3507 TRACE("(%p) : returning %p\n", This, *ppShader);
3511 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3512 IWineD3DDevice *iface,
3514 CONST BOOL *srcData,
3517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3518 int i, cnt = min(count, MAX_CONST_B - start);
3520 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3521 iface, srcData, start, count);
3523 if (srcData == NULL || cnt < 0)
3524 return WINED3DERR_INVALIDCALL;
3526 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3527 for (i = 0; i < cnt; i++)
3528 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3530 for (i = start; i < cnt + start; ++i) {
3531 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3539 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3540 IWineD3DDevice *iface,
3545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 int cnt = min(count, MAX_CONST_B - start);
3548 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3549 iface, dstData, start, count);
3551 if (dstData == NULL || cnt < 0)
3552 return WINED3DERR_INVALIDCALL;
3554 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3558 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3559 IWineD3DDevice *iface,
3564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3565 int i, cnt = min(count, MAX_CONST_I - start);
3567 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3568 iface, srcData, start, count);
3570 if (srcData == NULL || cnt < 0)
3571 return WINED3DERR_INVALIDCALL;
3573 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3574 for (i = 0; i < cnt; i++)
3575 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3576 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3578 for (i = start; i < cnt + start; ++i) {
3579 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3582 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3587 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3588 IWineD3DDevice *iface,
3593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3594 int cnt = min(count, MAX_CONST_I - start);
3596 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3597 iface, dstData, start, count);
3599 if (dstData == NULL || cnt < 0)
3600 return WINED3DERR_INVALIDCALL;
3602 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3606 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3607 IWineD3DDevice *iface,
3609 CONST float *srcData,
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3615 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3616 iface, srcData, start, count);
3618 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3619 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3620 return WINED3DERR_INVALIDCALL;
3622 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3624 for (i = 0; i < count; i++)
3625 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3626 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3629 for (i = start; i < count + start; ++i) {
3630 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3631 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3632 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3633 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3634 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3636 ptr->idx[ptr->count++] = i;
3637 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3646 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3647 IWineD3DDevice *iface,
3652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3653 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3655 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3656 iface, dstData, start, count);
3658 if (dstData == NULL || cnt < 0)
3659 return WINED3DERR_INVALIDCALL;
3661 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3665 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3667 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3668 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3670 DWORD DestFVF = dest->fvf;
3672 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3676 if (lpStrideData->u.s.normal.lpData) {
3677 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3680 if (lpStrideData->u.s.position.lpData == NULL) {
3681 ERR("Source has no position mask\n");
3682 return WINED3DERR_INVALIDCALL;
3685 /* We might access VBOs from this code, so hold the lock */
3688 if (dest->resource.allocatedMemory == NULL) {
3689 /* This may happen if we do direct locking into a vbo. Unlikely,
3690 * but theoretically possible(ddraw processvertices test)
3692 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3693 if(!dest->resource.allocatedMemory) {
3695 ERR("Out of memory\n");
3696 return E_OUTOFMEMORY;
3700 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3701 checkGLcall("glBindBufferARB");
3702 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3704 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3706 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3707 checkGLcall("glUnmapBufferARB");
3711 /* Get a pointer into the destination vbo(create one if none exists) and
3712 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3714 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3719 unsigned char extrabytes = 0;
3720 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3721 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3722 * this may write 4 extra bytes beyond the area that should be written
3724 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3725 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3726 if(!dest_conv_addr) {
3727 ERR("Out of memory\n");
3728 /* Continue without storing converted vertices */
3730 dest_conv = dest_conv_addr;
3734 * a) WINED3DRS_CLIPPING is enabled
3735 * b) WINED3DVOP_CLIP is passed
3737 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3738 static BOOL warned = FALSE;
3740 * The clipping code is not quite correct. Some things need
3741 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3742 * so disable clipping for now.
3743 * (The graphics in Half-Life are broken, and my processvertices
3744 * test crashes with IDirect3DDevice3)
3750 FIXME("Clipping is broken and disabled for now\n");
3752 } else doClip = FALSE;
3753 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3755 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3758 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3759 WINED3DTS_PROJECTION,
3761 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3762 WINED3DTS_WORLDMATRIX(0),
3765 TRACE("View mat:\n");
3766 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);
3767 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);
3768 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);
3769 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);
3771 TRACE("Proj mat:\n");
3772 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);
3773 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);
3774 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);
3775 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);
3777 TRACE("World mat:\n");
3778 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);
3779 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);
3780 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);
3781 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);
3783 /* Get the viewport */
3784 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3785 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3786 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3788 multiply_matrix(&mat,&view_mat,&world_mat);
3789 multiply_matrix(&mat,&proj_mat,&mat);
3791 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3793 for (i = 0; i < dwCount; i+= 1) {
3794 unsigned int tex_index;
3796 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3797 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3798 /* The position first */
3800 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3802 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3804 /* Multiplication with world, view and projection matrix */
3805 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);
3806 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);
3807 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);
3808 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);
3810 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3812 /* WARNING: The following things are taken from d3d7 and were not yet checked
3813 * against d3d8 or d3d9!
3816 /* Clipping conditions: From
3817 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3819 * A vertex is clipped if it does not match the following requirements
3823 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3825 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3826 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3831 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3832 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3835 /* "Normal" viewport transformation (not clipped)
3836 * 1) The values are divided by rhw
3837 * 2) The y axis is negative, so multiply it with -1
3838 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3839 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3840 * 4) Multiply x with Width/2 and add Width/2
3841 * 5) The same for the height
3842 * 6) Add the viewpoint X and Y to the 2D coordinates and
3843 * The minimum Z value to z
3844 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3846 * Well, basically it's simply a linear transformation into viewport
3858 z *= vp.MaxZ - vp.MinZ;
3860 x += vp.Width / 2 + vp.X;
3861 y += vp.Height / 2 + vp.Y;
3866 /* That vertex got clipped
3867 * Contrary to OpenGL it is not dropped completely, it just
3868 * undergoes a different calculation.
3870 TRACE("Vertex got clipped\n");
3877 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3878 * outside of the main vertex buffer memory. That needs some more
3883 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3886 ( (float *) dest_ptr)[0] = x;
3887 ( (float *) dest_ptr)[1] = y;
3888 ( (float *) dest_ptr)[2] = z;
3889 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3891 dest_ptr += 3 * sizeof(float);
3893 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3894 dest_ptr += sizeof(float);
3899 ( (float *) dest_conv)[0] = x * w;
3900 ( (float *) dest_conv)[1] = y * w;
3901 ( (float *) dest_conv)[2] = z * w;
3902 ( (float *) dest_conv)[3] = w;
3904 dest_conv += 3 * sizeof(float);
3906 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3907 dest_conv += sizeof(float);
3911 if (DestFVF & WINED3DFVF_PSIZE) {
3912 dest_ptr += sizeof(DWORD);
3913 if(dest_conv) dest_conv += sizeof(DWORD);
3915 if (DestFVF & WINED3DFVF_NORMAL) {
3917 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3918 /* AFAIK this should go into the lighting information */
3919 FIXME("Didn't expect the destination to have a normal\n");
3920 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3922 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3926 if (DestFVF & WINED3DFVF_DIFFUSE) {
3928 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3930 static BOOL warned = FALSE;
3933 ERR("No diffuse color in source, but destination has one\n");
3937 *( (DWORD *) dest_ptr) = 0xffffffff;
3938 dest_ptr += sizeof(DWORD);
3941 *( (DWORD *) dest_conv) = 0xffffffff;
3942 dest_conv += sizeof(DWORD);
3946 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3948 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3949 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3950 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3951 dest_conv += sizeof(DWORD);
3956 if (DestFVF & WINED3DFVF_SPECULAR) {
3957 /* What's the color value in the feedback buffer? */
3959 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3961 static BOOL warned = FALSE;
3964 ERR("No specular color in source, but destination has one\n");
3968 *( (DWORD *) dest_ptr) = 0xFF000000;
3969 dest_ptr += sizeof(DWORD);
3972 *( (DWORD *) dest_conv) = 0xFF000000;
3973 dest_conv += sizeof(DWORD);
3977 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3979 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3980 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3981 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3982 dest_conv += sizeof(DWORD);
3987 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3989 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3990 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3992 ERR("No source texture, but destination requests one\n");
3993 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3994 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3997 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3999 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4006 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4007 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4008 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4009 dwCount * get_flexible_vertex_size(DestFVF),
4011 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4012 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4019 #undef copy_and_next
4021 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4023 WineDirect3DVertexStridedData strided;
4024 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4025 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4028 ERR("Output vertex declaration not implemented yet\n");
4031 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4032 * and this call is quite performance critical, so don't call needlessly
4034 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4035 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4038 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4039 * control the streamIsUP flag, thus restore it afterwards.
4041 This->stateBlock->streamIsUP = FALSE;
4042 memset(&strided, 0, sizeof(strided));
4043 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4044 This->stateBlock->streamIsUP = streamWasUP;
4046 if(vbo || SrcStartIndex) {
4048 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4049 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4051 * Also get the start index in, but only loop over all elements if there's something to add at all.
4053 #define FIXSRC(type) \
4054 if(strided.u.s.type.VBO) { \
4055 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4056 strided.u.s.type.VBO = 0; \
4057 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4059 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4063 if(strided.u.s.type.lpData) { \
4064 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4067 FIXSRC(blendWeights);
4068 FIXSRC(blendMatrixIndices);
4073 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4074 FIXSRC(texCoords[i]);
4087 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4091 * Get / Set Texture Stage States
4092 * TODO: Verify against dx9 definitions
4094 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4096 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4098 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4100 if (Stage >= MAX_TEXTURES) {
4101 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4105 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4106 This->updateStateBlock->textureState[Stage][Type] = Value;
4108 if (This->isRecordingState) {
4109 TRACE("Recording... not performing anything\n");
4113 /* Checked after the assignments to allow proper stateblock recording */
4114 if(oldValue == Value) {
4115 TRACE("App is setting the old value over, nothing to do\n");
4119 if(Stage > This->stateBlock->lowest_disabled_stage &&
4120 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4121 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4122 * Changes in other states are important on disabled stages too
4127 if(Type == WINED3DTSS_COLOROP) {
4130 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4131 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4132 * they have to be disabled
4134 * The current stage is dirtified below.
4136 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4137 TRACE("Additionally dirtifying stage %d\n", i);
4138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4140 This->stateBlock->lowest_disabled_stage = Stage;
4141 TRACE("New lowest disabled: %d\n", Stage);
4142 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4143 /* Previously disabled stage enabled. Stages above it may need enabling
4144 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4145 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4147 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4150 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4151 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4154 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4157 This->stateBlock->lowest_disabled_stage = i;
4158 TRACE("New lowest disabled: %d\n", i);
4160 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4161 /* TODO: Built a stage -> texture unit mapping for register combiners */
4165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4170 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4172 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4173 *pValue = This->updateStateBlock->textureState[Stage][Type];
4180 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4182 IWineD3DBaseTexture *oldTexture;
4184 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4186 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4187 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4190 oldTexture = This->updateStateBlock->textures[Stage];
4192 if(pTexture != NULL) {
4193 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4195 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4196 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4197 return WINED3DERR_INVALIDCALL;
4199 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4202 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4203 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4205 This->updateStateBlock->changed.textures[Stage] = TRUE;
4206 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4207 This->updateStateBlock->textures[Stage] = pTexture;
4209 /* Handle recording of state blocks */
4210 if (This->isRecordingState) {
4211 TRACE("Recording... not performing anything\n");
4215 if(oldTexture == pTexture) {
4216 TRACE("App is setting the same texture again, nothing to do\n");
4220 /** NOTE: MSDN says that setTexture increases the reference count,
4221 * and the the application must set the texture back to null (or have a leaky application),
4222 * This means we should pass the refcount up to the parent
4223 *******************************/
4224 if (NULL != This->updateStateBlock->textures[Stage]) {
4225 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4226 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4228 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4229 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4230 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4231 * so the COLOROP and ALPHAOP have to be dirtified.
4233 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4236 if(bindCount == 1) {
4237 new->baseTexture.sampler = Stage;
4239 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4243 if (NULL != oldTexture) {
4244 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4245 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4247 IWineD3DBaseTexture_Release(oldTexture);
4248 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4250 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4253 if(bindCount && old->baseTexture.sampler == Stage) {
4255 /* Have to do a search for the other sampler(s) where the texture is bound to
4256 * Shouldn't happen as long as apps bind a texture only to one stage
4258 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4259 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4260 if(This->updateStateBlock->textures[i] == oldTexture) {
4261 old->baseTexture.sampler = i;
4268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4273 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4276 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4278 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4279 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4282 *ppTexture=This->stateBlock->textures[Stage];
4284 IWineD3DBaseTexture_AddRef(*ppTexture);
4286 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4294 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4295 IWineD3DSurface **ppBackBuffer) {
4296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4297 IWineD3DSwapChain *swapChain;
4300 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4302 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4303 if (hr == WINED3D_OK) {
4304 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4305 IWineD3DSwapChain_Release(swapChain);
4307 *ppBackBuffer = NULL;
4312 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4313 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4314 WARN("(%p) : stub, calling idirect3d for now\n", This);
4315 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4318 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4320 IWineD3DSwapChain *swapChain;
4323 if(iSwapChain > 0) {
4324 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4325 if (hr == WINED3D_OK) {
4326 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4327 IWineD3DSwapChain_Release(swapChain);
4329 FIXME("(%p) Error getting display mode\n", This);
4332 /* Don't read the real display mode,
4333 but return the stored mode instead. X11 can't change the color
4334 depth, and some apps are pretty angry if they SetDisplayMode from
4335 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4337 Also don't relay to the swapchain because with ddraw it's possible
4338 that there isn't a swapchain at all */
4339 pMode->Width = This->ddraw_width;
4340 pMode->Height = This->ddraw_height;
4341 pMode->Format = This->ddraw_format;
4342 pMode->RefreshRate = 0;
4349 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4351 TRACE("(%p)->(%p)\n", This, hWnd);
4353 if(This->ddraw_fullscreen) {
4354 if(This->ddraw_window && This->ddraw_window != hWnd) {
4355 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4357 if(hWnd && This->ddraw_window != hWnd) {
4358 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4362 This->ddraw_window = hWnd;
4366 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4368 TRACE("(%p)->(%p)\n", This, hWnd);
4370 *hWnd = This->ddraw_window;
4375 * Stateblock related functions
4378 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4380 IWineD3DStateBlockImpl *object;
4381 HRESULT temp_result;
4384 TRACE("(%p)\n", This);
4386 if (This->isRecordingState) {
4387 return WINED3DERR_INVALIDCALL;
4390 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4391 if (NULL == object ) {
4392 FIXME("(%p)Error allocating memory for stateblock\n", This);
4393 return E_OUTOFMEMORY;
4395 TRACE("(%p) created object %p\n", This, object);
4396 object->wineD3DDevice= This;
4397 /** FIXME: object->parent = parent; **/
4398 object->parent = NULL;
4399 object->blockType = WINED3DSBT_RECORDED;
4401 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4403 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4404 list_init(&object->lightMap[i]);
4407 temp_result = allocate_shader_constants(object);
4408 if (WINED3D_OK != temp_result)
4411 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4412 This->updateStateBlock = object;
4413 This->isRecordingState = TRUE;
4415 TRACE("(%p) recording stateblock %p\n",This , object);
4419 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4422 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4424 if (!This->isRecordingState) {
4425 FIXME("(%p) not recording! returning error\n", This);
4426 *ppStateBlock = NULL;
4427 return WINED3DERR_INVALIDCALL;
4430 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4431 if(object->changed.renderState[i]) {
4432 object->contained_render_states[object->num_contained_render_states] = i;
4433 object->num_contained_render_states++;
4436 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4437 if(object->changed.transform[i]) {
4438 object->contained_transform_states[object->num_contained_transform_states] = i;
4439 object->num_contained_transform_states++;
4442 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4443 if(object->changed.vertexShaderConstantsF[i]) {
4444 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4445 object->num_contained_vs_consts_f++;
4448 for(i = 0; i < MAX_CONST_I; i++) {
4449 if(object->changed.vertexShaderConstantsI[i]) {
4450 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4451 object->num_contained_vs_consts_i++;
4454 for(i = 0; i < MAX_CONST_B; i++) {
4455 if(object->changed.vertexShaderConstantsB[i]) {
4456 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4457 object->num_contained_vs_consts_b++;
4460 for(i = 0; i < MAX_CONST_I; i++) {
4461 if(object->changed.pixelShaderConstantsI[i]) {
4462 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4463 object->num_contained_ps_consts_i++;
4466 for(i = 0; i < MAX_CONST_B; i++) {
4467 if(object->changed.pixelShaderConstantsB[i]) {
4468 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4469 object->num_contained_ps_consts_b++;
4472 for(i = 0; i < MAX_TEXTURES; i++) {
4473 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4474 if(object->changed.textureState[i][j]) {
4475 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4476 object->contained_tss_states[object->num_contained_tss_states].state = j;
4477 object->num_contained_tss_states++;
4481 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4482 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4483 if(object->changed.samplerState[i][j]) {
4484 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4485 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4486 object->num_contained_sampler_states++;
4491 *ppStateBlock = (IWineD3DStateBlock*) object;
4492 This->isRecordingState = FALSE;
4493 This->updateStateBlock = This->stateBlock;
4494 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4495 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4496 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4501 * Scene related functions
4503 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4504 /* At the moment we have no need for any functionality at the beginning
4506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4507 TRACE("(%p)\n", This);
4510 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4511 return WINED3DERR_INVALIDCALL;
4513 This->inScene = TRUE;
4517 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4519 TRACE("(%p)\n", This);
4521 if(!This->inScene) {
4522 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4523 return WINED3DERR_INVALIDCALL;
4526 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4527 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4529 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4532 checkGLcall("glFlush");
4535 This->inScene = FALSE;
4539 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4540 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4541 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 IWineD3DSwapChain *swapChain = NULL;
4545 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4547 TRACE("(%p) Presenting the frame\n", This);
4549 for(i = 0 ; i < swapchains ; i ++) {
4551 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4552 TRACE("presentinng chain %d, %p\n", i, swapChain);
4553 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4554 IWineD3DSwapChain_Release(swapChain);
4560 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4561 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4563 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4565 GLbitfield glMask = 0;
4567 CONST WINED3DRECT* curRect;
4569 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4570 Count, pRects, Flags, Color, Z, Stencil);
4572 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4573 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4574 /* TODO: What about depth stencil buffers without stencil bits? */
4575 return WINED3DERR_INVALIDCALL;
4578 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4579 * and not the last active one.
4581 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4584 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4585 apply_fbo_state(iface);
4588 if (Count > 0 && pRects) {
4594 /* Only set the values up once, as they are not changing */
4595 if (Flags & WINED3DCLEAR_STENCIL) {
4596 glClearStencil(Stencil);
4597 checkGLcall("glClearStencil");
4598 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4599 glStencilMask(0xFFFFFFFF);
4602 if (Flags & WINED3DCLEAR_ZBUFFER) {
4603 glDepthMask(GL_TRUE);
4605 checkGLcall("glClearDepth");
4606 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4610 if (Flags & WINED3DCLEAR_TARGET) {
4611 TRACE("Clearing screen with glClear to color %x\n", Color);
4612 glClearColor(D3DCOLOR_R(Color),
4616 checkGLcall("glClearColor");
4618 /* Clear ALL colors! */
4619 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4620 glMask = glMask | GL_COLOR_BUFFER_BIT;
4624 /* In drawable flag is set below */
4626 if (This->render_offscreen) {
4627 glScissor(This->stateBlock->viewport.X,
4628 This->stateBlock->viewport.Y,
4629 This->stateBlock->viewport.Width,
4630 This->stateBlock->viewport.Height);
4632 glScissor(This->stateBlock->viewport.X,
4633 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4634 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4635 This->stateBlock->viewport.Width,
4636 This->stateBlock->viewport.Height);
4638 checkGLcall("glScissor");
4640 checkGLcall("glClear");
4642 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4643 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4645 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4646 curRect[0].x2 < target->currentDesc.Width ||
4647 curRect[0].y2 < target->currentDesc.Height) {
4648 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4649 blt_to_drawable(This, target);
4653 /* Now process each rect in turn */
4654 for (i = 0; i < Count; i++) {
4655 /* Note gl uses lower left, width/height */
4656 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4657 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4658 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4659 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4661 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4662 * The rectangle is not cleared, no error is returned, but further rectanlges are
4663 * still cleared if they are valid
4665 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4666 TRACE("Rectangle with negative dimensions, ignoring\n");
4670 if(This->render_offscreen) {
4671 glScissor(curRect[i].x1, curRect[i].y1,
4672 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4674 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4675 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4677 checkGLcall("glScissor");
4680 checkGLcall("glClear");
4684 /* Restore the old values (why..?) */
4685 if (Flags & WINED3DCLEAR_STENCIL) {
4686 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4688 if (Flags & WINED3DCLEAR_TARGET) {
4689 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4690 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4691 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4692 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4693 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4698 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4699 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4701 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4702 target->Flags |= SFLAG_INTEXTURE;
4703 target->Flags &= ~SFLAG_INSYSMEM;
4705 target->Flags |= SFLAG_INDRAWABLE;
4706 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4714 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4715 UINT PrimitiveCount) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4719 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4720 debug_d3dprimitivetype(PrimitiveType),
4721 StartVertex, PrimitiveCount);
4723 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4724 if(This->stateBlock->streamIsUP) {
4725 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4726 This->stateBlock->streamIsUP = FALSE;
4729 if(This->stateBlock->loadBaseVertexIndex != 0) {
4730 This->stateBlock->loadBaseVertexIndex = 0;
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4733 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4734 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4735 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4739 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4740 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4741 WINED3DPRIMITIVETYPE PrimitiveType,
4742 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4746 IWineD3DIndexBuffer *pIB;
4747 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4750 pIB = This->stateBlock->pIndexData;
4752 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4753 * without an index buffer set. (The first time at least...)
4754 * D3D8 simply dies, but I doubt it can do much harm to return
4755 * D3DERR_INVALIDCALL there as well. */
4756 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4757 return WINED3DERR_INVALIDCALL;
4760 if(This->stateBlock->streamIsUP) {
4761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4762 This->stateBlock->streamIsUP = FALSE;
4764 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4766 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4767 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4768 minIndex, NumVertices, startIndex, primCount);
4770 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4771 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4777 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4778 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4782 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4783 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4788 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4789 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4790 UINT VertexStreamZeroStride) {
4791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4792 IWineD3DVertexBuffer *vb;
4794 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4795 debug_d3dprimitivetype(PrimitiveType),
4796 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4798 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4799 vb = This->stateBlock->streamSource[0];
4800 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4801 if(vb) IWineD3DVertexBuffer_Release(vb);
4802 This->stateBlock->streamOffset[0] = 0;
4803 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4804 This->stateBlock->streamIsUP = TRUE;
4805 This->stateBlock->loadBaseVertexIndex = 0;
4807 /* TODO: Only mark dirty if drawing from a different UP address */
4808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4810 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4811 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4813 /* MSDN specifies stream zero settings must be set to NULL */
4814 This->stateBlock->streamStride[0] = 0;
4815 This->stateBlock->streamSource[0] = NULL;
4817 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4818 * the new stream sources or use UP drawing again
4823 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4824 UINT MinVertexIndex, UINT NumVertices,
4825 UINT PrimitiveCount, CONST void* pIndexData,
4826 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4827 UINT VertexStreamZeroStride) {
4829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4830 IWineD3DVertexBuffer *vb;
4831 IWineD3DIndexBuffer *ib;
4833 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4834 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4835 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4836 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4838 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4844 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4845 vb = This->stateBlock->streamSource[0];
4846 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4847 if(vb) IWineD3DVertexBuffer_Release(vb);
4848 This->stateBlock->streamIsUP = TRUE;
4849 This->stateBlock->streamOffset[0] = 0;
4850 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4852 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4853 This->stateBlock->baseVertexIndex = 0;
4854 This->stateBlock->loadBaseVertexIndex = 0;
4855 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4859 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4861 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4862 This->stateBlock->streamSource[0] = NULL;
4863 This->stateBlock->streamStride[0] = 0;
4864 ib = This->stateBlock->pIndexData;
4866 IWineD3DIndexBuffer_Release(ib);
4867 This->stateBlock->pIndexData = NULL;
4869 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4870 * SetStreamSource to specify a vertex buffer
4876 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4879 /* Mark the state dirty until we have nicer tracking
4880 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4885 This->stateBlock->baseVertexIndex = 0;
4886 This->up_strided = DrawPrimStrideData;
4887 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4888 This->up_strided = NULL;
4892 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4894 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4896 /* Mark the state dirty until we have nicer tracking
4897 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4900 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4901 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4902 This->stateBlock->streamIsUP = TRUE;
4903 This->stateBlock->baseVertexIndex = 0;
4904 This->up_strided = DrawPrimStrideData;
4905 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4906 This->up_strided = NULL;
4911 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4912 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4914 HRESULT hr = WINED3D_OK;
4915 WINED3DRESOURCETYPE sourceType;
4916 WINED3DRESOURCETYPE destinationType;
4919 /* TODO: think about moving the code into IWineD3DBaseTexture */
4921 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4923 /* verify that the source and destination textures aren't NULL */
4924 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4925 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4926 This, pSourceTexture, pDestinationTexture);
4927 hr = WINED3DERR_INVALIDCALL;
4930 if (pSourceTexture == pDestinationTexture) {
4931 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4932 This, pSourceTexture, pDestinationTexture);
4933 hr = WINED3DERR_INVALIDCALL;
4935 /* Verify that the source and destination textures are the same type */
4936 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4937 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4939 if (sourceType != destinationType) {
4940 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4942 hr = WINED3DERR_INVALIDCALL;
4945 /* check that both textures have the identical numbers of levels */
4946 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4947 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4948 hr = WINED3DERR_INVALIDCALL;
4951 if (WINED3D_OK == hr) {
4953 /* Make sure that the destination texture is loaded */
4954 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4956 /* Update every surface level of the texture */
4957 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4959 switch (sourceType) {
4960 case WINED3DRTYPE_TEXTURE:
4962 IWineD3DSurface *srcSurface;
4963 IWineD3DSurface *destSurface;
4965 for (i = 0 ; i < levels ; ++i) {
4966 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4967 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4968 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4969 IWineD3DSurface_Release(srcSurface);
4970 IWineD3DSurface_Release(destSurface);
4971 if (WINED3D_OK != hr) {
4972 WARN("(%p) : Call to update surface failed\n", This);
4978 case WINED3DRTYPE_CUBETEXTURE:
4980 IWineD3DSurface *srcSurface;
4981 IWineD3DSurface *destSurface;
4982 WINED3DCUBEMAP_FACES faceType;
4984 for (i = 0 ; i < levels ; ++i) {
4985 /* Update each cube face */
4986 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4987 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4988 if (WINED3D_OK != hr) {
4989 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4991 TRACE("Got srcSurface %p\n", srcSurface);
4993 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4994 if (WINED3D_OK != hr) {
4995 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4997 TRACE("Got desrSurface %p\n", destSurface);
4999 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5000 IWineD3DSurface_Release(srcSurface);
5001 IWineD3DSurface_Release(destSurface);
5002 if (WINED3D_OK != hr) {
5003 WARN("(%p) : Call to update surface failed\n", This);
5010 #if 0 /* TODO: Add support for volume textures */
5011 case WINED3DRTYPE_VOLUMETEXTURE:
5013 IWineD3DVolume srcVolume = NULL;
5014 IWineD3DSurface destVolume = NULL;
5016 for (i = 0 ; i < levels ; ++i) {
5017 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5018 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5019 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5020 IWineD3DVolume_Release(srcSurface);
5021 IWineD3DVolume_Release(destSurface);
5022 if (WINED3D_OK != hr) {
5023 WARN("(%p) : Call to update volume failed\n", This);
5031 FIXME("(%p) : Unsupported source and destination type\n", This);
5032 hr = WINED3DERR_INVALIDCALL;
5039 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5040 IWineD3DSwapChain *swapChain;
5042 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5043 if(hr == WINED3D_OK) {
5044 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5045 IWineD3DSwapChain_Release(swapChain);
5050 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5052 /* return a sensible default */
5054 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5055 FIXME("(%p) : stub\n", This);
5059 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5062 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5063 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5064 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5065 return WINED3DERR_INVALIDCALL;
5067 for (j = 0; j < 256; ++j) {
5068 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5069 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5070 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5071 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5073 TRACE("(%p) : returning\n", This);
5077 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5080 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5081 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5082 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5083 return WINED3DERR_INVALIDCALL;
5085 for (j = 0; j < 256; ++j) {
5086 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5087 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5088 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5089 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5091 TRACE("(%p) : returning\n", This);
5095 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5097 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5098 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5099 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5100 return WINED3DERR_INVALIDCALL;
5102 /*TODO: stateblocks */
5103 This->currentPalette = PaletteNumber;
5104 TRACE("(%p) : returning\n", This);
5108 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5110 if (PaletteNumber == NULL) {
5111 WARN("(%p) : returning Invalid Call\n", This);
5112 return WINED3DERR_INVALIDCALL;
5114 /*TODO: stateblocks */
5115 *PaletteNumber = This->currentPalette;
5116 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5120 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5122 static BOOL showFixmes = TRUE;
5124 FIXME("(%p) : stub\n", This);
5128 This->softwareVertexProcessing = bSoftware;
5133 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5135 static BOOL showFixmes = TRUE;
5137 FIXME("(%p) : stub\n", This);
5140 return This->softwareVertexProcessing;
5144 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5146 IWineD3DSwapChain *swapChain;
5149 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5151 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5152 if(hr == WINED3D_OK){
5153 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5154 IWineD3DSwapChain_Release(swapChain);
5156 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5162 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5163 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5164 static BOOL showfixmes = TRUE;
5165 if(nSegments != 0.0f) {
5167 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5174 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5176 static BOOL showfixmes = TRUE;
5178 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5184 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5186 /** TODO: remove casts to IWineD3DSurfaceImpl
5187 * NOTE: move code to surface to accomplish this
5188 ****************************************/
5189 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5190 int srcWidth, srcHeight;
5191 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5192 WINED3DFORMAT destFormat, srcFormat;
5194 int srcLeft, destLeft, destTop;
5195 WINED3DPOOL srcPool, destPool;
5197 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5198 glDescriptor *glDescription = NULL;
5201 CONVERT_TYPES convert = NO_CONVERSION;
5203 WINED3DSURFACE_DESC winedesc;
5205 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5206 memset(&winedesc, 0, sizeof(winedesc));
5207 winedesc.Width = &srcSurfaceWidth;
5208 winedesc.Height = &srcSurfaceHeight;
5209 winedesc.Pool = &srcPool;
5210 winedesc.Format = &srcFormat;
5212 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5214 winedesc.Width = &destSurfaceWidth;
5215 winedesc.Height = &destSurfaceHeight;
5216 winedesc.Pool = &destPool;
5217 winedesc.Format = &destFormat;
5218 winedesc.Size = &destSize;
5220 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5222 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5223 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5224 return WINED3DERR_INVALIDCALL;
5227 /* This call loads the opengl surface directly, instead of copying the surface to the
5228 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5229 * copy in sysmem and use regular surface loading.
5231 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5232 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5233 if(convert != NO_CONVERSION) {
5234 return IWineD3DSurface_BltFast(pDestinationSurface,
5235 pDestPoint ? pDestPoint->x : 0,
5236 pDestPoint ? pDestPoint->y : 0,
5237 pSourceSurface, (RECT *) pSourceRect, 0);
5240 if (destFormat == WINED3DFMT_UNKNOWN) {
5241 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5242 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5244 /* Get the update surface description */
5245 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5248 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5252 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5253 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5254 checkGLcall("glActiveTextureARB");
5257 /* Make sure the surface is loaded and up to date */
5258 IWineD3DSurface_PreLoad(pDestinationSurface);
5260 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5262 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5263 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5264 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5265 srcLeft = pSourceRect ? pSourceRect->left : 0;
5266 destLeft = pDestPoint ? pDestPoint->x : 0;
5267 destTop = pDestPoint ? pDestPoint->y : 0;
5270 /* This function doesn't support compressed textures
5271 the pitch is just bytesPerPixel * width */
5272 if(srcWidth != srcSurfaceWidth || srcLeft ){
5273 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5274 offset += srcLeft * pSrcSurface->bytesPerPixel;
5275 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5277 /* TODO DXT formats */
5279 if(pSourceRect != NULL && pSourceRect->top != 0){
5280 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5282 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5284 ,glDescription->level
5289 ,glDescription->glFormat
5290 ,glDescription->glType
5291 ,IWineD3DSurface_GetData(pSourceSurface)
5295 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5297 /* need to lock the surface to get the data */
5298 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5301 /* TODO: Cube and volume support */
5303 /* not a whole row so we have to do it a line at a time */
5306 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5307 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5309 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5311 glTexSubImage2D(glDescription->target
5312 ,glDescription->level
5317 ,glDescription->glFormat
5318 ,glDescription->glType
5319 ,data /* could be quicker using */
5324 } else { /* Full width, so just write out the whole texture */
5326 if (WINED3DFMT_DXT1 == destFormat ||
5327 WINED3DFMT_DXT2 == destFormat ||
5328 WINED3DFMT_DXT3 == destFormat ||
5329 WINED3DFMT_DXT4 == destFormat ||
5330 WINED3DFMT_DXT5 == destFormat) {
5331 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5332 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5333 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5334 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5335 } if (destFormat != srcFormat) {
5336 FIXME("Updating mixed format compressed texture is not curretly support\n");
5338 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5339 glDescription->level,
5340 glDescription->glFormatInternal,
5345 IWineD3DSurface_GetData(pSourceSurface));
5348 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5353 glTexSubImage2D(glDescription->target
5354 ,glDescription->level
5359 ,glDescription->glFormat
5360 ,glDescription->glType
5361 ,IWineD3DSurface_GetData(pSourceSurface)
5365 checkGLcall("glTexSubImage2D");
5369 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5370 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5376 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5378 struct WineD3DRectPatch *patch;
5382 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5384 if(!(Handle || pRectPatchInfo)) {
5385 /* TODO: Write a test for the return value, thus the FIXME */
5386 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5387 return WINED3DERR_INVALIDCALL;
5391 i = PATCHMAP_HASHFUNC(Handle);
5393 LIST_FOR_EACH(e, &This->patches[i]) {
5394 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5395 if(patch->Handle == Handle) {
5402 TRACE("Patch does not exist. Creating a new one\n");
5403 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5404 patch->Handle = Handle;
5405 list_add_head(&This->patches[i], &patch->entry);
5407 TRACE("Found existing patch %p\n", patch);
5410 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5411 * attributes we have to tesselate, read back, and draw. This needs a patch
5412 * management structure instance. Create one.
5414 * A possible improvement is to check if a vertex shader is used, and if not directly
5417 FIXME("Drawing an uncached patch. This is slow\n");
5418 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5421 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5422 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5423 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5425 TRACE("Tesselation density or patch info changed, retesselating\n");
5427 if(pRectPatchInfo) {
5428 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5430 patch->numSegs[0] = pNumSegs[0];
5431 patch->numSegs[1] = pNumSegs[1];
5432 patch->numSegs[2] = pNumSegs[2];
5433 patch->numSegs[3] = pNumSegs[3];
5435 hr = tesselate_rectpatch(This, patch);
5437 WARN("Patch tesselation failed\n");
5439 /* Do not release the handle to store the params of the patch */
5441 HeapFree(GetProcessHeap(), 0, patch);
5447 This->currentPatch = patch;
5448 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5449 This->currentPatch = NULL;
5451 /* Destroy uncached patches */
5453 HeapFree(GetProcessHeap(), 0, patch->mem);
5454 HeapFree(GetProcessHeap(), 0, patch);
5459 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5460 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5462 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5463 FIXME("(%p) : Stub\n", This);
5467 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5470 struct WineD3DRectPatch *patch;
5472 TRACE("(%p) Handle(%d)\n", This, Handle);
5474 i = PATCHMAP_HASHFUNC(Handle);
5475 LIST_FOR_EACH(e, &This->patches[i]) {
5476 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5477 if(patch->Handle == Handle) {
5478 TRACE("Deleting patch %p\n", patch);
5479 list_remove(&patch->entry);
5480 HeapFree(GetProcessHeap(), 0, patch->mem);
5481 HeapFree(GetProcessHeap(), 0, patch);
5486 /* TODO: Write a test for the return value */
5487 FIXME("Attempt to destroy nonexistant patch\n");
5488 return WINED3DERR_INVALIDCALL;
5491 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5493 IWineD3DSwapChain *swapchain;
5495 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5496 if (SUCCEEDED(hr)) {
5497 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5504 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5508 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5509 checkGLcall("glGenFramebuffersEXT()");
5511 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5512 checkGLcall("glBindFramebuffer()");
5515 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5516 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5517 IWineD3DBaseTextureImpl *texture_impl;
5518 GLenum texttarget, target;
5521 texttarget = surface_impl->glDescription.target;
5522 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5523 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5525 IWineD3DSurface_PreLoad(surface);
5527 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5528 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5529 glBindTexture(target, old_binding);
5531 /* Update base texture states array */
5532 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5533 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5534 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5535 if (texture_impl->baseTexture.bindCount) {
5536 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5539 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5542 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5543 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5545 checkGLcall("attach_surface_fbo");
5548 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5550 IWineD3DSwapChain *swapchain;
5552 swapchain = get_swapchain(surface);
5556 TRACE("Surface %p is onscreen\n", surface);
5558 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5559 buffer = surface_get_gl_buffer(surface, swapchain);
5560 glDrawBuffer(buffer);
5561 checkGLcall("glDrawBuffer()");
5563 TRACE("Surface %p is offscreen\n", surface);
5564 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5565 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5569 glEnable(GL_SCISSOR_TEST);
5571 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5573 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5574 rect->x2 - rect->x1, rect->y2 - rect->y1);
5576 checkGLcall("glScissor");
5578 glDisable(GL_SCISSOR_TEST);
5580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5582 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5585 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5586 glClear(GL_COLOR_BUFFER_BIT);
5587 checkGLcall("glClear");
5589 if (This->render_offscreen) {
5590 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5592 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5593 checkGLcall("glBindFramebuffer()");
5596 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5597 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5598 glDrawBuffer(GL_BACK);
5599 checkGLcall("glDrawBuffer()");
5603 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5605 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5607 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5609 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5610 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5611 return WINED3DERR_INVALIDCALL;
5614 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5615 color_fill_fbo(iface, pSurface, pRect, color);
5618 /* Just forward this to the DirectDraw blitting engine */
5619 memset(&BltFx, 0, sizeof(BltFx));
5620 BltFx.dwSize = sizeof(BltFx);
5621 BltFx.u5.dwFillColor = color;
5622 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5626 /* rendertarget and deptth stencil functions */
5627 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5630 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5631 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5632 return WINED3DERR_INVALIDCALL;
5635 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5636 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5637 /* Note inc ref on returned surface */
5638 if(*ppRenderTarget != NULL)
5639 IWineD3DSurface_AddRef(*ppRenderTarget);
5643 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5645 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5646 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5647 IWineD3DSwapChainImpl *Swapchain;
5650 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5652 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5653 if(hr != WINED3D_OK) {
5654 ERR("Can't get the swapchain\n");
5658 /* Make sure to release the swapchain */
5659 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5661 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5662 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5663 return WINED3DERR_INVALIDCALL;
5665 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5666 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5667 return WINED3DERR_INVALIDCALL;
5670 if(Swapchain->frontBuffer != Front) {
5671 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5673 if(Swapchain->frontBuffer)
5674 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5675 Swapchain->frontBuffer = Front;
5677 if(Swapchain->frontBuffer) {
5678 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5682 if(Back && !Swapchain->backBuffer) {
5683 /* We need memory for the back buffer array - only one back buffer this way */
5684 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5685 if(!Swapchain->backBuffer) {
5686 ERR("Out of memory\n");
5687 return E_OUTOFMEMORY;
5691 if(Swapchain->backBuffer[0] != Back) {
5692 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5694 /* What to do about the context here in the case of multithreading? Not sure.
5695 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5698 if(!Swapchain->backBuffer[0]) {
5699 /* GL was told to draw to the front buffer at creation,
5702 glDrawBuffer(GL_BACK);
5703 checkGLcall("glDrawBuffer(GL_BACK)");
5704 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5705 Swapchain->presentParms.BackBufferCount = 1;
5707 /* That makes problems - disable for now */
5708 /* glDrawBuffer(GL_FRONT); */
5709 checkGLcall("glDrawBuffer(GL_FRONT)");
5710 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5711 Swapchain->presentParms.BackBufferCount = 0;
5715 if(Swapchain->backBuffer[0])
5716 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5717 Swapchain->backBuffer[0] = Back;
5719 if(Swapchain->backBuffer[0]) {
5720 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5722 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5730 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5732 *ppZStencilSurface = This->depthStencilBuffer;
5733 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5735 if(*ppZStencilSurface != NULL) {
5736 /* Note inc ref on returned surface */
5737 IWineD3DSurface_AddRef(*ppZStencilSurface);
5742 /* TODO: Handle stencil attachments */
5743 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5745 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5747 TRACE("Set depth stencil to %p\n", depth_stencil);
5749 if (depth_stencil_impl) {
5750 if (depth_stencil_impl->current_renderbuffer) {
5751 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5752 checkGLcall("glFramebufferRenderbufferEXT()");
5754 IWineD3DBaseTextureImpl *texture_impl;
5755 GLenum texttarget, target;
5756 GLint old_binding = 0;
5758 texttarget = depth_stencil_impl->glDescription.target;
5759 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5760 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5762 IWineD3DSurface_PreLoad(depth_stencil);
5764 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5765 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5766 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5767 glBindTexture(target, old_binding);
5769 /* Update base texture states array */
5770 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5771 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5772 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5773 if (texture_impl->baseTexture.bindCount) {
5774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5777 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5780 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5781 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5782 checkGLcall("glFramebufferTexture2DEXT()");
5785 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5786 checkGLcall("glFramebufferTexture2DEXT()");
5790 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5792 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5794 TRACE("Set render target %u to %p\n", idx, render_target);
5797 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5798 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5800 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5801 checkGLcall("glFramebufferTexture2DEXT()");
5803 This->draw_buffers[idx] = GL_NONE;
5807 static void check_fbo_status(IWineD3DDevice *iface) {
5808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5811 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5812 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5813 TRACE("FBO complete\n");
5815 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5817 /* Dump the FBO attachments */
5818 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5819 IWineD3DSurfaceImpl *attachment;
5822 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5823 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5825 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5826 attachment->pow2Width, attachment->pow2Height);
5829 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5831 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5832 attachment->pow2Width, attachment->pow2Height);
5838 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5840 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5841 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5843 if (!ds_impl) return FALSE;
5845 if (ds_impl->current_renderbuffer) {
5846 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5847 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5850 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5851 rt_impl->pow2Height != ds_impl->pow2Height);
5854 void apply_fbo_state(IWineD3DDevice *iface) {
5855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5858 if (This->render_offscreen) {
5859 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5861 /* Apply render targets */
5862 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5863 IWineD3DSurface *render_target = This->render_targets[i];
5864 if (This->fbo_color_attachments[i] != render_target) {
5865 set_render_target_fbo(iface, i, render_target);
5866 This->fbo_color_attachments[i] = render_target;
5870 /* Apply depth targets */
5871 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5872 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5873 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5875 if (This->stencilBufferTarget) {
5876 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5878 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5879 This->fbo_depth_attachment = This->stencilBufferTarget;
5882 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5883 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5884 checkGLcall("glDrawBuffers()");
5886 glDrawBuffer(This->draw_buffers[0]);
5887 checkGLcall("glDrawBuffer()");
5890 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5893 check_fbo_status(iface);
5896 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5897 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5899 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5900 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5903 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5904 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5905 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5906 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5909 case WINED3DTEXF_LINEAR:
5910 gl_filter = GL_LINEAR;
5914 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5915 case WINED3DTEXF_NONE:
5916 case WINED3DTEXF_POINT:
5917 gl_filter = GL_NEAREST;
5921 /* Attach src surface to src fbo */
5922 src_swapchain = get_swapchain(src_surface);
5923 if (src_swapchain) {
5926 TRACE("Source surface %p is onscreen\n", src_surface);
5927 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5930 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5931 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5932 glReadBuffer(buffer);
5933 checkGLcall("glReadBuffer()");
5935 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5936 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5938 TRACE("Source surface %p is offscreen\n", src_surface);
5940 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5941 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5942 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5943 checkGLcall("glReadBuffer()");
5947 /* Attach dst surface to dst fbo */
5948 dst_swapchain = get_swapchain(dst_surface);
5949 if (dst_swapchain) {
5952 TRACE("Destination surface %p is onscreen\n", dst_surface);
5953 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5956 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5957 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5958 glDrawBuffer(buffer);
5959 checkGLcall("glDrawBuffer()");
5961 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5962 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5964 TRACE("Destination surface %p is offscreen\n", dst_surface);
5966 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5967 if(!src_swapchain) {
5968 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5972 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5973 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5974 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5975 checkGLcall("glDrawBuffer()");
5977 glDisable(GL_SCISSOR_TEST);
5978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5981 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5982 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5983 checkGLcall("glBlitFramebuffer()");
5985 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5986 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5987 checkGLcall("glBlitFramebuffer()");
5990 if (This->render_offscreen) {
5991 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5993 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5994 checkGLcall("glBindFramebuffer()");
5997 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5998 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5999 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6000 glDrawBuffer(GL_BACK);
6001 checkGLcall("glDrawBuffer()");
6006 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6008 WINED3DVIEWPORT viewport;
6010 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6012 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6013 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6014 return WINED3DERR_INVALIDCALL;
6017 /* MSDN says that null disables the render target
6018 but a device must always be associated with a render target
6019 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6021 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6024 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6025 FIXME("Trying to set render target 0 to NULL\n");
6026 return WINED3DERR_INVALIDCALL;
6028 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6029 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);
6030 return WINED3DERR_INVALIDCALL;
6033 /* If we are trying to set what we already have, don't bother */
6034 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6035 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6038 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6039 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6040 This->render_targets[RenderTargetIndex] = pRenderTarget;
6042 /* Render target 0 is special */
6043 if(RenderTargetIndex == 0) {
6044 /* Finally, reset the viewport as the MSDN states. */
6045 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6046 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6049 viewport.MaxZ = 1.0f;
6050 viewport.MinZ = 0.0f;
6051 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6052 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6053 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6057 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6059 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6060 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6062 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6067 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6069 HRESULT hr = WINED3D_OK;
6070 IWineD3DSurface *tmp;
6072 TRACE("(%p) Swapping z-buffer\n",This);
6074 if (pNewZStencil == This->stencilBufferTarget) {
6075 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6077 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6078 * depending on the renter target implementation being used.
6079 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6080 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6081 * stencil buffer and incure an extra memory overhead
6082 ******************************************************/
6084 tmp = This->stencilBufferTarget;
6085 This->stencilBufferTarget = pNewZStencil;
6086 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6087 /* should we be calling the parent or the wined3d surface? */
6088 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6089 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6092 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6093 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6103 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6104 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6106 /* TODO: the use of Impl is deprecated. */
6107 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6108 WINED3DLOCKED_RECT lockedRect;
6110 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6112 /* some basic validation checks */
6113 if(This->cursorTexture) {
6114 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6116 glDeleteTextures(1, &This->cursorTexture);
6118 This->cursorTexture = 0;
6121 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6122 This->haveHardwareCursor = TRUE;
6124 This->haveHardwareCursor = FALSE;
6127 WINED3DLOCKED_RECT rect;
6129 /* MSDN: Cursor must be A8R8G8B8 */
6130 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6131 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6132 return WINED3DERR_INVALIDCALL;
6135 /* MSDN: Cursor must be smaller than the display mode */
6136 if(pSur->currentDesc.Width > This->ddraw_width ||
6137 pSur->currentDesc.Height > This->ddraw_height) {
6138 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);
6139 return WINED3DERR_INVALIDCALL;
6142 if (!This->haveHardwareCursor) {
6143 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6145 /* Do not store the surface's pointer because the application may
6146 * release it after setting the cursor image. Windows doesn't
6147 * addref the set surface, so we can't do this either without
6148 * creating circular refcount dependencies. Copy out the gl texture
6151 This->cursorWidth = pSur->currentDesc.Width;
6152 This->cursorHeight = pSur->currentDesc.Height;
6153 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6155 const GlPixelFormatDesc *glDesc;
6156 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6157 char *mem, *bits = (char *)rect.pBits;
6158 GLint intfmt = glDesc->glInternal;
6159 GLint format = glDesc->glFormat;
6160 GLint type = glDesc->glType;
6161 INT height = This->cursorHeight;
6162 INT width = This->cursorWidth;
6163 INT bpp = tableEntry->bpp;
6166 /* Reformat the texture memory (pitch and width can be
6168 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6169 for(i = 0; i < height; i++)
6170 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6171 IWineD3DSurface_UnlockRect(pCursorBitmap);
6174 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6175 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6176 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6179 /* Make sure that a proper texture unit is selected */
6180 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6181 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6182 checkGLcall("glActiveTextureARB");
6184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6185 /* Create a new cursor texture */
6186 glGenTextures(1, &This->cursorTexture);
6187 checkGLcall("glGenTextures");
6188 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6189 checkGLcall("glBindTexture");
6190 /* Copy the bitmap memory into the cursor texture */
6191 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6192 HeapFree(GetProcessHeap(), 0, mem);
6193 checkGLcall("glTexImage2D");
6195 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6196 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6197 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6204 FIXME("A cursor texture was not returned.\n");
6205 This->cursorTexture = 0;
6210 /* Draw a hardware cursor */
6211 ICONINFO cursorInfo;
6213 /* Create and clear maskBits because it is not needed for
6214 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6216 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6217 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6218 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6219 WINED3DLOCK_NO_DIRTY_UPDATE |
6220 WINED3DLOCK_READONLY
6222 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6223 pSur->currentDesc.Height);
6225 cursorInfo.fIcon = FALSE;
6226 cursorInfo.xHotspot = XHotSpot;
6227 cursorInfo.yHotspot = YHotSpot;
6228 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6229 pSur->currentDesc.Height, 1,
6231 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6232 pSur->currentDesc.Height, 1,
6233 32, lockedRect.pBits);
6234 IWineD3DSurface_UnlockRect(pCursorBitmap);
6235 /* Create our cursor and clean up. */
6236 cursor = CreateIconIndirect(&cursorInfo);
6238 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6239 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6240 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6241 This->hardwareCursor = cursor;
6242 HeapFree(GetProcessHeap(), 0, maskBits);
6246 This->xHotSpot = XHotSpot;
6247 This->yHotSpot = YHotSpot;
6251 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6253 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6255 This->xScreenSpace = XScreenSpace;
6256 This->yScreenSpace = YScreenSpace;
6262 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6264 BOOL oldVisible = This->bCursorVisible;
6267 TRACE("(%p) : visible(%d)\n", This, bShow);
6270 * When ShowCursor is first called it should make the cursor appear at the OS's last
6271 * known cursor position. Because of this, some applications just repetitively call
6272 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6275 This->xScreenSpace = pt.x;
6276 This->yScreenSpace = pt.y;
6278 if (This->haveHardwareCursor) {
6279 This->bCursorVisible = bShow;
6281 SetCursor(This->hardwareCursor);
6287 if (This->cursorTexture)
6288 This->bCursorVisible = bShow;
6294 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6296 TRACE("(%p) : state (%u)\n", This, This->state);
6297 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6298 switch (This->state) {
6301 case WINED3DERR_DEVICELOST:
6303 ResourceList *resourceList = This->resources;
6304 while (NULL != resourceList) {
6305 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6306 return WINED3DERR_DEVICENOTRESET;
6307 resourceList = resourceList->next;
6309 return WINED3DERR_DEVICELOST;
6311 case WINED3DERR_DRIVERINTERNALERROR:
6312 return WINED3DERR_DRIVERINTERNALERROR;
6316 return WINED3DERR_DRIVERINTERNALERROR;
6320 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6322 /** FIXME: Resource tracking needs to be done,
6323 * The closes we can do to this is set the priorities of all managed textures low
6324 * and then reset them.
6325 ***********************************************************/
6326 FIXME("(%p) : stub\n", This);
6330 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6331 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6333 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6334 if(surface->Flags & SFLAG_DIBSECTION) {
6335 /* Release the DC */
6336 SelectObject(surface->hDC, surface->dib.holdbitmap);
6337 DeleteDC(surface->hDC);
6338 /* Release the DIB section */
6339 DeleteObject(surface->dib.DIBsection);
6340 surface->dib.bitmap_data = NULL;
6341 surface->resource.allocatedMemory = NULL;
6342 surface->Flags &= ~SFLAG_DIBSECTION;
6344 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6345 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6346 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6347 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6348 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6350 surface->pow2Width = surface->pow2Height = 1;
6351 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6352 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6354 if(surface->glDescription.textureName) {
6355 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6357 glDeleteTextures(1, &surface->glDescription.textureName);
6359 surface->glDescription.textureName = 0;
6360 surface->Flags &= ~SFLAG_CLIENT;
6362 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6363 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6364 surface->Flags |= SFLAG_NONPOW2;
6366 surface->Flags &= ~SFLAG_NONPOW2;
6368 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6369 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6372 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6374 IWineD3DSwapChainImpl *swapchain;
6376 BOOL DisplayModeChanged = FALSE;
6377 WINED3DDISPLAYMODE mode;
6378 TRACE("(%p)\n", This);
6380 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6382 ERR("Failed to get the first implicit swapchain\n");
6386 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6387 * on an existing gl context, so there's no real need for recreation.
6389 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6391 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6393 TRACE("New params:\n");
6394 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6395 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6396 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6397 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6398 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6399 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6400 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6401 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6402 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6403 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6404 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6405 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6406 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6408 /* No special treatment of these parameters. Just store them */
6409 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6410 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6411 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6412 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6414 /* What to do about these? */
6415 if(pPresentationParameters->BackBufferCount != 0 &&
6416 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6417 ERR("Cannot change the back buffer count yet\n");
6419 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6420 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6421 ERR("Cannot change the back buffer format yet\n");
6423 if(pPresentationParameters->hDeviceWindow != NULL &&
6424 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6425 ERR("Cannot change the device window yet\n");
6427 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6428 ERR("What do do about a changed auto depth stencil parameter?\n");
6431 if(pPresentationParameters->Windowed) {
6432 mode.Width = swapchain->orig_width;
6433 mode.Height = swapchain->orig_height;
6434 mode.RefreshRate = 0;
6435 mode.Format = swapchain->presentParms.BackBufferFormat;
6437 mode.Width = pPresentationParameters->BackBufferWidth;
6438 mode.Height = pPresentationParameters->BackBufferHeight;
6439 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6440 mode.Format = swapchain->presentParms.BackBufferFormat;
6443 /* Should Width == 800 && Height == 0 set 800x600? */
6444 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6445 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6446 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6453 vp.Width = pPresentationParameters->BackBufferWidth;
6454 vp.Height = pPresentationParameters->BackBufferHeight;
6458 if(!pPresentationParameters->Windowed) {
6459 DisplayModeChanged = TRUE;
6461 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6462 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6464 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6465 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6466 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6469 /* Now set the new viewport */
6470 IWineD3DDevice_SetViewport(iface, &vp);
6473 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6474 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6475 DisplayModeChanged) {
6477 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6478 if(!pPresentationParameters->Windowed) {
6479 IWineD3DDevice_SetFullscreen(iface, TRUE);
6482 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6484 /* Switching out of fullscreen mode? First set the original res, then change the window */
6485 if(pPresentationParameters->Windowed) {
6486 IWineD3DDevice_SetFullscreen(iface, FALSE);
6488 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6491 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6495 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6497 /** FIXME: always true at the moment **/
6498 if(!bEnableDialogs) {
6499 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6505 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6507 TRACE("(%p) : pParameters %p\n", This, pParameters);
6509 *pParameters = This->createParms;
6513 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6514 IWineD3DSwapChain *swapchain;
6515 HRESULT hrc = WINED3D_OK;
6517 TRACE("Relaying to swapchain\n");
6519 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6520 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6521 IWineD3DSwapChain_Release(swapchain);
6526 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6527 IWineD3DSwapChain *swapchain;
6528 HRESULT hrc = WINED3D_OK;
6530 TRACE("Relaying to swapchain\n");
6532 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6533 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6534 IWineD3DSwapChain_Release(swapchain);
6540 /** ********************************************************
6541 * Notification functions
6542 ** ********************************************************/
6543 /** This function must be called in the release of a resource when ref == 0,
6544 * the contents of resource must still be correct,
6545 * any handels to other resource held by the caller must be closed
6546 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6547 *****************************************************/
6548 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6550 ResourceList* resourceList;
6552 TRACE("(%p) : resource %p\n", This, resource);
6553 /* add a new texture to the frot of the linked list */
6554 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6555 resourceList->resource = resource;
6557 /* Get the old head */
6558 resourceList->next = This->resources;
6560 This->resources = resourceList;
6561 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6566 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6568 ResourceList* resourceList = NULL;
6569 ResourceList* previousResourceList = NULL;
6571 TRACE("(%p) : resource %p\n", This, resource);
6573 resourceList = This->resources;
6575 while (resourceList != NULL) {
6576 if(resourceList->resource == resource) break;
6577 previousResourceList = resourceList;
6578 resourceList = resourceList->next;
6581 if (resourceList == NULL) {
6582 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6585 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6587 /* make sure we don't leave a hole in the list */
6588 if (previousResourceList != NULL) {
6589 previousResourceList->next = resourceList->next;
6591 This->resources = resourceList->next;
6598 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6602 TRACE("(%p) : resource %p\n", This, resource);
6603 switch(IWineD3DResource_GetType(resource)){
6604 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6605 case WINED3DRTYPE_SURFACE: {
6608 /* Cleanup any FBO attachments if d3d is enabled */
6609 if(This->d3d_initialized) {
6610 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6611 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6612 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6613 set_render_target_fbo(iface, i, NULL);
6614 This->fbo_color_attachments[i] = NULL;
6617 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6618 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6619 set_depth_stencil_fbo(iface, NULL);
6620 This->fbo_depth_attachment = NULL;
6626 case WINED3DRTYPE_TEXTURE:
6627 case WINED3DRTYPE_CUBETEXTURE:
6628 case WINED3DRTYPE_VOLUMETEXTURE:
6629 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6630 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6631 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6632 This->stateBlock->textures[counter] = NULL;
6634 if (This->updateStateBlock != This->stateBlock ){
6635 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6636 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6637 This->updateStateBlock->textures[counter] = NULL;
6642 case WINED3DRTYPE_VOLUME:
6643 /* TODO: nothing really? */
6645 case WINED3DRTYPE_VERTEXBUFFER:
6646 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6649 TRACE("Cleaning up stream pointers\n");
6651 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6652 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6653 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6655 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6656 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6657 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6658 This->updateStateBlock->streamSource[streamNumber] = 0;
6659 /* Set changed flag? */
6662 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) */
6663 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6664 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6665 This->stateBlock->streamSource[streamNumber] = 0;
6668 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6669 else { /* This shouldn't happen */
6670 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6677 case WINED3DRTYPE_INDEXBUFFER:
6678 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6679 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6680 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6681 This->updateStateBlock->pIndexData = NULL;
6684 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6685 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6686 This->stateBlock->pIndexData = NULL;
6692 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6697 /* Remove the resoruce from the resourceStore */
6698 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6700 TRACE("Resource released\n");
6704 /**********************************************************
6705 * IWineD3DDevice VTbl follows
6706 **********************************************************/
6708 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6710 /*** IUnknown methods ***/
6711 IWineD3DDeviceImpl_QueryInterface,
6712 IWineD3DDeviceImpl_AddRef,
6713 IWineD3DDeviceImpl_Release,
6714 /*** IWineD3DDevice methods ***/
6715 IWineD3DDeviceImpl_GetParent,
6716 /*** Creation methods**/
6717 IWineD3DDeviceImpl_CreateVertexBuffer,
6718 IWineD3DDeviceImpl_CreateIndexBuffer,
6719 IWineD3DDeviceImpl_CreateStateBlock,
6720 IWineD3DDeviceImpl_CreateSurface,
6721 IWineD3DDeviceImpl_CreateTexture,
6722 IWineD3DDeviceImpl_CreateVolumeTexture,
6723 IWineD3DDeviceImpl_CreateVolume,
6724 IWineD3DDeviceImpl_CreateCubeTexture,
6725 IWineD3DDeviceImpl_CreateQuery,
6726 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6727 IWineD3DDeviceImpl_CreateVertexDeclaration,
6728 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6729 IWineD3DDeviceImpl_CreateVertexShader,
6730 IWineD3DDeviceImpl_CreatePixelShader,
6731 IWineD3DDeviceImpl_CreatePalette,
6732 /*** Odd functions **/
6733 IWineD3DDeviceImpl_Init3D,
6734 IWineD3DDeviceImpl_Uninit3D,
6735 IWineD3DDeviceImpl_SetFullscreen,
6736 IWineD3DDeviceImpl_SetMultithreaded,
6737 IWineD3DDeviceImpl_EvictManagedResources,
6738 IWineD3DDeviceImpl_GetAvailableTextureMem,
6739 IWineD3DDeviceImpl_GetBackBuffer,
6740 IWineD3DDeviceImpl_GetCreationParameters,
6741 IWineD3DDeviceImpl_GetDeviceCaps,
6742 IWineD3DDeviceImpl_GetDirect3D,
6743 IWineD3DDeviceImpl_GetDisplayMode,
6744 IWineD3DDeviceImpl_SetDisplayMode,
6745 IWineD3DDeviceImpl_GetHWND,
6746 IWineD3DDeviceImpl_SetHWND,
6747 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6748 IWineD3DDeviceImpl_GetRasterStatus,
6749 IWineD3DDeviceImpl_GetSwapChain,
6750 IWineD3DDeviceImpl_Reset,
6751 IWineD3DDeviceImpl_SetDialogBoxMode,
6752 IWineD3DDeviceImpl_SetCursorProperties,
6753 IWineD3DDeviceImpl_SetCursorPosition,
6754 IWineD3DDeviceImpl_ShowCursor,
6755 IWineD3DDeviceImpl_TestCooperativeLevel,
6756 /*** Getters and setters **/
6757 IWineD3DDeviceImpl_SetClipPlane,
6758 IWineD3DDeviceImpl_GetClipPlane,
6759 IWineD3DDeviceImpl_SetClipStatus,
6760 IWineD3DDeviceImpl_GetClipStatus,
6761 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6762 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6763 IWineD3DDeviceImpl_SetDepthStencilSurface,
6764 IWineD3DDeviceImpl_GetDepthStencilSurface,
6765 IWineD3DDeviceImpl_SetFVF,
6766 IWineD3DDeviceImpl_GetFVF,
6767 IWineD3DDeviceImpl_SetGammaRamp,
6768 IWineD3DDeviceImpl_GetGammaRamp,
6769 IWineD3DDeviceImpl_SetIndices,
6770 IWineD3DDeviceImpl_GetIndices,
6771 IWineD3DDeviceImpl_SetBaseVertexIndex,
6772 IWineD3DDeviceImpl_GetBaseVertexIndex,
6773 IWineD3DDeviceImpl_SetLight,
6774 IWineD3DDeviceImpl_GetLight,
6775 IWineD3DDeviceImpl_SetLightEnable,
6776 IWineD3DDeviceImpl_GetLightEnable,
6777 IWineD3DDeviceImpl_SetMaterial,
6778 IWineD3DDeviceImpl_GetMaterial,
6779 IWineD3DDeviceImpl_SetNPatchMode,
6780 IWineD3DDeviceImpl_GetNPatchMode,
6781 IWineD3DDeviceImpl_SetPaletteEntries,
6782 IWineD3DDeviceImpl_GetPaletteEntries,
6783 IWineD3DDeviceImpl_SetPixelShader,
6784 IWineD3DDeviceImpl_GetPixelShader,
6785 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6786 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6787 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6788 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6789 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6790 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6791 IWineD3DDeviceImpl_SetRenderState,
6792 IWineD3DDeviceImpl_GetRenderState,
6793 IWineD3DDeviceImpl_SetRenderTarget,
6794 IWineD3DDeviceImpl_GetRenderTarget,
6795 IWineD3DDeviceImpl_SetFrontBackBuffers,
6796 IWineD3DDeviceImpl_SetSamplerState,
6797 IWineD3DDeviceImpl_GetSamplerState,
6798 IWineD3DDeviceImpl_SetScissorRect,
6799 IWineD3DDeviceImpl_GetScissorRect,
6800 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6801 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6802 IWineD3DDeviceImpl_SetStreamSource,
6803 IWineD3DDeviceImpl_GetStreamSource,
6804 IWineD3DDeviceImpl_SetStreamSourceFreq,
6805 IWineD3DDeviceImpl_GetStreamSourceFreq,
6806 IWineD3DDeviceImpl_SetTexture,
6807 IWineD3DDeviceImpl_GetTexture,
6808 IWineD3DDeviceImpl_SetTextureStageState,
6809 IWineD3DDeviceImpl_GetTextureStageState,
6810 IWineD3DDeviceImpl_SetTransform,
6811 IWineD3DDeviceImpl_GetTransform,
6812 IWineD3DDeviceImpl_SetVertexDeclaration,
6813 IWineD3DDeviceImpl_GetVertexDeclaration,
6814 IWineD3DDeviceImpl_SetVertexShader,
6815 IWineD3DDeviceImpl_GetVertexShader,
6816 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6817 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6818 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6819 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6820 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6821 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6822 IWineD3DDeviceImpl_SetViewport,
6823 IWineD3DDeviceImpl_GetViewport,
6824 IWineD3DDeviceImpl_MultiplyTransform,
6825 IWineD3DDeviceImpl_ValidateDevice,
6826 IWineD3DDeviceImpl_ProcessVertices,
6827 /*** State block ***/
6828 IWineD3DDeviceImpl_BeginStateBlock,
6829 IWineD3DDeviceImpl_EndStateBlock,
6830 /*** Scene management ***/
6831 IWineD3DDeviceImpl_BeginScene,
6832 IWineD3DDeviceImpl_EndScene,
6833 IWineD3DDeviceImpl_Present,
6834 IWineD3DDeviceImpl_Clear,
6836 IWineD3DDeviceImpl_DrawPrimitive,
6837 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6838 IWineD3DDeviceImpl_DrawPrimitiveUP,
6839 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6840 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6841 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6842 IWineD3DDeviceImpl_DrawRectPatch,
6843 IWineD3DDeviceImpl_DrawTriPatch,
6844 IWineD3DDeviceImpl_DeletePatch,
6845 IWineD3DDeviceImpl_ColorFill,
6846 IWineD3DDeviceImpl_UpdateTexture,
6847 IWineD3DDeviceImpl_UpdateSurface,
6848 IWineD3DDeviceImpl_GetFrontBufferData,
6849 /*** object tracking ***/
6850 IWineD3DDeviceImpl_ResourceReleased
6854 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6855 WINED3DRS_ALPHABLENDENABLE ,
6856 WINED3DRS_ALPHAFUNC ,
6857 WINED3DRS_ALPHAREF ,
6858 WINED3DRS_ALPHATESTENABLE ,
6860 WINED3DRS_COLORWRITEENABLE ,
6861 WINED3DRS_DESTBLEND ,
6862 WINED3DRS_DITHERENABLE ,
6863 WINED3DRS_FILLMODE ,
6864 WINED3DRS_FOGDENSITY ,
6866 WINED3DRS_FOGSTART ,
6867 WINED3DRS_LASTPIXEL ,
6868 WINED3DRS_SHADEMODE ,
6869 WINED3DRS_SRCBLEND ,
6870 WINED3DRS_STENCILENABLE ,
6871 WINED3DRS_STENCILFAIL ,
6872 WINED3DRS_STENCILFUNC ,
6873 WINED3DRS_STENCILMASK ,
6874 WINED3DRS_STENCILPASS ,
6875 WINED3DRS_STENCILREF ,
6876 WINED3DRS_STENCILWRITEMASK ,
6877 WINED3DRS_STENCILZFAIL ,
6878 WINED3DRS_TEXTUREFACTOR ,
6889 WINED3DRS_ZWRITEENABLE
6892 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6893 WINED3DTSS_ADDRESSW ,
6894 WINED3DTSS_ALPHAARG0 ,
6895 WINED3DTSS_ALPHAARG1 ,
6896 WINED3DTSS_ALPHAARG2 ,
6897 WINED3DTSS_ALPHAOP ,
6898 WINED3DTSS_BUMPENVLOFFSET ,
6899 WINED3DTSS_BUMPENVLSCALE ,
6900 WINED3DTSS_BUMPENVMAT00 ,
6901 WINED3DTSS_BUMPENVMAT01 ,
6902 WINED3DTSS_BUMPENVMAT10 ,
6903 WINED3DTSS_BUMPENVMAT11 ,
6904 WINED3DTSS_COLORARG0 ,
6905 WINED3DTSS_COLORARG1 ,
6906 WINED3DTSS_COLORARG2 ,
6907 WINED3DTSS_COLOROP ,
6908 WINED3DTSS_RESULTARG ,
6909 WINED3DTSS_TEXCOORDINDEX ,
6910 WINED3DTSS_TEXTURETRANSFORMFLAGS
6913 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6914 WINED3DSAMP_ADDRESSU ,
6915 WINED3DSAMP_ADDRESSV ,
6916 WINED3DSAMP_ADDRESSW ,
6917 WINED3DSAMP_BORDERCOLOR ,
6918 WINED3DSAMP_MAGFILTER ,
6919 WINED3DSAMP_MINFILTER ,
6920 WINED3DSAMP_MIPFILTER ,
6921 WINED3DSAMP_MIPMAPLODBIAS ,
6922 WINED3DSAMP_MAXMIPLEVEL ,
6923 WINED3DSAMP_MAXANISOTROPY ,
6924 WINED3DSAMP_SRGBTEXTURE ,
6925 WINED3DSAMP_ELEMENTINDEX
6928 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6930 WINED3DRS_AMBIENTMATERIALSOURCE ,
6931 WINED3DRS_CLIPPING ,
6932 WINED3DRS_CLIPPLANEENABLE ,
6933 WINED3DRS_COLORVERTEX ,
6934 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6935 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6936 WINED3DRS_FOGDENSITY ,
6938 WINED3DRS_FOGSTART ,
6939 WINED3DRS_FOGTABLEMODE ,
6940 WINED3DRS_FOGVERTEXMODE ,
6941 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6942 WINED3DRS_LIGHTING ,
6943 WINED3DRS_LOCALVIEWER ,
6944 WINED3DRS_MULTISAMPLEANTIALIAS ,
6945 WINED3DRS_MULTISAMPLEMASK ,
6946 WINED3DRS_NORMALIZENORMALS ,
6947 WINED3DRS_PATCHEDGESTYLE ,
6948 WINED3DRS_POINTSCALE_A ,
6949 WINED3DRS_POINTSCALE_B ,
6950 WINED3DRS_POINTSCALE_C ,
6951 WINED3DRS_POINTSCALEENABLE ,
6952 WINED3DRS_POINTSIZE ,
6953 WINED3DRS_POINTSIZE_MAX ,
6954 WINED3DRS_POINTSIZE_MIN ,
6955 WINED3DRS_POINTSPRITEENABLE ,
6956 WINED3DRS_RANGEFOGENABLE ,
6957 WINED3DRS_SPECULARMATERIALSOURCE ,
6958 WINED3DRS_TWEENFACTOR ,
6959 WINED3DRS_VERTEXBLEND ,
6960 WINED3DRS_CULLMODE ,
6964 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6965 WINED3DTSS_TEXCOORDINDEX ,
6966 WINED3DTSS_TEXTURETRANSFORMFLAGS
6969 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6970 WINED3DSAMP_DMAPOFFSET
6973 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6974 DWORD rep = StateTable[state].representative;
6978 WineD3DContext *context;
6981 for(i = 0; i < This->numContexts; i++) {
6982 context = This->contexts[i];
6983 if(isStateDirty(context, rep)) continue;
6985 context->dirtyArray[context->numDirtyEntries++] = rep;
6988 context->isStateDirty[idx] |= (1 << shift);