wined3d: Mark STATE_SCISSORRECT dirty in color_fill_fbo().
[wine/hacks.git] / dlls / wined3d / device.c
blob55c1f467b12f176bfa8594f747eb7dcc1b675e86
1 /*
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-2008 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
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
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 */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
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; \
66 object->ref = 1; \
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; \
75 object->baseShader.ref = 1; \
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); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This->resources)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
182 dumpResources(&This->resources);
185 if(This->contexts) ERR("Context array not freed!\n");
186 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
187 This->haveHardwareCursor = FALSE;
189 IWineD3D_Release(This->wineD3D);
190 This->wineD3D = NULL;
191 HeapFree(GetProcessHeap(), 0, This);
192 TRACE("Freed device %p\n", This);
193 This = NULL;
195 return refCount;
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 *pParent = This->parent;
204 IUnknown_AddRef(This->parent);
205 return WINED3D_OK;
208 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
209 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
210 IUnknown *parent) {
211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
212 IWineD3DVertexBufferImpl *object;
213 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
214 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
215 BOOL conv;
217 if(Size == 0) {
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer = NULL;
220 return WINED3DERR_INVALIDCALL;
221 } else if(Pool == WINED3DPOOL_SCRATCH) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer = NULL;
227 return WINED3DERR_INVALIDCALL;
230 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
232 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
233 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
235 object->fvf = FVF;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
248 * dx7 apps.
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion <= 7 && conv) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
261 } else {
262 object->Flags |= VBFLAG_CREATEVBO;
264 return WINED3D_OK;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
268 GLenum error, glUsage;
269 TRACE("Creating VBO for Index Buffer %p\n", object);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
278 ENTER_GL();
280 while(glGetError());
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR || object->vbo == 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
286 goto out;
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
293 goto out;
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage = GL_STATIC_DRAW_ARB;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
301 error = glGetError();
302 if(error != GL_NO_ERROR) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
304 goto out;
306 LEAVE_GL();
307 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
308 return;
310 out:
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
313 LEAVE_GL();
314 object->vbo = 0;
317 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
318 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
319 HANDLE *sharedHandle, IUnknown *parent) {
320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
321 IWineD3DIndexBufferImpl *object;
322 TRACE("(%p) Creating index buffer\n", This);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
327 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 CreateIndexBufferVBO(This, object);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
332 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
333 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
335 return WINED3D_OK;
338 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DStateBlockImpl *object;
342 int i, j;
343 HRESULT temp_result;
345 D3DCREATEOBJECTINSTANCE(object, StateBlock)
346 object->blockType = Type;
348 for(i = 0; i < LIGHTMAP_SIZE; i++) {
349 list_init(&object->lightMap[i]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type == WINED3DSBT_INIT) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
357 return WINED3D_OK;
360 temp_result = allocate_shader_constants(object);
361 if (WINED3D_OK != temp_result)
362 return temp_result;
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This->stateBlock != NULL)
366 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
367 else
368 memset(object->streamFreq, 1, sizeof(object->streamFreq));
370 /* Reset the ref and type after kludging it */
371 object->wineD3DDevice = This;
372 object->ref = 1;
373 object->blockType = Type;
375 TRACE("Updating changed flags appropriate for type %d\n", Type);
377 if (Type == WINED3DSBT_ALL) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
382 /* Lights are not part of the changed / set structure */
383 for(j = 0; j < LIGHTMAP_SIZE; j++) {
384 struct list *e;
385 LIST_FOR_EACH(e, &object->lightMap[j]) {
386 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
387 light->changed = TRUE;
388 light->enabledChanged = TRUE;
391 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
392 object->contained_render_states[j - 1] = j;
394 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
397 object->contained_transform_states[j - 1] = j;
399 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
400 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
401 object->contained_vs_consts_f[j] = j;
403 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_vs_consts_i[j] = j;
407 object->num_contained_vs_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_vs_consts_b[j] = j;
411 object->num_contained_vs_consts_b = MAX_CONST_B;
412 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
413 object->contained_ps_consts_f[j] = j;
415 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
416 for(j = 0; j < MAX_CONST_I; j++) {
417 object->contained_ps_consts_i[j] = j;
419 object->num_contained_ps_consts_i = MAX_CONST_I;
420 for(j = 0; j < MAX_CONST_B; j++) {
421 object->contained_ps_consts_b[j] = j;
423 object->num_contained_ps_consts_b = MAX_CONST_B;
424 for(i = 0; i < MAX_TEXTURES; i++) {
425 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
426 object->contained_tss_states[object->num_contained_tss_states].stage = i;
427 object->contained_tss_states[object->num_contained_tss_states].state = j;
428 object->num_contained_tss_states++;
431 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
432 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
433 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
434 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
435 object->num_contained_sampler_states++;
439 for(i = 0; i < MAX_STREAMS; i++) {
440 if(object->streamSource[i]) {
441 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
444 if(object->pIndexData) {
445 IWineD3DIndexBuffer_AddRef(object->pIndexData);
447 if(object->vertexShader) {
448 IWineD3DVertexShader_AddRef(object->vertexShader);
450 if(object->pixelShader) {
451 IWineD3DPixelShader_AddRef(object->pixelShader);
454 } else if (Type == WINED3DSBT_PIXELSTATE) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
459 object->changed.pixelShader = TRUE;
461 /* Pixel Shader Constants */
462 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
463 object->contained_ps_consts_f[i] = i;
464 object->changed.pixelShaderConstantsF[i] = TRUE;
466 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
467 for (i = 0; i < MAX_CONST_B; ++i) {
468 object->contained_ps_consts_b[i] = i;
469 object->changed.pixelShaderConstantsB[i] = TRUE;
471 object->num_contained_ps_consts_b = MAX_CONST_B;
472 for (i = 0; i < MAX_CONST_I; ++i) {
473 object->contained_ps_consts_i[i] = i;
474 object->changed.pixelShaderConstantsI[i] = TRUE;
476 object->num_contained_ps_consts_i = MAX_CONST_I;
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
479 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
480 object->contained_render_states[i] = SavedPixelStates_R[i];
482 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
483 for (j = 0; j < MAX_TEXTURES; j++) {
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
485 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
486 object->contained_tss_states[object->num_contained_tss_states].stage = j;
487 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
488 object->num_contained_tss_states++;
491 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
492 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
493 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
494 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
495 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
496 object->num_contained_sampler_states++;
499 if(object->pixelShader) {
500 IWineD3DPixelShader_AddRef(object->pixelShader);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i = 0; i < MAX_STREAMS; i++) {
507 object->streamSource[i] = NULL;
509 object->pIndexData = NULL;
510 object->vertexShader = NULL;
512 } else if (Type == WINED3DSBT_VERTEXSTATE) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
517 object->changed.vertexShader = TRUE;
519 /* Vertex Shader Constants */
520 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
521 object->changed.vertexShaderConstantsF[i] = TRUE;
522 object->contained_vs_consts_f[i] = i;
524 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
525 for (i = 0; i < MAX_CONST_B; ++i) {
526 object->changed.vertexShaderConstantsB[i] = TRUE;
527 object->contained_vs_consts_b[i] = i;
529 object->num_contained_vs_consts_b = MAX_CONST_B;
530 for (i = 0; i < MAX_CONST_I; ++i) {
531 object->changed.vertexShaderConstantsI[i] = TRUE;
532 object->contained_vs_consts_i[i] = i;
534 object->num_contained_vs_consts_i = MAX_CONST_I;
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
536 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 object->contained_render_states[i] = SavedVertexStates_R[i];
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
545 object->num_contained_tss_states++;
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
551 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
552 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
553 object->num_contained_sampler_states++;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
558 struct list *e;
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 for(i = 0; i < MAX_STREAMS; i++) {
567 if(object->streamSource[i]) {
568 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
571 if(object->vertexShader) {
572 IWineD3DVertexShader_AddRef(object->vertexShader);
574 object->pIndexData = NULL;
575 object->pixelShader = NULL;
576 } else {
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
581 return WINED3D_OK;
584 /* ************************************
585 MSDN:
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
588 Discard
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
593 ******************************** */
595 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size = 1;
599 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
600 TRACE("(%p) Create surface\n",This);
602 /** FIXME: Check ranges on the inputs are valid
603 * MSDN
604 * MultisampleQuality
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
609 * must all match.
610 *******************************/
614 * TODO: Discard MSDN
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality > 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
626 MultisampleQuality=0;
629 /** FIXME: Check that the format is supported
630 * by the device.
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
635 * space!
636 *********************************/
637 if (WINED3DFMT_UNKNOWN == Format) {
638 Size = 0;
639 } else if (Format == WINED3DFMT_DXT1) {
640 /* DXT1 is half byte per pixel */
641 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
643 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
644 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
645 Format == WINED3DFMT_ATI2N) {
646 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
647 } else {
648 /* The pitch is a multiple of 4 bytes */
649 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
650 Size *= Height;
653 /** Create and initialise the surface resource **/
654 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
655 /* "Standalone" surface */
656 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
658 object->currentDesc.Width = Width;
659 object->currentDesc.Height = Height;
660 object->currentDesc.MultiSampleType = MultiSample;
661 object->currentDesc.MultiSampleQuality = MultisampleQuality;
662 object->glDescription.level = Level;
664 /* Flags */
665 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
666 object->Flags |= Discard ? SFLAG_DISCARD : 0;
667 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
668 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
671 if (WINED3DFMT_UNKNOWN != Format) {
672 object->bytesPerPixel = tableEntry->bpp;
673 } else {
674 object->bytesPerPixel = 0;
677 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
679 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
681 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
682 * this function is too deep to need to care about things like this.
683 * Levels need to be checked too, and possibly Type since they all affect what can be done.
684 * ****************************************/
685 switch(Pool) {
686 case WINED3DPOOL_SCRATCH:
687 if(!Lockable)
688 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
689 "which are mutually exclusive, setting lockable to TRUE\n");
690 Lockable = TRUE;
691 break;
692 case WINED3DPOOL_SYSTEMMEM:
693 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
694 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
695 case WINED3DPOOL_MANAGED:
696 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
697 "Usage of DYNAMIC which are mutually exclusive, not doing "
698 "anything just telling you.\n");
699 break;
700 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
701 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
702 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
703 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
704 break;
705 default:
706 FIXME("(%p) Unknown pool %d\n", This, Pool);
707 break;
710 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
711 FIXME("Trying to create a render target that isn't in the default pool\n");
714 /* mark the texture as dirty so that it gets loaded first time around*/
715 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
716 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
717 This, Width, Height, Format, debug_d3dformat(Format),
718 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
720 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
721 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
722 This->ddraw_primary = (IWineD3DSurface *) object;
724 /* Look at the implementation and set the correct Vtable */
725 switch(Impl) {
726 case SURFACE_OPENGL:
727 /* Check if a 3D adapter is available when creating gl surfaces */
728 if(!This->adapter) {
729 ERR("OpenGL surfaces are not available without opengl\n");
730 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
731 HeapFree(GetProcessHeap(), 0, object);
732 return WINED3DERR_NOTAVAILABLE;
734 break;
736 case SURFACE_GDI:
737 object->lpVtbl = &IWineGDISurface_Vtbl;
738 break;
740 default:
741 /* To be sure to catch this */
742 ERR("Unknown requested surface implementation %d!\n", Impl);
743 IWineD3DSurface_Release((IWineD3DSurface *) object);
744 return WINED3DERR_INVALIDCALL;
747 list_init(&object->renderbuffers);
749 /* Call the private setup routine */
750 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
754 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
755 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
756 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
757 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
760 IWineD3DTextureImpl *object;
761 unsigned int i;
762 UINT tmpW;
763 UINT tmpH;
764 HRESULT hr;
765 unsigned int pow2Width;
766 unsigned int pow2Height;
767 const GlPixelFormatDesc *glDesc;
768 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
770 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
771 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
772 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
774 /* TODO: It should only be possible to create textures for formats
775 that are reported as supported */
776 if (WINED3DFMT_UNKNOWN >= Format) {
777 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
778 return WINED3DERR_INVALIDCALL;
781 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
782 D3DINITIALIZEBASETEXTURE(object->baseTexture);
783 object->width = Width;
784 object->height = Height;
786 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
787 object->baseTexture.minMipLookup = &minMipLookup;
788 object->baseTexture.magLookup = &magLookup;
789 } else {
790 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
791 object->baseTexture.magLookup = &magLookup_noFilter;
794 /** Non-power2 support **/
795 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
796 pow2Width = Width;
797 pow2Height = Height;
798 } else {
799 /* Find the nearest pow2 match */
800 pow2Width = pow2Height = 1;
801 while (pow2Width < Width) pow2Width <<= 1;
802 while (pow2Height < Height) pow2Height <<= 1;
804 if(pow2Width != Width || pow2Height != Height) {
805 if(Levels > 1) {
806 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
807 HeapFree(GetProcessHeap(), 0, object);
808 *ppTexture = NULL;
809 return WINED3DERR_INVALIDCALL;
810 } else {
811 Levels = 1;
816 /** FIXME: add support for real non-power-two if it's provided by the video card **/
817 /* Precalculated scaling for 'faked' non power of two texture coords.
818 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
819 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
820 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
822 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
823 object->baseTexture.pow2Matrix[0] = 1.0;
824 object->baseTexture.pow2Matrix[5] = 1.0;
825 object->baseTexture.pow2Matrix[10] = 1.0;
826 object->baseTexture.pow2Matrix[15] = 1.0;
827 object->target = GL_TEXTURE_2D;
828 object->cond_np2 = TRUE;
829 pow2Width = Width;
830 pow2Height = Height;
831 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
832 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
833 (Width != pow2Width || Height != pow2Height) &&
834 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
836 object->baseTexture.pow2Matrix[0] = (float)Width;
837 object->baseTexture.pow2Matrix[5] = (float)Height;
838 object->baseTexture.pow2Matrix[10] = 1.0;
839 object->baseTexture.pow2Matrix[15] = 1.0;
840 object->target = GL_TEXTURE_RECTANGLE_ARB;
841 object->cond_np2 = TRUE;
842 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
843 } else {
844 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
845 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
846 object->baseTexture.pow2Matrix[10] = 1.0;
847 object->baseTexture.pow2Matrix[15] = 1.0;
848 object->target = GL_TEXTURE_2D;
849 object->cond_np2 = FALSE;
851 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
853 /* Calculate levels for mip mapping */
854 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
855 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
856 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
857 return WINED3DERR_INVALIDCALL;
859 if(Levels > 1) {
860 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
861 return WINED3DERR_INVALIDCALL;
863 object->baseTexture.levels = 1;
864 } else if (Levels == 0) {
865 TRACE("calculating levels %d\n", object->baseTexture.levels);
866 object->baseTexture.levels++;
867 tmpW = Width;
868 tmpH = Height;
869 while (tmpW > 1 || tmpH > 1) {
870 tmpW = max(1, tmpW >> 1);
871 tmpH = max(1, tmpH >> 1);
872 object->baseTexture.levels++;
874 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
877 /* Generate all the surfaces */
878 tmpW = Width;
879 tmpH = Height;
880 for (i = 0; i < object->baseTexture.levels; i++)
882 /* use the callback to create the texture surface */
883 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
884 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
885 FIXME("Failed to create surface %p\n", object);
886 /* clean up */
887 object->surfaces[i] = NULL;
888 IWineD3DTexture_Release((IWineD3DTexture *)object);
890 *ppTexture = NULL;
891 return hr;
894 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
895 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
896 /* calculate the next mipmap level */
897 tmpW = max(1, tmpW >> 1);
898 tmpH = max(1, tmpH >> 1);
900 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
902 TRACE("(%p) : Created texture %p\n", This, object);
903 return WINED3D_OK;
906 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
907 UINT Width, UINT Height, UINT Depth,
908 UINT Levels, DWORD Usage,
909 WINED3DFORMAT Format, WINED3DPOOL Pool,
910 IWineD3DVolumeTexture **ppVolumeTexture,
911 HANDLE *pSharedHandle, IUnknown *parent,
912 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
915 IWineD3DVolumeTextureImpl *object;
916 unsigned int i;
917 UINT tmpW;
918 UINT tmpH;
919 UINT tmpD;
920 const GlPixelFormatDesc *glDesc;
922 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
924 /* TODO: It should only be possible to create textures for formats
925 that are reported as supported */
926 if (WINED3DFMT_UNKNOWN >= Format) {
927 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
928 return WINED3DERR_INVALIDCALL;
930 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
931 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
932 return WINED3DERR_INVALIDCALL;
935 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
936 D3DINITIALIZEBASETEXTURE(object->baseTexture);
938 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
939 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
941 object->width = Width;
942 object->height = Height;
943 object->depth = Depth;
945 /* Is NP2 support for volumes needed? */
946 object->baseTexture.pow2Matrix[ 0] = 1.0;
947 object->baseTexture.pow2Matrix[ 5] = 1.0;
948 object->baseTexture.pow2Matrix[10] = 1.0;
949 object->baseTexture.pow2Matrix[15] = 1.0;
951 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
952 object->baseTexture.minMipLookup = &minMipLookup;
953 object->baseTexture.magLookup = &magLookup;
954 } else {
955 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
956 object->baseTexture.magLookup = &magLookup_noFilter;
959 /* Calculate levels for mip mapping */
960 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
961 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
962 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
963 return WINED3DERR_INVALIDCALL;
965 if(Levels > 1) {
966 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
967 return WINED3DERR_INVALIDCALL;
969 Levels = 1;
970 } else if (Levels == 0) {
971 object->baseTexture.levels++;
972 tmpW = Width;
973 tmpH = Height;
974 tmpD = Depth;
975 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
976 tmpW = max(1, tmpW >> 1);
977 tmpH = max(1, tmpH >> 1);
978 tmpD = max(1, tmpD >> 1);
979 object->baseTexture.levels++;
981 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
984 /* Generate all the surfaces */
985 tmpW = Width;
986 tmpH = Height;
987 tmpD = Depth;
989 for (i = 0; i < object->baseTexture.levels; i++)
991 HRESULT hr;
992 /* Create the volume */
993 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
994 &object->volumes[i], pSharedHandle);
996 if(FAILED(hr)) {
997 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
998 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
999 *ppVolumeTexture = NULL;
1000 return hr;
1003 /* Set its container to this object */
1004 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1006 /* calculate the next mipmap level */
1007 tmpW = max(1, tmpW >> 1);
1008 tmpH = max(1, tmpH >> 1);
1009 tmpD = max(1, tmpD >> 1);
1011 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1013 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1014 TRACE("(%p) : Created volume texture %p\n", This, object);
1015 return WINED3D_OK;
1018 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1019 UINT Width, UINT Height, UINT Depth,
1020 DWORD Usage,
1021 WINED3DFORMAT Format, WINED3DPOOL Pool,
1022 IWineD3DVolume** ppVolume,
1023 HANDLE* pSharedHandle, IUnknown *parent) {
1025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1026 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1027 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1029 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1030 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1031 return WINED3DERR_INVALIDCALL;
1034 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1036 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1037 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1039 object->currentDesc.Width = Width;
1040 object->currentDesc.Height = Height;
1041 object->currentDesc.Depth = Depth;
1042 object->bytesPerPixel = formatDesc->bpp;
1044 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1045 object->lockable = TRUE;
1046 object->locked = FALSE;
1047 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1048 object->dirty = TRUE;
1050 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1053 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1054 UINT Levels, DWORD Usage,
1055 WINED3DFORMAT Format, WINED3DPOOL Pool,
1056 IWineD3DCubeTexture **ppCubeTexture,
1057 HANDLE *pSharedHandle, IUnknown *parent,
1058 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1061 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1062 unsigned int i, j;
1063 UINT tmpW;
1064 HRESULT hr;
1065 unsigned int pow2EdgeLength = EdgeLength;
1066 const GlPixelFormatDesc *glDesc;
1067 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1069 /* TODO: It should only be possible to create textures for formats
1070 that are reported as supported */
1071 if (WINED3DFMT_UNKNOWN >= Format) {
1072 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1073 return WINED3DERR_INVALIDCALL;
1076 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1077 WARN("(%p) : Tried to create not supported cube texture\n", This);
1078 return WINED3DERR_INVALIDCALL;
1081 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1082 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1084 TRACE("(%p) Create Cube Texture\n", This);
1086 /** Non-power2 support **/
1088 /* Find the nearest pow2 match */
1089 pow2EdgeLength = 1;
1090 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1092 object->edgeLength = EdgeLength;
1093 /* TODO: support for native non-power 2 */
1094 /* Precalculated scaling for 'faked' non power of two texture coords */
1095 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1096 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 object->baseTexture.pow2Matrix[15] = 1.0;
1100 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1101 object->baseTexture.minMipLookup = &minMipLookup;
1102 object->baseTexture.magLookup = &magLookup;
1103 } else {
1104 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1105 object->baseTexture.magLookup = &magLookup_noFilter;
1108 /* Calculate levels for mip mapping */
1109 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object);
1113 *ppCubeTexture = NULL;
1115 return WINED3DERR_INVALIDCALL;
1117 if(Levels > 1) {
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object);
1120 *ppCubeTexture = NULL;
1122 return WINED3DERR_INVALIDCALL;
1124 Levels = 1;
1125 } else if (Levels == 0) {
1126 object->baseTexture.levels++;
1127 tmpW = EdgeLength;
1128 while (tmpW > 1) {
1129 tmpW = max(1, tmpW >> 1);
1130 object->baseTexture.levels++;
1132 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1135 /* Generate all the surfaces */
1136 tmpW = EdgeLength;
1137 for (i = 0; i < object->baseTexture.levels; i++) {
1139 /* Create the 6 faces */
1140 for (j = 0; j < 6; j++) {
1142 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1143 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1145 if(hr!= WINED3D_OK) {
1146 /* clean up */
1147 int k;
1148 int l;
1149 for (l = 0; l < j; l++) {
1150 IWineD3DSurface_Release(object->surfaces[l][i]);
1152 for (k = 0; k < i; k++) {
1153 for (l = 0; l < 6; l++) {
1154 IWineD3DSurface_Release(object->surfaces[l][k]);
1158 FIXME("(%p) Failed to create surface\n",object);
1159 HeapFree(GetProcessHeap(),0,object);
1160 *ppCubeTexture = NULL;
1161 return hr;
1163 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1164 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1166 tmpW = max(1, tmpW >> 1);
1168 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1170 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1171 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1172 return WINED3D_OK;
1175 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1178 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1179 const IWineD3DQueryVtbl *vtable;
1181 /* Just a check to see if we support this type of query */
1182 switch(Type) {
1183 case WINED3DQUERYTYPE_OCCLUSION:
1184 TRACE("(%p) occlusion query\n", This);
1185 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1186 hr = WINED3D_OK;
1187 else
1188 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1190 vtable = &IWineD3DOcclusionQuery_Vtbl;
1191 break;
1193 case WINED3DQUERYTYPE_EVENT:
1194 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1195 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1196 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1198 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1200 vtable = &IWineD3DEventQuery_Vtbl;
1201 hr = WINED3D_OK;
1202 break;
1204 case WINED3DQUERYTYPE_VCACHE:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1206 case WINED3DQUERYTYPE_VERTEXSTATS:
1207 case WINED3DQUERYTYPE_TIMESTAMP:
1208 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1209 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1210 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1211 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1212 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1213 case WINED3DQUERYTYPE_PIXELTIMINGS:
1214 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1215 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1216 default:
1217 /* Use the base Query vtable until we have a special one for each query */
1218 vtable = &IWineD3DQuery_Vtbl;
1219 FIXME("(%p) Unhandled query type %d\n", This, Type);
1221 if(NULL == ppQuery || hr != WINED3D_OK) {
1222 return hr;
1225 D3DCREATEOBJECTINSTANCE(object, Query)
1226 object->lpVtbl = vtable;
1227 object->type = Type;
1228 object->state = QUERY_CREATED;
1229 /* allocated the 'extended' data based on the type of query requested */
1230 switch(Type){
1231 case WINED3DQUERYTYPE_OCCLUSION:
1232 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1233 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1235 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1236 TRACE("(%p) Allocating data for an occlusion query\n", This);
1237 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1238 break;
1240 case WINED3DQUERYTYPE_EVENT:
1241 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1242 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1244 if(GL_SUPPORT(APPLE_FENCE)) {
1245 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesAPPLE");
1247 } else if(GL_SUPPORT(NV_FENCE)) {
1248 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1249 checkGLcall("glGenFencesNV");
1251 break;
1253 case WINED3DQUERYTYPE_VCACHE:
1254 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1255 case WINED3DQUERYTYPE_VERTEXSTATS:
1256 case WINED3DQUERYTYPE_TIMESTAMP:
1257 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1258 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1259 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1260 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1261 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1262 case WINED3DQUERYTYPE_PIXELTIMINGS:
1263 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1264 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1265 default:
1266 object->extendedData = 0;
1267 FIXME("(%p) Unhandled query type %d\n",This , Type);
1269 TRACE("(%p) : Created Query %p\n", This, object);
1270 return WINED3D_OK;
1273 /*****************************************************************************
1274 * IWineD3DDeviceImpl_SetupFullscreenWindow
1276 * Helper function that modifies a HWND's Style and ExStyle for proper
1277 * fullscreen use.
1279 * Params:
1280 * iface: Pointer to the IWineD3DDevice interface
1281 * window: Window to setup
1283 *****************************************************************************/
1284 static LONG fullscreen_style(LONG orig_style) {
1285 LONG style = orig_style;
1286 style &= ~WS_CAPTION;
1287 style &= ~WS_THICKFRAME;
1289 /* Make sure the window is managed, otherwise we won't get keyboard input */
1290 style |= WS_POPUP | WS_SYSMENU;
1292 return style;
1295 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1296 LONG exStyle = orig_exStyle;
1298 /* Filter out window decorations */
1299 exStyle &= ~WS_EX_WINDOWEDGE;
1300 exStyle &= ~WS_EX_CLIENTEDGE;
1302 return exStyle;
1305 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1308 LONG style, exStyle;
1309 /* Don't do anything if an original style is stored.
1310 * That shouldn't happen
1312 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1313 if (This->style || This->exStyle) {
1314 ERR("(%p): Want to change the window parameters of HWND %p, but "
1315 "another style is stored for restoration afterwards\n", This, window);
1318 /* Get the parameters and save them */
1319 style = GetWindowLongW(window, GWL_STYLE);
1320 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1321 This->style = style;
1322 This->exStyle = exStyle;
1324 style = fullscreen_style(style);
1325 exStyle = fullscreen_exStyle(exStyle);
1327 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1328 This->style, This->exStyle, style, exStyle);
1330 SetWindowLongW(window, GWL_STYLE, style);
1331 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1333 /* Inform the window about the update. */
1334 SetWindowPos(window, HWND_TOP, 0, 0,
1335 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1336 ShowWindow(window, SW_NORMAL);
1339 /*****************************************************************************
1340 * IWineD3DDeviceImpl_RestoreWindow
1342 * Helper function that restores a windows' properties when taking it out
1343 * of fullscreen mode
1345 * Params:
1346 * iface: Pointer to the IWineD3DDevice interface
1347 * window: Window to setup
1349 *****************************************************************************/
1350 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1352 LONG style, exStyle;
1354 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1355 * switch, do nothing
1357 if (!This->style && !This->exStyle) return;
1359 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1360 This, window, This->style, This->exStyle);
1362 style = GetWindowLongW(window, GWL_STYLE);
1363 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1365 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1366 * Some applications change it before calling Reset() when switching between windowed and
1367 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1369 if(style == fullscreen_style(This->style) &&
1370 exStyle == fullscreen_style(This->exStyle)) {
1371 SetWindowLongW(window, GWL_STYLE, This->style);
1372 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1375 /* Delete the old values */
1376 This->style = 0;
1377 This->exStyle = 0;
1379 /* Inform the window about the update */
1380 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1381 0, 0, 0, 0, /* Pos, Size, ignored */
1382 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1385 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1386 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1387 IUnknown* parent,
1388 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1389 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1392 HDC hDc;
1393 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1394 HRESULT hr = WINED3D_OK;
1395 IUnknown *bufferParent;
1396 BOOL displaymode_set = FALSE;
1397 WINED3DDISPLAYMODE Mode;
1398 const StaticPixelFormatDesc *formatDesc;
1400 TRACE("(%p) : Created Additional Swap Chain\n", This);
1402 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1403 * does a device hold a reference to a swap chain giving them a lifetime of the device
1404 * or does the swap chain notify the device of its destruction.
1405 *******************************/
1407 /* Check the params */
1408 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1409 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1410 return WINED3DERR_INVALIDCALL;
1411 } else if (pPresentationParameters->BackBufferCount > 1) {
1412 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");
1415 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1417 /*********************
1418 * Lookup the window Handle and the relating X window handle
1419 ********************/
1421 /* Setup hwnd we are using, plus which display this equates to */
1422 object->win_handle = pPresentationParameters->hDeviceWindow;
1423 if (!object->win_handle) {
1424 object->win_handle = This->createParms.hFocusWindow;
1426 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1428 hDc = GetDC(object->win_handle);
1429 TRACE("Using hDc %p\n", hDc);
1431 if (NULL == hDc) {
1432 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1433 return WINED3DERR_NOTAVAILABLE;
1436 /* Get info on the current display setup */
1437 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1438 object->orig_width = Mode.Width;
1439 object->orig_height = Mode.Height;
1440 object->orig_fmt = Mode.Format;
1441 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1443 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1444 * then the corresponding dimension of the client area of the hDeviceWindow
1445 * (or the focus window, if hDeviceWindow is NULL) is taken.
1446 **********************/
1448 if (pPresentationParameters->Windowed &&
1449 ((pPresentationParameters->BackBufferWidth == 0) ||
1450 (pPresentationParameters->BackBufferHeight == 0) ||
1451 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1453 RECT Rect;
1454 GetClientRect(object->win_handle, &Rect);
1456 if (pPresentationParameters->BackBufferWidth == 0) {
1457 pPresentationParameters->BackBufferWidth = Rect.right;
1458 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1460 if (pPresentationParameters->BackBufferHeight == 0) {
1461 pPresentationParameters->BackBufferHeight = Rect.bottom;
1462 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1464 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1465 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1466 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1470 /* Put the correct figures in the presentation parameters */
1471 TRACE("Copying across presentation parameters\n");
1472 object->presentParms = *pPresentationParameters;
1474 TRACE("calling rendertarget CB\n");
1475 hr = D3DCB_CreateRenderTarget(This->parent,
1476 parent,
1477 object->presentParms.BackBufferWidth,
1478 object->presentParms.BackBufferHeight,
1479 object->presentParms.BackBufferFormat,
1480 object->presentParms.MultiSampleType,
1481 object->presentParms.MultiSampleQuality,
1482 TRUE /* Lockable */,
1483 &object->frontBuffer,
1484 NULL /* pShared (always null)*/);
1485 if (object->frontBuffer != NULL) {
1486 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1487 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1488 } else {
1489 ERR("Failed to create the front buffer\n");
1490 goto error;
1493 /*********************
1494 * Windowed / Fullscreen
1495 *******************/
1498 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1499 * so we should really check to see if there is a fullscreen swapchain already
1500 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1501 **************************************/
1503 if (!pPresentationParameters->Windowed) {
1504 WINED3DDISPLAYMODE mode;
1507 /* Change the display settings */
1508 mode.Width = pPresentationParameters->BackBufferWidth;
1509 mode.Height = pPresentationParameters->BackBufferHeight;
1510 mode.Format = pPresentationParameters->BackBufferFormat;
1511 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1513 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1514 displaymode_set = TRUE;
1515 IWineD3DDevice_SetFullscreen(iface, TRUE);
1519 * Create an opengl context for the display visual
1520 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1521 * use different properties after that point in time. FIXME: How to handle when requested format
1522 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1523 * it chooses is identical to the one already being used!
1524 **********************************/
1525 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1527 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1528 if(!object->context)
1529 return E_OUTOFMEMORY;
1530 object->num_contexts = 1;
1532 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1533 if (!object->context[0]) {
1534 ERR("Failed to create a new context\n");
1535 hr = WINED3DERR_NOTAVAILABLE;
1536 goto error;
1537 } else {
1538 TRACE("Context created (HWND=%p, glContext=%p)\n",
1539 object->win_handle, object->context[0]->glCtx);
1542 /*********************
1543 * Create the back, front and stencil buffers
1544 *******************/
1545 if(object->presentParms.BackBufferCount > 0) {
1546 int i;
1548 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1549 if(!object->backBuffer) {
1550 ERR("Out of memory\n");
1551 hr = E_OUTOFMEMORY;
1552 goto error;
1555 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1556 TRACE("calling rendertarget CB\n");
1557 hr = D3DCB_CreateRenderTarget(This->parent,
1558 parent,
1559 object->presentParms.BackBufferWidth,
1560 object->presentParms.BackBufferHeight,
1561 object->presentParms.BackBufferFormat,
1562 object->presentParms.MultiSampleType,
1563 object->presentParms.MultiSampleQuality,
1564 TRUE /* Lockable */,
1565 &object->backBuffer[i],
1566 NULL /* pShared (always null)*/);
1567 if(hr == WINED3D_OK && object->backBuffer[i]) {
1568 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1569 } else {
1570 ERR("Cannot create new back buffer\n");
1571 goto error;
1573 ENTER_GL();
1574 glDrawBuffer(GL_BACK);
1575 checkGLcall("glDrawBuffer(GL_BACK)");
1576 LEAVE_GL();
1578 } else {
1579 object->backBuffer = NULL;
1581 /* Single buffering - draw to front buffer */
1582 ENTER_GL();
1583 glDrawBuffer(GL_FRONT);
1584 checkGLcall("glDrawBuffer(GL_FRONT)");
1585 LEAVE_GL();
1588 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1589 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1590 TRACE("Creating depth stencil buffer\n");
1591 if (This->auto_depth_stencil_buffer == NULL ) {
1592 hr = D3DCB_CreateDepthStencil(This->parent,
1593 parent,
1594 object->presentParms.BackBufferWidth,
1595 object->presentParms.BackBufferHeight,
1596 object->presentParms.AutoDepthStencilFormat,
1597 object->presentParms.MultiSampleType,
1598 object->presentParms.MultiSampleQuality,
1599 FALSE /* FIXME: Discard */,
1600 &This->auto_depth_stencil_buffer,
1601 NULL /* pShared (always null)*/ );
1602 if (This->auto_depth_stencil_buffer != NULL)
1603 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1606 /** TODO: A check on width, height and multisample types
1607 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1608 ****************************/
1609 object->wantsDepthStencilBuffer = TRUE;
1610 } else {
1611 object->wantsDepthStencilBuffer = FALSE;
1614 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1616 TRACE("Created swapchain %p\n", object);
1617 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1618 return WINED3D_OK;
1620 error:
1621 if (displaymode_set) {
1622 DEVMODEW devmode;
1623 RECT clip_rc;
1625 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1626 ClipCursor(NULL);
1628 /* Change the display settings */
1629 memset(&devmode, 0, sizeof(devmode));
1630 devmode.dmSize = sizeof(devmode);
1631 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1632 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1633 devmode.dmPelsWidth = object->orig_width;
1634 devmode.dmPelsHeight = object->orig_height;
1635 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1638 if (object->backBuffer) {
1639 int i;
1640 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1641 if(object->backBuffer[i]) {
1642 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1643 IUnknown_Release(bufferParent); /* once for the get parent */
1644 if (IUnknown_Release(bufferParent) > 0) {
1645 FIXME("(%p) Something's still holding the back buffer\n",This);
1649 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1650 object->backBuffer = NULL;
1652 if(object->context[0])
1653 DestroyContext(This, object->context[0]);
1654 if(object->frontBuffer) {
1655 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1656 IUnknown_Release(bufferParent); /* once for the get parent */
1657 if (IUnknown_Release(bufferParent) > 0) {
1658 FIXME("(%p) Something's still holding the front buffer\n",This);
1661 HeapFree(GetProcessHeap(), 0, object);
1662 return hr;
1665 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1666 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1668 TRACE("(%p)\n", This);
1670 return This->NumberOfSwapChains;
1673 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1675 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1677 if(iSwapChain < This->NumberOfSwapChains) {
1678 *pSwapChain = This->swapchains[iSwapChain];
1679 IWineD3DSwapChain_AddRef(*pSwapChain);
1680 TRACE("(%p) returning %p\n", This, *pSwapChain);
1681 return WINED3D_OK;
1682 } else {
1683 TRACE("Swapchain out of range\n");
1684 *pSwapChain = NULL;
1685 return WINED3DERR_INVALIDCALL;
1689 /*****
1690 * Vertex Declaration
1691 *****/
1692 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1693 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 IWineD3DVertexDeclarationImpl *object = NULL;
1696 HRESULT hr = WINED3D_OK;
1698 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1699 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1701 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1703 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1704 if(FAILED(hr)) {
1705 *ppVertexDeclaration = NULL;
1706 HeapFree(GetProcessHeap(), 0, object);
1709 return hr;
1712 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1713 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1715 unsigned int idx, idx2;
1716 unsigned int offset;
1717 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1718 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1719 BOOL has_blend_idx = has_blend &&
1720 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1721 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1722 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1723 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1724 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1725 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1726 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1728 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1729 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1731 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1732 WINED3DVERTEXELEMENT *elements = NULL;
1734 unsigned int size;
1735 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1736 if (has_blend_idx) num_blends--;
1738 /* Compute declaration size */
1739 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1740 has_psize + has_diffuse + has_specular + num_textures + 1;
1742 /* convert the declaration */
1743 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1744 if (!elements)
1745 return 0;
1747 elements[size-1] = end_element;
1748 idx = 0;
1749 if (has_pos) {
1750 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1752 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1754 else {
1755 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1756 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1758 elements[idx].UsageIndex = 0;
1759 idx++;
1761 if (has_blend && (num_blends > 0)) {
1762 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1763 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1764 else
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1766 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1767 elements[idx].UsageIndex = 0;
1768 idx++;
1770 if (has_blend_idx) {
1771 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1772 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1773 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1774 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1775 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1776 else
1777 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1778 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1779 elements[idx].UsageIndex = 0;
1780 idx++;
1782 if (has_normal) {
1783 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1784 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1785 elements[idx].UsageIndex = 0;
1786 idx++;
1788 if (has_psize) {
1789 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1790 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1791 elements[idx].UsageIndex = 0;
1792 idx++;
1794 if (has_diffuse) {
1795 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1796 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1797 elements[idx].UsageIndex = 0;
1798 idx++;
1800 if (has_specular) {
1801 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1802 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1803 elements[idx].UsageIndex = 1;
1804 idx++;
1806 for (idx2 = 0; idx2 < num_textures; idx2++) {
1807 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1808 switch (numcoords) {
1809 case WINED3DFVF_TEXTUREFORMAT1:
1810 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1811 break;
1812 case WINED3DFVF_TEXTUREFORMAT2:
1813 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1814 break;
1815 case WINED3DFVF_TEXTUREFORMAT3:
1816 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1817 break;
1818 case WINED3DFVF_TEXTUREFORMAT4:
1819 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1820 break;
1822 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1823 elements[idx].UsageIndex = idx2;
1824 idx++;
1827 /* Now compute offsets, and initialize the rest of the fields */
1828 for (idx = 0, offset = 0; idx < size-1; idx++) {
1829 elements[idx].Stream = 0;
1830 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1831 elements[idx].Offset = offset;
1832 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1835 *ppVertexElements = elements;
1836 return size;
1839 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1840 WINED3DVERTEXELEMENT* elements = NULL;
1841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1842 unsigned int size;
1843 DWORD hr;
1845 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1846 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1848 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1849 HeapFree(GetProcessHeap(), 0, elements);
1850 if (hr != S_OK) return hr;
1852 return WINED3D_OK;
1855 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1857 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1858 HRESULT hr = WINED3D_OK;
1859 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1860 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1862 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1864 if (vertex_declaration) {
1865 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1868 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1870 if (WINED3D_OK != hr) {
1871 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1872 IWineD3DVertexShader_Release(*ppVertexShader);
1873 return WINED3DERR_INVALIDCALL;
1875 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1877 return WINED3D_OK;
1880 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1882 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1883 HRESULT hr = WINED3D_OK;
1885 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1886 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1887 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1888 if (WINED3D_OK == hr) {
1889 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1890 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1891 } else {
1892 WARN("(%p) : Failed to create pixel shader\n", This);
1895 return hr;
1898 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1900 IWineD3DPaletteImpl *object;
1901 HRESULT hr;
1902 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1904 /* Create the new object */
1905 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1906 if(!object) {
1907 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1908 return E_OUTOFMEMORY;
1911 object->lpVtbl = &IWineD3DPalette_Vtbl;
1912 object->ref = 1;
1913 object->Flags = Flags;
1914 object->parent = Parent;
1915 object->wineD3DDevice = This;
1916 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1918 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1920 if(!object->hpal) {
1921 HeapFree( GetProcessHeap(), 0, object);
1922 return E_OUTOFMEMORY;
1925 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1926 if(FAILED(hr)) {
1927 IWineD3DPalette_Release((IWineD3DPalette *) object);
1928 return hr;
1931 *Palette = (IWineD3DPalette *) object;
1933 return WINED3D_OK;
1936 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1937 HBITMAP hbm;
1938 BITMAP bm;
1939 HRESULT hr;
1940 HDC dcb = NULL, dcs = NULL;
1941 WINEDDCOLORKEY colorkey;
1943 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1944 if(hbm)
1946 GetObjectA(hbm, sizeof(BITMAP), &bm);
1947 dcb = CreateCompatibleDC(NULL);
1948 if(!dcb) goto out;
1949 SelectObject(dcb, hbm);
1951 else
1953 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1954 * couldn't be loaded
1956 memset(&bm, 0, sizeof(bm));
1957 bm.bmWidth = 32;
1958 bm.bmHeight = 32;
1961 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1962 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1963 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1964 if(FAILED(hr)) {
1965 ERR("Wine logo requested, but failed to create surface\n");
1966 goto out;
1969 if(dcb) {
1970 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1971 if(FAILED(hr)) goto out;
1972 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1973 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1975 colorkey.dwColorSpaceLowValue = 0;
1976 colorkey.dwColorSpaceHighValue = 0;
1977 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1978 } else {
1979 /* Fill the surface with a white color to show that wined3d is there */
1980 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1983 out:
1984 if(dcb) {
1985 DeleteDC(dcb);
1987 if(hbm) {
1988 DeleteObject(hbm);
1990 return;
1993 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1994 unsigned int i;
1995 /* Under DirectX you can have texture stage operations even if no texture is
1996 bound, whereas opengl will only do texture operations when a valid texture is
1997 bound. We emulate this by creating dummy textures and binding them to each
1998 texture stage, but disable all stages by default. Hence if a stage is enabled
1999 then the default texture will kick in until replaced by a SetTexture call */
2000 ENTER_GL();
2002 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2003 /* The dummy texture does not have client storage backing */
2004 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2005 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2007 for (i = 0; i < GL_LIMITS(textures); i++) {
2008 GLubyte white = 255;
2010 /* Make appropriate texture active */
2011 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2012 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2013 checkGLcall("glActiveTextureARB");
2014 } else if (i > 0) {
2015 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2018 /* Generate an opengl texture name */
2019 glGenTextures(1, &This->dummyTextureName[i]);
2020 checkGLcall("glGenTextures");
2021 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2023 /* Generate a dummy 2d texture (not using 1d because they cause many
2024 * DRI drivers fall back to sw) */
2025 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2026 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2027 checkGLcall("glBindTexture");
2029 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2030 checkGLcall("glTexImage2D");
2032 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2033 /* Reenable because if supported it is enabled by default */
2034 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2035 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2038 LEAVE_GL();
2041 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2043 IWineD3DSwapChainImpl *swapchain = NULL;
2044 HRESULT hr;
2045 DWORD state;
2046 unsigned int i;
2048 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2049 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2050 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2052 /* TODO: Test if OpenGL is compiled in and loaded */
2054 TRACE("(%p) : Creating stateblock\n", This);
2055 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2056 hr = IWineD3DDevice_CreateStateBlock(iface,
2057 WINED3DSBT_INIT,
2058 (IWineD3DStateBlock **)&This->stateBlock,
2059 NULL);
2060 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2061 WARN("Failed to create stateblock\n");
2062 goto err_out;
2064 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2065 This->updateStateBlock = This->stateBlock;
2066 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2068 hr = allocate_shader_constants(This->updateStateBlock);
2069 if (WINED3D_OK != hr) {
2070 goto err_out;
2073 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2074 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2075 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2077 This->NumberOfPalettes = 1;
2078 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2079 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2080 ERR("Out of memory!\n");
2081 goto err_out;
2083 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2084 if(!This->palettes[0]) {
2085 ERR("Out of memory!\n");
2086 goto err_out;
2088 for (i = 0; i < 256; ++i) {
2089 This->palettes[0][i].peRed = 0xFF;
2090 This->palettes[0][i].peGreen = 0xFF;
2091 This->palettes[0][i].peBlue = 0xFF;
2092 This->palettes[0][i].peFlags = 0xFF;
2094 This->currentPalette = 0;
2096 /* Initialize the texture unit mapping to a 1:1 mapping */
2097 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2098 if (state < GL_LIMITS(fragment_samplers)) {
2099 This->texUnitMap[state] = state;
2100 This->rev_tex_unit_map[state] = state;
2101 } else {
2102 This->texUnitMap[state] = -1;
2103 This->rev_tex_unit_map[state] = -1;
2107 /* Setup the implicit swapchain */
2108 TRACE("Creating implicit swapchain\n");
2109 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2110 if (FAILED(hr) || !swapchain) {
2111 WARN("Failed to create implicit swapchain\n");
2112 goto err_out;
2115 This->NumberOfSwapChains = 1;
2116 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2117 if(!This->swapchains) {
2118 ERR("Out of memory!\n");
2119 goto err_out;
2121 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2123 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2124 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2125 This->render_targets[0] = swapchain->backBuffer[0];
2126 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2128 else {
2129 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2130 This->render_targets[0] = swapchain->frontBuffer;
2131 This->lastActiveRenderTarget = swapchain->frontBuffer;
2133 IWineD3DSurface_AddRef(This->render_targets[0]);
2134 This->activeContext = swapchain->context[0];
2135 This->lastThread = GetCurrentThreadId();
2137 /* Depth Stencil support */
2138 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2139 if (NULL != This->stencilBufferTarget) {
2140 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2143 hr = This->shader_backend->shader_alloc_private(iface);
2144 if(FAILED(hr)) {
2145 TRACE("Shader private data couldn't be allocated\n");
2146 goto err_out;
2148 hr = This->frag_pipe->alloc_private(iface);
2149 if(FAILED(hr)) {
2150 TRACE("Fragment pipeline private data couldn't be allocated\n");
2151 goto err_out;
2154 /* Set up some starting GL setup */
2156 /* Setup all the devices defaults */
2157 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2158 create_dummy_textures(This);
2160 ENTER_GL();
2162 #if 0
2163 IWineD3DImpl_CheckGraphicsMemory();
2164 #endif
2166 { /* Set a default viewport */
2167 WINED3DVIEWPORT vp;
2168 vp.X = 0;
2169 vp.Y = 0;
2170 vp.Width = pPresentationParameters->BackBufferWidth;
2171 vp.Height = pPresentationParameters->BackBufferHeight;
2172 vp.MinZ = 0.0f;
2173 vp.MaxZ = 1.0f;
2174 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2177 /* Initialize the current view state */
2178 This->view_ident = 1;
2179 This->contexts[0]->last_was_rhw = 0;
2180 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2181 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2183 switch(wined3d_settings.offscreen_rendering_mode) {
2184 case ORM_FBO:
2185 case ORM_PBUFFER:
2186 This->offscreenBuffer = GL_BACK;
2187 break;
2189 case ORM_BACKBUFFER:
2191 if(This->activeContext->aux_buffers > 0) {
2192 TRACE("Using auxilliary buffer for offscreen rendering\n");
2193 This->offscreenBuffer = GL_AUX0;
2194 } else {
2195 TRACE("Using back buffer for offscreen rendering\n");
2196 This->offscreenBuffer = GL_BACK;
2201 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2202 LEAVE_GL();
2204 /* Clear the screen */
2205 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2206 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2207 0x00, 1.0, 0);
2209 This->d3d_initialized = TRUE;
2211 if(wined3d_settings.logo) {
2212 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2214 This->highest_dirty_ps_const = 0;
2215 This->highest_dirty_vs_const = 0;
2216 return WINED3D_OK;
2218 err_out:
2219 HeapFree(GetProcessHeap(), 0, This->render_targets);
2220 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2221 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2222 HeapFree(GetProcessHeap(), 0, This->swapchains);
2223 This->NumberOfSwapChains = 0;
2224 if(This->palettes) {
2225 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2226 HeapFree(GetProcessHeap(), 0, This->palettes);
2228 This->NumberOfPalettes = 0;
2229 if(swapchain) {
2230 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2232 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2233 if(This->stateBlock) {
2234 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2235 This->stateBlock = NULL;
2237 This->frag_pipe->free_private(iface);
2238 This->shader_backend->shader_free_private(iface);
2239 return hr;
2242 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2244 int sampler;
2245 UINT i;
2246 TRACE("(%p)\n", This);
2248 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2250 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2251 * it was created. Thus make sure a context is active for the glDelete* calls
2253 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2255 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2257 TRACE("Deleting high order patches\n");
2258 for(i = 0; i < PATCHMAP_SIZE; i++) {
2259 struct list *e1, *e2;
2260 struct WineD3DRectPatch *patch;
2261 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2262 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2263 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2267 /* Delete the palette conversion shader if it is around */
2268 if(This->paletteConversionShader) {
2269 ENTER_GL();
2270 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2271 LEAVE_GL();
2272 This->paletteConversionShader = 0;
2275 /* Delete the pbuffer context if there is any */
2276 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2278 /* Delete the mouse cursor texture */
2279 if(This->cursorTexture) {
2280 ENTER_GL();
2281 glDeleteTextures(1, &This->cursorTexture);
2282 LEAVE_GL();
2283 This->cursorTexture = 0;
2286 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2287 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2289 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2290 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2293 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2294 * private data, it might contain opengl pointers
2296 if(This->depth_blt_texture) {
2297 glDeleteTextures(1, &This->depth_blt_texture);
2298 This->depth_blt_texture = 0;
2300 if (This->depth_blt_rb) {
2301 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2302 This->depth_blt_rb = 0;
2303 This->depth_blt_rb_w = 0;
2304 This->depth_blt_rb_h = 0;
2307 /* Release the update stateblock */
2308 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2309 if(This->updateStateBlock != This->stateBlock)
2310 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2312 This->updateStateBlock = NULL;
2314 { /* because were not doing proper internal refcounts releasing the primary state block
2315 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2316 to set this->stateBlock = NULL; first */
2317 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2318 This->stateBlock = NULL;
2320 /* Release the stateblock */
2321 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2322 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2326 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2327 This->frag_pipe->free_private(iface);
2328 This->shader_backend->shader_free_private(iface);
2330 /* Release the buffers (with sanity checks)*/
2331 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2332 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2333 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2334 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2336 This->stencilBufferTarget = NULL;
2338 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2339 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2340 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2342 TRACE("Setting rendertarget to NULL\n");
2343 This->render_targets[0] = NULL;
2345 if (This->auto_depth_stencil_buffer) {
2346 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2347 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2349 This->auto_depth_stencil_buffer = NULL;
2352 for(i=0; i < This->NumberOfSwapChains; i++) {
2353 TRACE("Releasing the implicit swapchain %d\n", i);
2354 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2355 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2359 HeapFree(GetProcessHeap(), 0, This->swapchains);
2360 This->swapchains = NULL;
2361 This->NumberOfSwapChains = 0;
2363 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2364 HeapFree(GetProcessHeap(), 0, This->palettes);
2365 This->palettes = NULL;
2366 This->NumberOfPalettes = 0;
2368 HeapFree(GetProcessHeap(), 0, This->render_targets);
2369 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2370 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2371 This->render_targets = NULL;
2372 This->fbo_color_attachments = NULL;
2373 This->draw_buffers = NULL;
2375 This->d3d_initialized = FALSE;
2376 return WINED3D_OK;
2379 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2381 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2383 /* Setup the window for fullscreen mode */
2384 if(fullscreen && !This->ddraw_fullscreen) {
2385 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2386 } else if(!fullscreen && This->ddraw_fullscreen) {
2387 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2390 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2391 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2392 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2393 * separately.
2395 This->ddraw_fullscreen = fullscreen;
2398 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2399 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2400 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2402 * There is no way to deactivate thread safety once it is enabled.
2404 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2407 /*For now just store the flag(needed in case of ddraw) */
2408 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2410 return;
2413 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2414 DEVMODEW devmode;
2415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2416 LONG ret;
2417 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2418 RECT clip_rc;
2420 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2422 /* Resize the screen even without a window:
2423 * The app could have unset it with SetCooperativeLevel, but not called
2424 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2425 * but we don't have any hwnd
2428 memset(&devmode, 0, sizeof(devmode));
2429 devmode.dmSize = sizeof(devmode);
2430 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2431 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2432 devmode.dmPelsWidth = pMode->Width;
2433 devmode.dmPelsHeight = pMode->Height;
2435 devmode.dmDisplayFrequency = pMode->RefreshRate;
2436 if (pMode->RefreshRate != 0) {
2437 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2440 /* Only change the mode if necessary */
2441 if( (This->ddraw_width == pMode->Width) &&
2442 (This->ddraw_height == pMode->Height) &&
2443 (This->ddraw_format == pMode->Format) &&
2444 (pMode->RefreshRate == 0) ) {
2445 return WINED3D_OK;
2448 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2449 if (ret != DISP_CHANGE_SUCCESSFUL) {
2450 if(devmode.dmDisplayFrequency != 0) {
2451 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2452 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2453 devmode.dmDisplayFrequency = 0;
2454 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2456 if(ret != DISP_CHANGE_SUCCESSFUL) {
2457 return WINED3DERR_NOTAVAILABLE;
2461 /* Store the new values */
2462 This->ddraw_width = pMode->Width;
2463 This->ddraw_height = pMode->Height;
2464 This->ddraw_format = pMode->Format;
2466 /* Only do this with a window of course, and only if we're fullscreened */
2467 if(This->ddraw_window && This->ddraw_fullscreen)
2468 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2470 /* And finally clip mouse to our screen */
2471 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2472 ClipCursor(&clip_rc);
2474 return WINED3D_OK;
2477 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2479 *ppD3D= This->wineD3D;
2480 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2481 IWineD3D_AddRef(*ppD3D);
2482 return WINED3D_OK;
2485 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2488 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2489 (This->adapter->TextureRam/(1024*1024)),
2490 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2491 /* return simulated texture memory left */
2492 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2497 /*****
2498 * Get / Set FVF
2499 *****/
2500 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2503 /* Update the current state block */
2504 This->updateStateBlock->changed.fvf = TRUE;
2506 if(This->updateStateBlock->fvf == fvf) {
2507 TRACE("Application is setting the old fvf over, nothing to do\n");
2508 return WINED3D_OK;
2511 This->updateStateBlock->fvf = fvf;
2512 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2514 return WINED3D_OK;
2518 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2520 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2521 *pfvf = This->stateBlock->fvf;
2522 return WINED3D_OK;
2525 /*****
2526 * Get / Set Stream Source
2527 *****/
2528 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2530 IWineD3DVertexBuffer *oldSrc;
2532 if (StreamNumber >= MAX_STREAMS) {
2533 WARN("Stream out of range %d\n", StreamNumber);
2534 return WINED3DERR_INVALIDCALL;
2535 } else if(OffsetInBytes & 0x3) {
2536 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2537 return WINED3DERR_INVALIDCALL;
2540 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2541 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2543 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2545 if(oldSrc == pStreamData &&
2546 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2547 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2548 TRACE("Application is setting the old values over, nothing to do\n");
2549 return WINED3D_OK;
2552 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2553 if (pStreamData) {
2554 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2555 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2558 /* Handle recording of state blocks */
2559 if (This->isRecordingState) {
2560 TRACE("Recording... not performing anything\n");
2561 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2562 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2563 return WINED3D_OK;
2566 /* Need to do a getParent and pass the references up */
2567 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2568 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2569 so for now, just count internally */
2570 if (pStreamData != NULL) {
2571 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2572 InterlockedIncrement(&vbImpl->bindCount);
2573 IWineD3DVertexBuffer_AddRef(pStreamData);
2575 if (oldSrc != NULL) {
2576 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2577 IWineD3DVertexBuffer_Release(oldSrc);
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2582 return WINED3D_OK;
2585 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2588 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2589 This->stateBlock->streamSource[StreamNumber],
2590 This->stateBlock->streamOffset[StreamNumber],
2591 This->stateBlock->streamStride[StreamNumber]);
2593 if (StreamNumber >= MAX_STREAMS) {
2594 WARN("Stream out of range %d\n", StreamNumber);
2595 return WINED3DERR_INVALIDCALL;
2597 *pStream = This->stateBlock->streamSource[StreamNumber];
2598 *pStride = This->stateBlock->streamStride[StreamNumber];
2599 if (pOffset) {
2600 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2603 if (*pStream != NULL) {
2604 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2606 return WINED3D_OK;
2609 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2611 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2612 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2614 /* Verify input at least in d3d9 this is invalid*/
2615 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2616 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2617 return WINED3DERR_INVALIDCALL;
2619 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2620 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2621 return WINED3DERR_INVALIDCALL;
2623 if( Divider == 0 ){
2624 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2625 return WINED3DERR_INVALIDCALL;
2628 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2629 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2631 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2632 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2634 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2635 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2639 return WINED3D_OK;
2642 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2646 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2648 TRACE("(%p) : returning %d\n", This, *Divider);
2650 return WINED3D_OK;
2653 /*****
2654 * Get / Set & Multiply Transform
2655 *****/
2656 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 /* Most of this routine, comments included copied from ddraw tree initially: */
2660 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2662 /* Handle recording of state blocks */
2663 if (This->isRecordingState) {
2664 TRACE("Recording... not performing anything\n");
2665 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2666 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2667 return WINED3D_OK;
2671 * If the new matrix is the same as the current one,
2672 * we cut off any further processing. this seems to be a reasonable
2673 * optimization because as was noticed, some apps (warcraft3 for example)
2674 * tend towards setting the same matrix repeatedly for some reason.
2676 * From here on we assume that the new matrix is different, wherever it matters.
2678 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2679 TRACE("The app is setting the same matrix over again\n");
2680 return WINED3D_OK;
2681 } else {
2682 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2686 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2687 where ViewMat = Camera space, WorldMat = world space.
2689 In OpenGL, camera and world space is combined into GL_MODELVIEW
2690 matrix. The Projection matrix stay projection matrix.
2693 /* Capture the times we can just ignore the change for now */
2694 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2695 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2696 /* Handled by the state manager */
2699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2700 return WINED3D_OK;
2703 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2705 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2706 *pMatrix = This->stateBlock->transforms[State];
2707 return WINED3D_OK;
2710 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2711 WINED3DMATRIX *mat = NULL;
2712 WINED3DMATRIX temp;
2714 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2715 * below means it will be recorded in a state block change, but it
2716 * works regardless where it is recorded.
2717 * If this is found to be wrong, change to StateBlock.
2719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2720 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2722 if (State < HIGHEST_TRANSFORMSTATE)
2724 mat = &This->updateStateBlock->transforms[State];
2725 } else {
2726 FIXME("Unhandled transform state!!\n");
2729 multiply_matrix(&temp, mat, pMatrix);
2731 /* Apply change via set transform - will reapply to eg. lights this way */
2732 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2735 /*****
2736 * Get / Set Light
2737 *****/
2738 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2739 you can reference any indexes you want as long as that number max are enabled at any
2740 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2741 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2742 but when recording, just build a chain pretty much of commands to be replayed. */
2744 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2745 float rho;
2746 PLIGHTINFOEL *object = NULL;
2747 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2748 struct list *e;
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2751 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2753 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2754 * the gl driver.
2756 if(!pLight) {
2757 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2758 return WINED3DERR_INVALIDCALL;
2761 switch(pLight->Type) {
2762 case WINED3DLIGHT_POINT:
2763 case WINED3DLIGHT_SPOT:
2764 case WINED3DLIGHT_PARALLELPOINT:
2765 case WINED3DLIGHT_GLSPOT:
2766 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2767 * most wanted
2769 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2770 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2771 return WINED3DERR_INVALIDCALL;
2773 break;
2775 case WINED3DLIGHT_DIRECTIONAL:
2776 /* Ignores attenuation */
2777 break;
2779 default:
2780 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2781 return WINED3DERR_INVALIDCALL;
2784 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2785 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2786 if(object->OriginalIndex == Index) break;
2787 object = NULL;
2790 if(!object) {
2791 TRACE("Adding new light\n");
2792 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2793 if(!object) {
2794 ERR("Out of memory error when allocating a light\n");
2795 return E_OUTOFMEMORY;
2797 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2798 object->glIndex = -1;
2799 object->OriginalIndex = Index;
2800 object->changed = TRUE;
2803 /* Initialize the object */
2804 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,
2805 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2806 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2807 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2808 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2809 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2810 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2812 /* Save away the information */
2813 object->OriginalParms = *pLight;
2815 switch (pLight->Type) {
2816 case WINED3DLIGHT_POINT:
2817 /* Position */
2818 object->lightPosn[0] = pLight->Position.x;
2819 object->lightPosn[1] = pLight->Position.y;
2820 object->lightPosn[2] = pLight->Position.z;
2821 object->lightPosn[3] = 1.0f;
2822 object->cutoff = 180.0f;
2823 /* FIXME: Range */
2824 break;
2826 case WINED3DLIGHT_DIRECTIONAL:
2827 /* Direction */
2828 object->lightPosn[0] = -pLight->Direction.x;
2829 object->lightPosn[1] = -pLight->Direction.y;
2830 object->lightPosn[2] = -pLight->Direction.z;
2831 object->lightPosn[3] = 0.0;
2832 object->exponent = 0.0f;
2833 object->cutoff = 180.0f;
2834 break;
2836 case WINED3DLIGHT_SPOT:
2837 /* Position */
2838 object->lightPosn[0] = pLight->Position.x;
2839 object->lightPosn[1] = pLight->Position.y;
2840 object->lightPosn[2] = pLight->Position.z;
2841 object->lightPosn[3] = 1.0;
2843 /* Direction */
2844 object->lightDirn[0] = pLight->Direction.x;
2845 object->lightDirn[1] = pLight->Direction.y;
2846 object->lightDirn[2] = pLight->Direction.z;
2847 object->lightDirn[3] = 1.0;
2850 * opengl-ish and d3d-ish spot lights use too different models for the
2851 * light "intensity" as a function of the angle towards the main light direction,
2852 * so we only can approximate very roughly.
2853 * however spot lights are rather rarely used in games (if ever used at all).
2854 * furthermore if still used, probably nobody pays attention to such details.
2856 if (pLight->Falloff == 0) {
2857 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2858 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2859 * will always be 1.0 for both of them, and we don't have to care for the
2860 * rest of the rather complex calculation
2862 object->exponent = 0;
2863 } else {
2864 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2865 if (rho < 0.0001) rho = 0.0001f;
2866 object->exponent = -0.3/log(cos(rho/2));
2868 if (object->exponent > 128.0) {
2869 object->exponent = 128.0;
2871 object->cutoff = pLight->Phi*90/M_PI;
2873 /* FIXME: Range */
2874 break;
2876 default:
2877 FIXME("Unrecognized light type %d\n", pLight->Type);
2880 /* Update the live definitions if the light is currently assigned a glIndex */
2881 if (object->glIndex != -1 && !This->isRecordingState) {
2882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2884 return WINED3D_OK;
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2888 PLIGHTINFOEL *lightInfo = NULL;
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2891 struct list *e;
2892 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2894 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2895 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2896 if(lightInfo->OriginalIndex == Index) break;
2897 lightInfo = NULL;
2900 if (lightInfo == NULL) {
2901 TRACE("Light information requested but light not defined\n");
2902 return WINED3DERR_INVALIDCALL;
2905 *pLight = lightInfo->OriginalParms;
2906 return WINED3D_OK;
2909 /*****
2910 * Get / Set Light Enable
2911 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2912 *****/
2913 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2914 PLIGHTINFOEL *lightInfo = NULL;
2915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2916 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2917 struct list *e;
2918 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2920 /* Tests show true = 128...not clear why */
2921 Enable = Enable? 128: 0;
2923 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2924 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2925 if(lightInfo->OriginalIndex == Index) break;
2926 lightInfo = NULL;
2928 TRACE("Found light: %p\n", lightInfo);
2930 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2931 if (lightInfo == NULL) {
2933 TRACE("Light enabled requested but light not defined, so defining one!\n");
2934 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2936 /* Search for it again! Should be fairly quick as near head of list */
2937 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2938 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2939 if(lightInfo->OriginalIndex == Index) break;
2940 lightInfo = NULL;
2942 if (lightInfo == NULL) {
2943 FIXME("Adding default lights has failed dismally\n");
2944 return WINED3DERR_INVALIDCALL;
2948 lightInfo->enabledChanged = TRUE;
2949 if(!Enable) {
2950 if(lightInfo->glIndex != -1) {
2951 if(!This->isRecordingState) {
2952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2955 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2956 lightInfo->glIndex = -1;
2957 } else {
2958 TRACE("Light already disabled, nothing to do\n");
2960 lightInfo->enabled = FALSE;
2961 } else {
2962 lightInfo->enabled = TRUE;
2963 if (lightInfo->glIndex != -1) {
2964 /* nop */
2965 TRACE("Nothing to do as light was enabled\n");
2966 } else {
2967 int i;
2968 /* Find a free gl light */
2969 for(i = 0; i < This->maxConcurrentLights; i++) {
2970 if(This->stateBlock->activeLights[i] == NULL) {
2971 This->stateBlock->activeLights[i] = lightInfo;
2972 lightInfo->glIndex = i;
2973 break;
2976 if(lightInfo->glIndex == -1) {
2977 /* Our tests show that Windows returns D3D_OK in this situation, even with
2978 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2979 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2980 * as well for those lights.
2982 * TODO: Test how this affects rendering
2984 FIXME("Too many concurrently active lights\n");
2985 return WINED3D_OK;
2988 /* i == lightInfo->glIndex */
2989 if(!This->isRecordingState) {
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2995 return WINED3D_OK;
2998 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3000 PLIGHTINFOEL *lightInfo = NULL;
3001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3002 struct list *e;
3003 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3004 TRACE("(%p) : for idx(%d)\n", This, Index);
3006 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3007 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3008 if(lightInfo->OriginalIndex == Index) break;
3009 lightInfo = NULL;
3012 if (lightInfo == NULL) {
3013 TRACE("Light enabled state requested but light not defined\n");
3014 return WINED3DERR_INVALIDCALL;
3016 /* true is 128 according to SetLightEnable */
3017 *pEnable = lightInfo->enabled ? 128 : 0;
3018 return WINED3D_OK;
3021 /*****
3022 * Get / Set Clip Planes
3023 *****/
3024 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3026 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3028 /* Validate Index */
3029 if (Index >= GL_LIMITS(clipplanes)) {
3030 TRACE("Application has requested clipplane this device doesn't support\n");
3031 return WINED3DERR_INVALIDCALL;
3034 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3036 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3037 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3038 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3039 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3040 TRACE("Application is setting old values over, nothing to do\n");
3041 return WINED3D_OK;
3044 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3045 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3046 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3047 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3049 /* Handle recording of state blocks */
3050 if (This->isRecordingState) {
3051 TRACE("Recording... not performing anything\n");
3052 return WINED3D_OK;
3055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3057 return WINED3D_OK;
3060 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3062 TRACE("(%p) : for idx %d\n", This, Index);
3064 /* Validate Index */
3065 if (Index >= GL_LIMITS(clipplanes)) {
3066 TRACE("Application has requested clipplane this device doesn't support\n");
3067 return WINED3DERR_INVALIDCALL;
3070 pPlane[0] = This->stateBlock->clipplane[Index][0];
3071 pPlane[1] = This->stateBlock->clipplane[Index][1];
3072 pPlane[2] = This->stateBlock->clipplane[Index][2];
3073 pPlane[3] = This->stateBlock->clipplane[Index][3];
3074 return WINED3D_OK;
3077 /*****
3078 * Get / Set Clip Plane Status
3079 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3080 *****/
3081 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 FIXME("(%p) : stub\n", This);
3084 if (NULL == pClipStatus) {
3085 return WINED3DERR_INVALIDCALL;
3087 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3088 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3089 return WINED3D_OK;
3092 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 FIXME("(%p) : stub\n", This);
3095 if (NULL == pClipStatus) {
3096 return WINED3DERR_INVALIDCALL;
3098 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3099 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3100 return WINED3D_OK;
3103 /*****
3104 * Get / Set Material
3105 *****/
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3111 This->updateStateBlock->changed.material = TRUE;
3112 This->updateStateBlock->material = *pMaterial;
3114 /* Handle recording of state blocks */
3115 if (This->isRecordingState) {
3116 TRACE("Recording... not performing anything\n");
3117 return WINED3D_OK;
3120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3121 return WINED3D_OK;
3124 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3126 *pMaterial = This->updateStateBlock->material;
3127 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3128 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3129 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3130 pMaterial->Ambient.b, pMaterial->Ambient.a);
3131 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3132 pMaterial->Specular.b, pMaterial->Specular.a);
3133 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3134 pMaterial->Emissive.b, pMaterial->Emissive.a);
3135 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3137 return WINED3D_OK;
3140 /*****
3141 * Get / Set Indices
3142 *****/
3143 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 IWineD3DIndexBuffer *oldIdxs;
3147 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3148 oldIdxs = This->updateStateBlock->pIndexData;
3150 This->updateStateBlock->changed.indices = TRUE;
3151 This->updateStateBlock->pIndexData = pIndexData;
3153 /* Handle recording of state blocks */
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3156 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3157 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3158 return WINED3D_OK;
3161 if(oldIdxs != pIndexData) {
3162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3163 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3164 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3166 return WINED3D_OK;
3169 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3172 *ppIndexData = This->stateBlock->pIndexData;
3174 /* up ref count on ppindexdata */
3175 if (*ppIndexData) {
3176 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3177 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3178 }else{
3179 TRACE("(%p) No index data set\n", This);
3181 TRACE("Returning %p\n", *ppIndexData);
3183 return WINED3D_OK;
3186 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3187 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 TRACE("(%p)->(%d)\n", This, BaseIndex);
3191 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3192 TRACE("Application is setting the old value over, nothing to do\n");
3193 return WINED3D_OK;
3196 This->updateStateBlock->baseVertexIndex = BaseIndex;
3198 if (This->isRecordingState) {
3199 TRACE("Recording... not performing anything\n");
3200 return WINED3D_OK;
3202 /* The base vertex index affects the stream sources */
3203 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3204 return WINED3D_OK;
3207 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3209 TRACE("(%p) : base_index %p\n", This, base_index);
3211 *base_index = This->stateBlock->baseVertexIndex;
3213 TRACE("Returning %u\n", *base_index);
3215 return WINED3D_OK;
3218 /*****
3219 * Get / Set Viewports
3220 *****/
3221 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 TRACE("(%p)\n", This);
3225 This->updateStateBlock->changed.viewport = TRUE;
3226 This->updateStateBlock->viewport = *pViewport;
3228 /* Handle recording of state blocks */
3229 if (This->isRecordingState) {
3230 TRACE("Recording... not performing anything\n");
3231 return WINED3D_OK;
3234 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3235 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3238 return WINED3D_OK;
3242 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3244 TRACE("(%p)\n", This);
3245 *pViewport = This->stateBlock->viewport;
3246 return WINED3D_OK;
3249 /*****
3250 * Get / Set Render States
3251 * TODO: Verify against dx9 definitions
3252 *****/
3253 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3256 DWORD oldValue = This->stateBlock->renderState[State];
3258 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3260 This->updateStateBlock->changed.renderState[State] = TRUE;
3261 This->updateStateBlock->renderState[State] = Value;
3263 /* Handle recording of state blocks */
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3266 return WINED3D_OK;
3269 /* Compared here and not before the assignment to allow proper stateblock recording */
3270 if(Value == oldValue) {
3271 TRACE("Application is setting the old value over, nothing to do\n");
3272 } else {
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3276 return WINED3D_OK;
3279 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3281 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3282 *pValue = This->stateBlock->renderState[State];
3283 return WINED3D_OK;
3286 /*****
3287 * Get / Set Sampler States
3288 * TODO: Verify against dx9 definitions
3289 *****/
3291 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 DWORD oldValue;
3295 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3296 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3298 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3299 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3302 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3303 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3304 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3307 * SetSampler is designed to allow for more than the standard up to 8 textures
3308 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3309 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3311 * http://developer.nvidia.com/object/General_FAQ.html#t6
3313 * There are two new settings for GForce
3314 * the sampler one:
3315 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3316 * and the texture one:
3317 * GL_MAX_TEXTURE_COORDS_ARB.
3318 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3319 ******************/
3321 oldValue = This->stateBlock->samplerState[Sampler][Type];
3322 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3323 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3325 /* Handle recording of state blocks */
3326 if (This->isRecordingState) {
3327 TRACE("Recording... not performing anything\n");
3328 return WINED3D_OK;
3331 if(oldValue == Value) {
3332 TRACE("Application is setting the old value over, nothing to do\n");
3333 return WINED3D_OK;
3336 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3338 return WINED3D_OK;
3341 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3345 This, Sampler, debug_d3dsamplerstate(Type), Type);
3347 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3348 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3351 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3352 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3353 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3355 *Value = This->stateBlock->samplerState[Sampler][Type];
3356 TRACE("(%p) : Returning %#x\n", This, *Value);
3358 return WINED3D_OK;
3361 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 This->updateStateBlock->changed.scissorRect = TRUE;
3365 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3366 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3367 return WINED3D_OK;
3369 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3371 if(This->isRecordingState) {
3372 TRACE("Recording... not performing anything\n");
3373 return WINED3D_OK;
3376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3378 return WINED3D_OK;
3381 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3384 *pRect = This->updateStateBlock->scissorRect;
3385 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3386 return WINED3D_OK;
3389 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3391 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3393 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3395 This->updateStateBlock->vertexDecl = pDecl;
3396 This->updateStateBlock->changed.vertexDecl = TRUE;
3398 if (This->isRecordingState) {
3399 TRACE("Recording... not performing anything\n");
3400 return WINED3D_OK;
3401 } else if(pDecl == oldDecl) {
3402 /* Checked after the assignment to allow proper stateblock recording */
3403 TRACE("Application is setting the old declaration over, nothing to do\n");
3404 return WINED3D_OK;
3407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3408 return WINED3D_OK;
3411 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3416 *ppDecl = This->stateBlock->vertexDecl;
3417 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3418 return WINED3D_OK;
3421 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3423 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3425 This->updateStateBlock->vertexShader = pShader;
3426 This->updateStateBlock->changed.vertexShader = TRUE;
3428 if (This->isRecordingState) {
3429 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3430 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3431 TRACE("Recording... not performing anything\n");
3432 return WINED3D_OK;
3433 } else if(oldShader == pShader) {
3434 /* Checked here to allow proper stateblock recording */
3435 TRACE("App is setting the old shader over, nothing to do\n");
3436 return WINED3D_OK;
3439 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3440 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3441 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3445 return WINED3D_OK;
3448 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3451 if (NULL == ppShader) {
3452 return WINED3DERR_INVALIDCALL;
3454 *ppShader = This->stateBlock->vertexShader;
3455 if( NULL != *ppShader)
3456 IWineD3DVertexShader_AddRef(*ppShader);
3458 TRACE("(%p) : returning %p\n", This, *ppShader);
3459 return WINED3D_OK;
3462 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3463 IWineD3DDevice *iface,
3464 UINT start,
3465 CONST BOOL *srcData,
3466 UINT count) {
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3469 int i, cnt = min(count, MAX_CONST_B - start);
3471 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3472 iface, srcData, start, count);
3474 if (srcData == NULL || cnt < 0)
3475 return WINED3DERR_INVALIDCALL;
3477 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3478 for (i = 0; i < cnt; i++)
3479 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3481 for (i = start; i < cnt + start; ++i) {
3482 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3487 return WINED3D_OK;
3490 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3491 IWineD3DDevice *iface,
3492 UINT start,
3493 BOOL *dstData,
3494 UINT count) {
3496 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3497 int cnt = min(count, MAX_CONST_B - start);
3499 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3500 iface, dstData, start, count);
3502 if (dstData == NULL || cnt < 0)
3503 return WINED3DERR_INVALIDCALL;
3505 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3506 return WINED3D_OK;
3509 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3510 IWineD3DDevice *iface,
3511 UINT start,
3512 CONST int *srcData,
3513 UINT count) {
3515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3516 int i, cnt = min(count, MAX_CONST_I - start);
3518 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3519 iface, srcData, start, count);
3521 if (srcData == NULL || cnt < 0)
3522 return WINED3DERR_INVALIDCALL;
3524 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3525 for (i = 0; i < cnt; i++)
3526 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3527 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3529 for (i = start; i < cnt + start; ++i) {
3530 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3535 return WINED3D_OK;
3538 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3539 IWineD3DDevice *iface,
3540 UINT start,
3541 int *dstData,
3542 UINT count) {
3544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3545 int cnt = min(count, MAX_CONST_I - start);
3547 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3548 iface, dstData, start, count);
3550 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3551 return WINED3DERR_INVALIDCALL;
3553 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3554 return WINED3D_OK;
3557 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3558 IWineD3DDevice *iface,
3559 UINT start,
3560 CONST float *srcData,
3561 UINT count) {
3563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3564 int i;
3566 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3567 iface, srcData, start, count);
3569 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3570 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3571 return WINED3DERR_INVALIDCALL;
3573 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3574 if(TRACE_ON(d3d)) {
3575 for (i = 0; i < count; i++)
3576 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3577 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3580 for (i = start; i < count + start; ++i) {
3581 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3582 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3583 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3584 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3585 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3587 ptr->idx[ptr->count++] = i;
3588 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3592 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3594 return WINED3D_OK;
3597 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3598 IWineD3DDevice *iface,
3599 UINT start,
3600 CONST float *srcData,
3601 UINT count) {
3603 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3604 int i;
3606 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3607 iface, srcData, start, count);
3609 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3610 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3611 return WINED3DERR_INVALIDCALL;
3613 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3614 if(TRACE_ON(d3d)) {
3615 for (i = 0; i < count; i++)
3616 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3617 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3620 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3621 * context. On a context switch the old context will be fully dirtified
3623 memset(This->activeContext->vshader_const_dirty + start, 1,
3624 sizeof(*This->activeContext->vshader_const_dirty) * count);
3625 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3629 return WINED3D_OK;
3632 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3633 IWineD3DDevice *iface,
3634 UINT start,
3635 float *dstData,
3636 UINT count) {
3638 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3639 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3641 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3642 iface, dstData, start, count);
3644 if (dstData == NULL || cnt < 0)
3645 return WINED3DERR_INVALIDCALL;
3647 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3648 return WINED3D_OK;
3651 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3652 DWORD i;
3653 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3654 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3658 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3659 int i = This->rev_tex_unit_map[unit];
3660 int j = This->texUnitMap[stage];
3662 This->texUnitMap[stage] = unit;
3663 if (i != -1 && i != stage) {
3664 This->texUnitMap[i] = -1;
3667 This->rev_tex_unit_map[unit] = stage;
3668 if (j != -1 && j != unit) {
3669 This->rev_tex_unit_map[j] = -1;
3673 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3674 int i;
3676 for (i = 0; i < MAX_TEXTURES; ++i) {
3677 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3678 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3679 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3680 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3681 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3682 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3683 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3684 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3686 if (color_op == WINED3DTOP_DISABLE) {
3687 /* Not used, and disable higher stages */
3688 while (i < MAX_TEXTURES) {
3689 This->fixed_function_usage_map[i] = FALSE;
3690 ++i;
3692 break;
3695 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3696 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3697 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3698 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3699 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3700 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3701 This->fixed_function_usage_map[i] = TRUE;
3702 } else {
3703 This->fixed_function_usage_map[i] = FALSE;
3706 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3707 This->fixed_function_usage_map[i+1] = TRUE;
3712 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3713 int i, tex;
3715 device_update_fixed_function_usage_map(This);
3717 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3718 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3719 if (!This->fixed_function_usage_map[i]) continue;
3721 if (This->texUnitMap[i] != i) {
3722 device_map_stage(This, i, i);
3723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3724 markTextureStagesDirty(This, i);
3727 return;
3730 /* Now work out the mapping */
3731 tex = 0;
3732 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3733 if (!This->fixed_function_usage_map[i]) continue;
3735 if (This->texUnitMap[i] != tex) {
3736 device_map_stage(This, i, tex);
3737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3738 markTextureStagesDirty(This, i);
3741 ++tex;
3745 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3746 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3747 int i;
3749 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3750 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3751 device_map_stage(This, i, i);
3752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3753 if (i < MAX_TEXTURES) {
3754 markTextureStagesDirty(This, i);
3760 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3761 int current_mapping = This->rev_tex_unit_map[unit];
3763 if (current_mapping == -1) {
3764 /* Not currently used */
3765 return TRUE;
3768 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3769 /* Used by a fragment sampler */
3771 if (!pshader_sampler_tokens) {
3772 /* No pixel shader, check fixed function */
3773 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3776 /* Pixel shader, check the shader's sampler map */
3777 return !pshader_sampler_tokens[current_mapping];
3780 /* Used by a vertex sampler */
3781 return !vshader_sampler_tokens[current_mapping];
3784 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3785 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3786 DWORD *pshader_sampler_tokens = NULL;
3787 int start = GL_LIMITS(combined_samplers) - 1;
3788 int i;
3790 if (ps) {
3791 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3793 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3794 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3795 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3798 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3799 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3800 if (vshader_sampler_tokens[i]) {
3801 if (This->texUnitMap[vsampler_idx] != -1) {
3802 /* Already mapped somewhere */
3803 continue;
3806 while (start >= 0) {
3807 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3808 device_map_stage(This, vsampler_idx, start);
3809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3811 --start;
3812 break;
3815 --start;
3821 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3822 BOOL vs = use_vs(This);
3823 BOOL ps = use_ps(This);
3825 * Rules are:
3826 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3827 * that would be really messy and require shader recompilation
3828 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3829 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3831 if (ps) {
3832 device_map_psamplers(This);
3833 } else {
3834 device_map_fixed_function_samplers(This);
3837 if (vs) {
3838 device_map_vsamplers(This, ps);
3842 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3844 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3845 This->updateStateBlock->pixelShader = pShader;
3846 This->updateStateBlock->changed.pixelShader = TRUE;
3848 /* Handle recording of state blocks */
3849 if (This->isRecordingState) {
3850 TRACE("Recording... not performing anything\n");
3853 if (This->isRecordingState) {
3854 TRACE("Recording... not performing anything\n");
3855 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3856 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3857 return WINED3D_OK;
3860 if(pShader == oldShader) {
3861 TRACE("App is setting the old pixel shader over, nothing to do\n");
3862 return WINED3D_OK;
3865 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3866 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3868 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3871 return WINED3D_OK;
3874 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3877 if (NULL == ppShader) {
3878 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3879 return WINED3DERR_INVALIDCALL;
3882 *ppShader = This->stateBlock->pixelShader;
3883 if (NULL != *ppShader) {
3884 IWineD3DPixelShader_AddRef(*ppShader);
3886 TRACE("(%p) : returning %p\n", This, *ppShader);
3887 return WINED3D_OK;
3890 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3891 IWineD3DDevice *iface,
3892 UINT start,
3893 CONST BOOL *srcData,
3894 UINT count) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 int i, cnt = min(count, MAX_CONST_B - start);
3899 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3900 iface, srcData, start, count);
3902 if (srcData == NULL || cnt < 0)
3903 return WINED3DERR_INVALIDCALL;
3905 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3906 for (i = 0; i < cnt; i++)
3907 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3909 for (i = start; i < cnt + start; ++i) {
3910 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3915 return WINED3D_OK;
3918 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3919 IWineD3DDevice *iface,
3920 UINT start,
3921 BOOL *dstData,
3922 UINT count) {
3924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3925 int cnt = min(count, MAX_CONST_B - start);
3927 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3928 iface, dstData, start, count);
3930 if (dstData == NULL || cnt < 0)
3931 return WINED3DERR_INVALIDCALL;
3933 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3934 return WINED3D_OK;
3937 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3938 IWineD3DDevice *iface,
3939 UINT start,
3940 CONST int *srcData,
3941 UINT count) {
3943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3944 int i, cnt = min(count, MAX_CONST_I - start);
3946 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3947 iface, srcData, start, count);
3949 if (srcData == NULL || cnt < 0)
3950 return WINED3DERR_INVALIDCALL;
3952 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3953 for (i = 0; i < cnt; i++)
3954 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3955 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3957 for (i = start; i < cnt + start; ++i) {
3958 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3963 return WINED3D_OK;
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3967 IWineD3DDevice *iface,
3968 UINT start,
3969 int *dstData,
3970 UINT count) {
3972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3973 int cnt = min(count, MAX_CONST_I - start);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface, dstData, start, count);
3978 if (dstData == NULL || cnt < 0)
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3982 return WINED3D_OK;
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3986 IWineD3DDevice *iface,
3987 UINT start,
3988 CONST float *srcData,
3989 UINT count) {
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 int i;
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface, srcData, start, count);
3997 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3998 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3999 return WINED3DERR_INVALIDCALL;
4001 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4002 if(TRACE_ON(d3d)) {
4003 for (i = 0; i < count; i++)
4004 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4005 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4008 for (i = start; i < count + start; ++i) {
4009 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4010 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4011 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4012 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4013 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4015 ptr->idx[ptr->count++] = i;
4016 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4022 return WINED3D_OK;
4025 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4026 IWineD3DDevice *iface,
4027 UINT start,
4028 CONST float *srcData,
4029 UINT count) {
4031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 int i;
4034 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4035 iface, srcData, start, count);
4037 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4038 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4039 return WINED3DERR_INVALIDCALL;
4041 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4042 if(TRACE_ON(d3d)) {
4043 for (i = 0; i < count; i++)
4044 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4045 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4048 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4049 * context. On a context switch the old context will be fully dirtified
4051 memset(This->activeContext->pshader_const_dirty + start, 1,
4052 sizeof(*This->activeContext->pshader_const_dirty) * count);
4053 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4057 return WINED3D_OK;
4060 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4061 IWineD3DDevice *iface,
4062 UINT start,
4063 float *dstData,
4064 UINT count) {
4066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4067 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4069 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4070 iface, dstData, start, count);
4072 if (dstData == NULL || cnt < 0)
4073 return WINED3DERR_INVALIDCALL;
4075 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4076 return WINED3D_OK;
4079 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4080 static HRESULT
4081 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4082 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4083 unsigned int i;
4084 DWORD DestFVF = dest->fvf;
4085 WINED3DVIEWPORT vp;
4086 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4087 BOOL doClip;
4088 int numTextures;
4090 if (lpStrideData->u.s.normal.lpData) {
4091 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4094 if (lpStrideData->u.s.position.lpData == NULL) {
4095 ERR("Source has no position mask\n");
4096 return WINED3DERR_INVALIDCALL;
4099 /* We might access VBOs from this code, so hold the lock */
4100 ENTER_GL();
4102 if (dest->resource.allocatedMemory == NULL) {
4103 /* This may happen if we do direct locking into a vbo. Unlikely,
4104 * but theoretically possible(ddraw processvertices test)
4106 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4107 if(!dest->resource.allocatedMemory) {
4108 LEAVE_GL();
4109 ERR("Out of memory\n");
4110 return E_OUTOFMEMORY;
4112 if(dest->vbo) {
4113 void *src;
4114 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4115 checkGLcall("glBindBufferARB");
4116 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4117 if(src) {
4118 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4120 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4121 checkGLcall("glUnmapBufferARB");
4125 /* Get a pointer into the destination vbo(create one if none exists) and
4126 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4128 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4129 dest->Flags |= VBFLAG_CREATEVBO;
4130 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4133 if(dest->vbo) {
4134 unsigned char extrabytes = 0;
4135 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4136 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4137 * this may write 4 extra bytes beyond the area that should be written
4139 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4140 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4141 if(!dest_conv_addr) {
4142 ERR("Out of memory\n");
4143 /* Continue without storing converted vertices */
4145 dest_conv = dest_conv_addr;
4148 /* Should I clip?
4149 * a) WINED3DRS_CLIPPING is enabled
4150 * b) WINED3DVOP_CLIP is passed
4152 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4153 static BOOL warned = FALSE;
4155 * The clipping code is not quite correct. Some things need
4156 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4157 * so disable clipping for now.
4158 * (The graphics in Half-Life are broken, and my processvertices
4159 * test crashes with IDirect3DDevice3)
4160 doClip = TRUE;
4162 doClip = FALSE;
4163 if(!warned) {
4164 warned = TRUE;
4165 FIXME("Clipping is broken and disabled for now\n");
4167 } else doClip = FALSE;
4168 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4170 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4171 WINED3DTS_VIEW,
4172 &view_mat);
4173 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4174 WINED3DTS_PROJECTION,
4175 &proj_mat);
4176 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4177 WINED3DTS_WORLDMATRIX(0),
4178 &world_mat);
4180 TRACE("View mat:\n");
4181 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);
4182 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);
4183 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);
4184 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);
4186 TRACE("Proj mat:\n");
4187 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);
4188 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);
4189 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);
4190 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);
4192 TRACE("World mat:\n");
4193 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);
4194 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);
4195 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);
4196 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);
4198 /* Get the viewport */
4199 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4200 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4201 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4203 multiply_matrix(&mat,&view_mat,&world_mat);
4204 multiply_matrix(&mat,&proj_mat,&mat);
4206 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4208 for (i = 0; i < dwCount; i+= 1) {
4209 unsigned int tex_index;
4211 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4212 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4213 /* The position first */
4214 float *p =
4215 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4216 float x, y, z, rhw;
4217 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4219 /* Multiplication with world, view and projection matrix */
4220 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);
4221 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);
4222 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);
4223 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);
4225 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4227 /* WARNING: The following things are taken from d3d7 and were not yet checked
4228 * against d3d8 or d3d9!
4231 /* Clipping conditions: From msdn
4233 * A vertex is clipped if it does not match the following requirements
4234 * -rhw < x <= rhw
4235 * -rhw < y <= rhw
4236 * 0 < z <= rhw
4237 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4239 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4240 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4244 if( !doClip ||
4245 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4246 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4247 ( rhw > eps ) ) ) {
4249 /* "Normal" viewport transformation (not clipped)
4250 * 1) The values are divided by rhw
4251 * 2) The y axis is negative, so multiply it with -1
4252 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4253 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4254 * 4) Multiply x with Width/2 and add Width/2
4255 * 5) The same for the height
4256 * 6) Add the viewpoint X and Y to the 2D coordinates and
4257 * The minimum Z value to z
4258 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4260 * Well, basically it's simply a linear transformation into viewport
4261 * coordinates
4264 x /= rhw;
4265 y /= rhw;
4266 z /= rhw;
4268 y *= -1;
4270 x *= vp.Width / 2;
4271 y *= vp.Height / 2;
4272 z *= vp.MaxZ - vp.MinZ;
4274 x += vp.Width / 2 + vp.X;
4275 y += vp.Height / 2 + vp.Y;
4276 z += vp.MinZ;
4278 rhw = 1 / rhw;
4279 } else {
4280 /* That vertex got clipped
4281 * Contrary to OpenGL it is not dropped completely, it just
4282 * undergoes a different calculation.
4284 TRACE("Vertex got clipped\n");
4285 x += rhw;
4286 y += rhw;
4288 x /= 2;
4289 y /= 2;
4291 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4292 * outside of the main vertex buffer memory. That needs some more
4293 * investigation...
4297 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4300 ( (float *) dest_ptr)[0] = x;
4301 ( (float *) dest_ptr)[1] = y;
4302 ( (float *) dest_ptr)[2] = z;
4303 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4305 dest_ptr += 3 * sizeof(float);
4307 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4308 dest_ptr += sizeof(float);
4311 if(dest_conv) {
4312 float w = 1 / rhw;
4313 ( (float *) dest_conv)[0] = x * w;
4314 ( (float *) dest_conv)[1] = y * w;
4315 ( (float *) dest_conv)[2] = z * w;
4316 ( (float *) dest_conv)[3] = w;
4318 dest_conv += 3 * sizeof(float);
4320 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4321 dest_conv += sizeof(float);
4325 if (DestFVF & WINED3DFVF_PSIZE) {
4326 dest_ptr += sizeof(DWORD);
4327 if(dest_conv) dest_conv += sizeof(DWORD);
4329 if (DestFVF & WINED3DFVF_NORMAL) {
4330 float *normal =
4331 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4332 /* AFAIK this should go into the lighting information */
4333 FIXME("Didn't expect the destination to have a normal\n");
4334 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4335 if(dest_conv) {
4336 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4340 if (DestFVF & WINED3DFVF_DIFFUSE) {
4341 DWORD *color_d =
4342 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4343 if(!color_d) {
4344 static BOOL warned = FALSE;
4346 if(!warned) {
4347 ERR("No diffuse color in source, but destination has one\n");
4348 warned = TRUE;
4351 *( (DWORD *) dest_ptr) = 0xffffffff;
4352 dest_ptr += sizeof(DWORD);
4354 if(dest_conv) {
4355 *( (DWORD *) dest_conv) = 0xffffffff;
4356 dest_conv += sizeof(DWORD);
4359 else {
4360 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4361 if(dest_conv) {
4362 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4363 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4364 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4365 dest_conv += sizeof(DWORD);
4370 if (DestFVF & WINED3DFVF_SPECULAR) {
4371 /* What's the color value in the feedback buffer? */
4372 DWORD *color_s =
4373 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4374 if(!color_s) {
4375 static BOOL warned = FALSE;
4377 if(!warned) {
4378 ERR("No specular color in source, but destination has one\n");
4379 warned = TRUE;
4382 *( (DWORD *) dest_ptr) = 0xFF000000;
4383 dest_ptr += sizeof(DWORD);
4385 if(dest_conv) {
4386 *( (DWORD *) dest_conv) = 0xFF000000;
4387 dest_conv += sizeof(DWORD);
4390 else {
4391 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4392 if(dest_conv) {
4393 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4394 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4395 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4396 dest_conv += sizeof(DWORD);
4401 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4402 float *tex_coord =
4403 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4404 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4405 if(!tex_coord) {
4406 ERR("No source texture, but destination requests one\n");
4407 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4408 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4410 else {
4411 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4412 if(dest_conv) {
4413 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4419 if(dest_conv) {
4420 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4421 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4422 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4423 dwCount * get_flexible_vertex_size(DestFVF),
4424 dest_conv_addr));
4425 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4426 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4429 LEAVE_GL();
4431 return WINED3D_OK;
4433 #undef copy_and_next
4435 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4437 WineDirect3DVertexStridedData strided;
4438 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4439 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4441 if(pVertexDecl) {
4442 ERR("Output vertex declaration not implemented yet\n");
4445 /* Need any context to write to the vbo. */
4446 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4448 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4449 * control the streamIsUP flag, thus restore it afterwards.
4451 This->stateBlock->streamIsUP = FALSE;
4452 memset(&strided, 0, sizeof(strided));
4453 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4454 This->stateBlock->streamIsUP = streamWasUP;
4456 if(vbo || SrcStartIndex) {
4457 unsigned int i;
4458 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4459 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4461 * Also get the start index in, but only loop over all elements if there's something to add at all.
4463 #define FIXSRC(type) \
4464 if(strided.u.s.type.VBO) { \
4465 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4466 strided.u.s.type.VBO = 0; \
4467 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4468 ENTER_GL(); \
4469 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4470 vb->vbo = 0; \
4471 LEAVE_GL(); \
4473 if(strided.u.s.type.lpData) { \
4474 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4476 FIXSRC(position);
4477 FIXSRC(blendWeights);
4478 FIXSRC(blendMatrixIndices);
4479 FIXSRC(normal);
4480 FIXSRC(pSize);
4481 FIXSRC(diffuse);
4482 FIXSRC(specular);
4483 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4484 FIXSRC(texCoords[i]);
4486 FIXSRC(position2);
4487 FIXSRC(normal2);
4488 FIXSRC(tangent);
4489 FIXSRC(binormal);
4490 FIXSRC(tessFactor);
4491 FIXSRC(fog);
4492 FIXSRC(depth);
4493 FIXSRC(sample);
4494 #undef FIXSRC
4497 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4500 /*****
4501 * Get / Set Texture Stage States
4502 * TODO: Verify against dx9 definitions
4503 *****/
4504 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4508 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4510 if (Stage >= MAX_TEXTURES) {
4511 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4512 return WINED3D_OK;
4515 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4516 This->updateStateBlock->textureState[Stage][Type] = Value;
4518 if (This->isRecordingState) {
4519 TRACE("Recording... not performing anything\n");
4520 return WINED3D_OK;
4523 /* Checked after the assignments to allow proper stateblock recording */
4524 if(oldValue == Value) {
4525 TRACE("App is setting the old value over, nothing to do\n");
4526 return WINED3D_OK;
4529 if(Stage > This->stateBlock->lowest_disabled_stage &&
4530 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4531 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4532 * Changes in other states are important on disabled stages too
4534 return WINED3D_OK;
4537 if(Type == WINED3DTSS_COLOROP) {
4538 int i;
4540 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4541 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4542 * they have to be disabled
4544 * The current stage is dirtified below.
4546 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4547 TRACE("Additionally dirtifying stage %d\n", i);
4548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4550 This->stateBlock->lowest_disabled_stage = Stage;
4551 TRACE("New lowest disabled: %d\n", Stage);
4552 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4553 /* Previously disabled stage enabled. Stages above it may need enabling
4554 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4555 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4557 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4560 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4561 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4562 break;
4564 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4567 This->stateBlock->lowest_disabled_stage = i;
4568 TRACE("New lowest disabled: %d\n", i);
4570 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4571 /* TODO: Built a stage -> texture unit mapping for register combiners */
4575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4577 return WINED3D_OK;
4580 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4582 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4583 *pValue = This->updateStateBlock->textureState[Stage][Type];
4584 return WINED3D_OK;
4587 /*****
4588 * Get / Set Texture
4589 *****/
4590 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4592 IWineD3DBaseTexture *oldTexture;
4594 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4596 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4597 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4600 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4601 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4602 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4605 oldTexture = This->updateStateBlock->textures[Stage];
4607 if(pTexture != NULL) {
4608 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4610 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4611 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4612 return WINED3DERR_INVALIDCALL;
4614 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4617 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4618 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4620 This->updateStateBlock->changed.textures[Stage] = TRUE;
4621 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4622 This->updateStateBlock->textures[Stage] = pTexture;
4624 /* Handle recording of state blocks */
4625 if (This->isRecordingState) {
4626 TRACE("Recording... not performing anything\n");
4627 return WINED3D_OK;
4630 if(oldTexture == pTexture) {
4631 TRACE("App is setting the same texture again, nothing to do\n");
4632 return WINED3D_OK;
4635 /** NOTE: MSDN says that setTexture increases the reference count,
4636 * and that the application must set the texture back to null (or have a leaky application),
4637 * This means we should pass the refcount up to the parent
4638 *******************************/
4639 if (NULL != This->updateStateBlock->textures[Stage]) {
4640 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4641 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4643 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4644 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4645 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4646 * so the COLOROP and ALPHAOP have to be dirtified.
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4651 if(bindCount == 1) {
4652 new->baseTexture.sampler = Stage;
4654 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4658 if (NULL != oldTexture) {
4659 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4660 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4662 IWineD3DBaseTexture_Release(oldTexture);
4663 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4665 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4668 if(bindCount && old->baseTexture.sampler == Stage) {
4669 int i;
4670 /* Have to do a search for the other sampler(s) where the texture is bound to
4671 * Shouldn't happen as long as apps bind a texture only to one stage
4673 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4674 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4675 if(This->updateStateBlock->textures[i] == oldTexture) {
4676 old->baseTexture.sampler = i;
4677 break;
4683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4685 return WINED3D_OK;
4688 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4693 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4694 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4697 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4698 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4699 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4702 *ppTexture=This->stateBlock->textures[Stage];
4703 if (*ppTexture)
4704 IWineD3DBaseTexture_AddRef(*ppTexture);
4706 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4708 return WINED3D_OK;
4711 /*****
4712 * Get Back Buffer
4713 *****/
4714 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4715 IWineD3DSurface **ppBackBuffer) {
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 IWineD3DSwapChain *swapChain;
4718 HRESULT hr;
4720 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4722 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4723 if (hr == WINED3D_OK) {
4724 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4725 IWineD3DSwapChain_Release(swapChain);
4726 } else {
4727 *ppBackBuffer = NULL;
4729 return hr;
4732 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4734 WARN("(%p) : stub, calling idirect3d for now\n", This);
4735 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4738 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4740 IWineD3DSwapChain *swapChain;
4741 HRESULT hr;
4743 if(iSwapChain > 0) {
4744 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4745 if (hr == WINED3D_OK) {
4746 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4747 IWineD3DSwapChain_Release(swapChain);
4748 } else {
4749 FIXME("(%p) Error getting display mode\n", This);
4751 } else {
4752 /* Don't read the real display mode,
4753 but return the stored mode instead. X11 can't change the color
4754 depth, and some apps are pretty angry if they SetDisplayMode from
4755 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4757 Also don't relay to the swapchain because with ddraw it's possible
4758 that there isn't a swapchain at all */
4759 pMode->Width = This->ddraw_width;
4760 pMode->Height = This->ddraw_height;
4761 pMode->Format = This->ddraw_format;
4762 pMode->RefreshRate = 0;
4763 hr = WINED3D_OK;
4766 return hr;
4769 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4771 TRACE("(%p)->(%p)\n", This, hWnd);
4773 if(This->ddraw_fullscreen) {
4774 if(This->ddraw_window && This->ddraw_window != hWnd) {
4775 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4777 if(hWnd && This->ddraw_window != hWnd) {
4778 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4782 This->ddraw_window = hWnd;
4783 return WINED3D_OK;
4786 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4788 TRACE("(%p)->(%p)\n", This, hWnd);
4790 *hWnd = This->ddraw_window;
4791 return WINED3D_OK;
4794 /*****
4795 * Stateblock related functions
4796 *****/
4798 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 IWineD3DStateBlockImpl *object;
4801 HRESULT temp_result;
4802 int i;
4804 TRACE("(%p)\n", This);
4806 if (This->isRecordingState) {
4807 return WINED3DERR_INVALIDCALL;
4810 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4811 if (NULL == object ) {
4812 FIXME("(%p)Error allocating memory for stateblock\n", This);
4813 return E_OUTOFMEMORY;
4815 TRACE("(%p) created object %p\n", This, object);
4816 object->wineD3DDevice= This;
4817 /** FIXME: object->parent = parent; **/
4818 object->parent = NULL;
4819 object->blockType = WINED3DSBT_RECORDED;
4820 object->ref = 1;
4821 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4823 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4824 list_init(&object->lightMap[i]);
4827 temp_result = allocate_shader_constants(object);
4828 if (WINED3D_OK != temp_result)
4829 return temp_result;
4831 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4832 This->updateStateBlock = object;
4833 This->isRecordingState = TRUE;
4835 TRACE("(%p) recording stateblock %p\n",This , object);
4836 return WINED3D_OK;
4839 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 unsigned int i, j;
4842 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4844 if (!This->isRecordingState) {
4845 FIXME("(%p) not recording! returning error\n", This);
4846 *ppStateBlock = NULL;
4847 return WINED3DERR_INVALIDCALL;
4850 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4851 if(object->changed.renderState[i]) {
4852 object->contained_render_states[object->num_contained_render_states] = i;
4853 object->num_contained_render_states++;
4856 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4857 if(object->changed.transform[i]) {
4858 object->contained_transform_states[object->num_contained_transform_states] = i;
4859 object->num_contained_transform_states++;
4862 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4863 if(object->changed.vertexShaderConstantsF[i]) {
4864 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4865 object->num_contained_vs_consts_f++;
4868 for(i = 0; i < MAX_CONST_I; i++) {
4869 if(object->changed.vertexShaderConstantsI[i]) {
4870 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4871 object->num_contained_vs_consts_i++;
4874 for(i = 0; i < MAX_CONST_B; i++) {
4875 if(object->changed.vertexShaderConstantsB[i]) {
4876 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4877 object->num_contained_vs_consts_b++;
4880 for(i = 0; i < MAX_CONST_I; i++) {
4881 if(object->changed.pixelShaderConstantsI[i]) {
4882 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4883 object->num_contained_ps_consts_i++;
4886 for(i = 0; i < MAX_CONST_B; i++) {
4887 if(object->changed.pixelShaderConstantsB[i]) {
4888 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4889 object->num_contained_ps_consts_b++;
4892 for(i = 0; i < MAX_TEXTURES; i++) {
4893 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4894 if(object->changed.textureState[i][j]) {
4895 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4896 object->contained_tss_states[object->num_contained_tss_states].state = j;
4897 object->num_contained_tss_states++;
4901 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4902 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4903 if(object->changed.samplerState[i][j]) {
4904 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4905 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4906 object->num_contained_sampler_states++;
4911 *ppStateBlock = (IWineD3DStateBlock*) object;
4912 This->isRecordingState = FALSE;
4913 This->updateStateBlock = This->stateBlock;
4914 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4915 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4916 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4917 return WINED3D_OK;
4920 /*****
4921 * Scene related functions
4922 *****/
4923 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4924 /* At the moment we have no need for any functionality at the beginning
4925 of a scene */
4926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4927 TRACE("(%p)\n", This);
4929 if(This->inScene) {
4930 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4931 return WINED3DERR_INVALIDCALL;
4933 This->inScene = TRUE;
4934 return WINED3D_OK;
4937 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4939 TRACE("(%p)\n", This);
4941 if(!This->inScene) {
4942 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4943 return WINED3DERR_INVALIDCALL;
4946 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4947 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4948 ENTER_GL();
4949 glFlush();
4950 checkGLcall("glFlush");
4951 LEAVE_GL();
4953 This->inScene = FALSE;
4954 return WINED3D_OK;
4957 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4958 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4959 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 IWineD3DSwapChain *swapChain = NULL;
4962 int i;
4963 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4965 TRACE("(%p) Presenting the frame\n", This);
4967 for(i = 0 ; i < swapchains ; i ++) {
4969 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4970 TRACE("presentinng chain %d, %p\n", i, swapChain);
4971 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4972 IWineD3DSwapChain_Release(swapChain);
4975 return WINED3D_OK;
4978 /* Not called from the VTable (internal subroutine) */
4979 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4980 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4981 float Z, DWORD Stencil) {
4982 GLbitfield glMask = 0;
4983 unsigned int i;
4984 WINED3DRECT curRect;
4985 RECT vp_rect;
4986 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4987 UINT drawable_width, drawable_height;
4988 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4990 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4991 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4992 * for the cleared parts, and the untouched parts.
4994 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4995 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4996 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4997 * checking all this if the dest surface is in the drawable anyway.
4999 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5000 while(1) {
5001 if(vp->X != 0 || vp->Y != 0 ||
5002 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5003 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5004 break;
5006 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5007 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5008 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5009 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5010 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5011 break;
5013 if(Count > 0 && pRects && (
5014 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5015 pRects[0].x2 < target->currentDesc.Width ||
5016 pRects[0].y2 < target->currentDesc.Height)) {
5017 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5018 break;
5020 break;
5024 target->get_drawable_size(target, &drawable_width, &drawable_height);
5026 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5027 ENTER_GL();
5029 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5030 apply_fbo_state((IWineD3DDevice *) This);
5033 /* Only set the values up once, as they are not changing */
5034 if (Flags & WINED3DCLEAR_STENCIL) {
5035 glClearStencil(Stencil);
5036 checkGLcall("glClearStencil");
5037 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5038 glStencilMask(0xFFFFFFFF);
5041 if (Flags & WINED3DCLEAR_ZBUFFER) {
5042 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5043 glDepthMask(GL_TRUE);
5044 glClearDepth(Z);
5045 checkGLcall("glClearDepth");
5046 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5047 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5049 if (vp->X != 0 || vp->Y != 0 ||
5050 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5051 surface_load_ds_location(This->stencilBufferTarget, location);
5053 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5054 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5055 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5056 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5057 surface_load_ds_location(This->stencilBufferTarget, location);
5059 else if (Count > 0 && pRects && (
5060 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5061 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5062 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5063 surface_load_ds_location(This->stencilBufferTarget, location);
5067 if (Flags & WINED3DCLEAR_TARGET) {
5068 TRACE("Clearing screen with glClear to color %x\n", Color);
5069 glClearColor(D3DCOLOR_R(Color),
5070 D3DCOLOR_G(Color),
5071 D3DCOLOR_B(Color),
5072 D3DCOLOR_A(Color));
5073 checkGLcall("glClearColor");
5075 /* Clear ALL colors! */
5076 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5077 glMask = glMask | GL_COLOR_BUFFER_BIT;
5080 vp_rect.left = vp->X;
5081 vp_rect.top = vp->Y;
5082 vp_rect.right = vp->X + vp->Width;
5083 vp_rect.bottom = vp->Y + vp->Height;
5084 if (!(Count > 0 && pRects)) {
5085 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5086 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5088 if(This->render_offscreen) {
5089 glScissor(vp_rect.left, vp_rect.top,
5090 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5091 } else {
5092 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5093 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5095 checkGLcall("glScissor");
5096 glClear(glMask);
5097 checkGLcall("glClear");
5098 } else {
5099 /* Now process each rect in turn */
5100 for (i = 0; i < Count; i++) {
5101 /* Note gl uses lower left, width/height */
5102 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5103 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5104 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5106 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5107 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5108 curRect.x1, (target->currentDesc.Height - curRect.y2),
5109 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5111 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5112 * The rectangle is not cleared, no error is returned, but further rectanlges are
5113 * still cleared if they are valid
5115 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5116 TRACE("Rectangle with negative dimensions, ignoring\n");
5117 continue;
5120 if(This->render_offscreen) {
5121 glScissor(curRect.x1, curRect.y1,
5122 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5123 } else {
5124 glScissor(curRect.x1, drawable_height - curRect.y2,
5125 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5127 checkGLcall("glScissor");
5129 glClear(glMask);
5130 checkGLcall("glClear");
5134 /* Restore the old values (why..?) */
5135 if (Flags & WINED3DCLEAR_STENCIL) {
5136 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5138 if (Flags & WINED3DCLEAR_TARGET) {
5139 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5140 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5141 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5142 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5143 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5145 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5146 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5148 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5149 /* TODO: Move the fbo logic into ModifyLocation() */
5150 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5151 target->Flags |= SFLAG_INTEXTURE;
5154 if (Flags & WINED3DCLEAR_ZBUFFER) {
5155 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5156 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5157 surface_modify_ds_location(This->stencilBufferTarget, location);
5160 LEAVE_GL();
5162 return WINED3D_OK;
5165 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5166 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5168 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5170 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5171 Count, pRects, Flags, Color, Z, Stencil);
5173 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5174 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5175 /* TODO: What about depth stencil buffers without stencil bits? */
5176 return WINED3DERR_INVALIDCALL;
5179 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5182 /*****
5183 * Drawing functions
5184 *****/
5185 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5186 UINT PrimitiveCount) {
5188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5190 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5191 debug_d3dprimitivetype(PrimitiveType),
5192 StartVertex, PrimitiveCount);
5194 if(!This->stateBlock->vertexDecl) {
5195 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5196 return WINED3DERR_INVALIDCALL;
5199 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5200 if(This->stateBlock->streamIsUP) {
5201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5202 This->stateBlock->streamIsUP = FALSE;
5205 if(This->stateBlock->loadBaseVertexIndex != 0) {
5206 This->stateBlock->loadBaseVertexIndex = 0;
5207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5209 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5210 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5211 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5212 return WINED3D_OK;
5215 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5216 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5217 WINED3DPRIMITIVETYPE PrimitiveType,
5218 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5221 UINT idxStride = 2;
5222 IWineD3DIndexBuffer *pIB;
5223 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5224 GLuint vbo;
5226 pIB = This->stateBlock->pIndexData;
5227 if (!pIB) {
5228 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5229 * without an index buffer set. (The first time at least...)
5230 * D3D8 simply dies, but I doubt it can do much harm to return
5231 * D3DERR_INVALIDCALL there as well. */
5232 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5233 return WINED3DERR_INVALIDCALL;
5236 if(!This->stateBlock->vertexDecl) {
5237 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5238 return WINED3DERR_INVALIDCALL;
5241 if(This->stateBlock->streamIsUP) {
5242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5243 This->stateBlock->streamIsUP = FALSE;
5245 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5247 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5248 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5249 minIndex, NumVertices, startIndex, primCount);
5251 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5252 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5253 idxStride = 2;
5254 } else {
5255 idxStride = 4;
5258 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5259 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5263 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5264 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5266 return WINED3D_OK;
5269 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5270 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5271 UINT VertexStreamZeroStride) {
5272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5273 IWineD3DVertexBuffer *vb;
5275 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5276 debug_d3dprimitivetype(PrimitiveType),
5277 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5279 if(!This->stateBlock->vertexDecl) {
5280 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5281 return WINED3DERR_INVALIDCALL;
5284 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5285 vb = This->stateBlock->streamSource[0];
5286 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5287 if(vb) IWineD3DVertexBuffer_Release(vb);
5288 This->stateBlock->streamOffset[0] = 0;
5289 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5290 This->stateBlock->streamIsUP = TRUE;
5291 This->stateBlock->loadBaseVertexIndex = 0;
5293 /* TODO: Only mark dirty if drawing from a different UP address */
5294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5296 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5297 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5299 /* MSDN specifies stream zero settings must be set to NULL */
5300 This->stateBlock->streamStride[0] = 0;
5301 This->stateBlock->streamSource[0] = NULL;
5303 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5304 * the new stream sources or use UP drawing again
5306 return WINED3D_OK;
5309 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5310 UINT MinVertexIndex, UINT NumVertices,
5311 UINT PrimitiveCount, CONST void* pIndexData,
5312 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5313 UINT VertexStreamZeroStride) {
5314 int idxStride;
5315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5316 IWineD3DVertexBuffer *vb;
5317 IWineD3DIndexBuffer *ib;
5319 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5320 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5321 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5322 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5324 if(!This->stateBlock->vertexDecl) {
5325 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5326 return WINED3DERR_INVALIDCALL;
5329 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5330 idxStride = 2;
5331 } else {
5332 idxStride = 4;
5335 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5336 vb = This->stateBlock->streamSource[0];
5337 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5338 if(vb) IWineD3DVertexBuffer_Release(vb);
5339 This->stateBlock->streamIsUP = TRUE;
5340 This->stateBlock->streamOffset[0] = 0;
5341 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5343 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5344 This->stateBlock->baseVertexIndex = 0;
5345 This->stateBlock->loadBaseVertexIndex = 0;
5346 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5350 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5352 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5353 This->stateBlock->streamSource[0] = NULL;
5354 This->stateBlock->streamStride[0] = 0;
5355 ib = This->stateBlock->pIndexData;
5356 if(ib) {
5357 IWineD3DIndexBuffer_Release(ib);
5358 This->stateBlock->pIndexData = NULL;
5360 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5361 * SetStreamSource to specify a vertex buffer
5364 return WINED3D_OK;
5367 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5370 /* Mark the state dirty until we have nicer tracking
5371 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5372 * that value.
5374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5376 This->stateBlock->baseVertexIndex = 0;
5377 This->up_strided = DrawPrimStrideData;
5378 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5379 This->up_strided = NULL;
5380 return WINED3D_OK;
5383 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5385 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5387 /* Mark the state dirty until we have nicer tracking
5388 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5389 * that value.
5391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5392 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5393 This->stateBlock->streamIsUP = TRUE;
5394 This->stateBlock->baseVertexIndex = 0;
5395 This->up_strided = DrawPrimStrideData;
5396 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5397 This->up_strided = NULL;
5398 return WINED3D_OK;
5401 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5402 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5403 * not callable by the app directly no parameter validation checks are needed here.
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5406 WINED3DLOCKED_BOX src;
5407 WINED3DLOCKED_BOX dst;
5408 HRESULT hr;
5409 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5411 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5412 * dirtification to improve loading performance.
5414 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5415 if(FAILED(hr)) return hr;
5416 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5417 if(FAILED(hr)) {
5418 IWineD3DVolume_UnlockBox(pSourceVolume);
5419 return hr;
5422 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5424 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5425 if(FAILED(hr)) {
5426 IWineD3DVolume_UnlockBox(pSourceVolume);
5427 } else {
5428 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5430 return hr;
5433 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5434 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5436 HRESULT hr = WINED3D_OK;
5437 WINED3DRESOURCETYPE sourceType;
5438 WINED3DRESOURCETYPE destinationType;
5439 int i ,levels;
5441 /* TODO: think about moving the code into IWineD3DBaseTexture */
5443 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5445 /* verify that the source and destination textures aren't NULL */
5446 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5447 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5448 This, pSourceTexture, pDestinationTexture);
5449 hr = WINED3DERR_INVALIDCALL;
5452 if (pSourceTexture == pDestinationTexture) {
5453 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5454 This, pSourceTexture, pDestinationTexture);
5455 hr = WINED3DERR_INVALIDCALL;
5457 /* Verify that the source and destination textures are the same type */
5458 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5459 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5461 if (sourceType != destinationType) {
5462 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5463 This);
5464 hr = WINED3DERR_INVALIDCALL;
5467 /* check that both textures have the identical numbers of levels */
5468 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5469 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5470 hr = WINED3DERR_INVALIDCALL;
5473 if (WINED3D_OK == hr) {
5475 /* Make sure that the destination texture is loaded */
5476 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5478 /* Update every surface level of the texture */
5479 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5481 switch (sourceType) {
5482 case WINED3DRTYPE_TEXTURE:
5484 IWineD3DSurface *srcSurface;
5485 IWineD3DSurface *destSurface;
5487 for (i = 0 ; i < levels ; ++i) {
5488 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5489 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5490 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5491 IWineD3DSurface_Release(srcSurface);
5492 IWineD3DSurface_Release(destSurface);
5493 if (WINED3D_OK != hr) {
5494 WARN("(%p) : Call to update surface failed\n", This);
5495 return hr;
5499 break;
5500 case WINED3DRTYPE_CUBETEXTURE:
5502 IWineD3DSurface *srcSurface;
5503 IWineD3DSurface *destSurface;
5504 WINED3DCUBEMAP_FACES faceType;
5506 for (i = 0 ; i < levels ; ++i) {
5507 /* Update each cube face */
5508 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5509 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5510 if (WINED3D_OK != hr) {
5511 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5512 } else {
5513 TRACE("Got srcSurface %p\n", srcSurface);
5515 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5516 if (WINED3D_OK != hr) {
5517 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5518 } else {
5519 TRACE("Got desrSurface %p\n", destSurface);
5521 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5522 IWineD3DSurface_Release(srcSurface);
5523 IWineD3DSurface_Release(destSurface);
5524 if (WINED3D_OK != hr) {
5525 WARN("(%p) : Call to update surface failed\n", This);
5526 return hr;
5531 break;
5533 case WINED3DRTYPE_VOLUMETEXTURE:
5535 IWineD3DVolume *srcVolume = NULL;
5536 IWineD3DVolume *destVolume = NULL;
5538 for (i = 0 ; i < levels ; ++i) {
5539 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5540 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5541 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5542 IWineD3DVolume_Release(srcVolume);
5543 IWineD3DVolume_Release(destVolume);
5544 if (WINED3D_OK != hr) {
5545 WARN("(%p) : Call to update volume failed\n", This);
5546 return hr;
5550 break;
5552 default:
5553 FIXME("(%p) : Unsupported source and destination type\n", This);
5554 hr = WINED3DERR_INVALIDCALL;
5558 return hr;
5561 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5562 IWineD3DSwapChain *swapChain;
5563 HRESULT hr;
5564 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5565 if(hr == WINED3D_OK) {
5566 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5567 IWineD3DSwapChain_Release(swapChain);
5569 return hr;
5572 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5574 /* return a sensible default */
5575 *pNumPasses = 1;
5576 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5577 FIXME("(%p) : stub\n", This);
5578 return WINED3D_OK;
5581 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5583 int i;
5585 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5586 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5587 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5588 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5593 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5595 int j;
5596 UINT NewSize;
5597 PALETTEENTRY **palettes;
5599 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5601 if (PaletteNumber >= MAX_PALETTES) {
5602 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5603 return WINED3DERR_INVALIDCALL;
5606 if (PaletteNumber >= This->NumberOfPalettes) {
5607 NewSize = This->NumberOfPalettes;
5608 do {
5609 NewSize *= 2;
5610 } while(PaletteNumber >= NewSize);
5611 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5612 if (!palettes) {
5613 ERR("Out of memory!\n");
5614 return E_OUTOFMEMORY;
5616 This->palettes = palettes;
5617 This->NumberOfPalettes = NewSize;
5620 if (!This->palettes[PaletteNumber]) {
5621 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5622 if (!This->palettes[PaletteNumber]) {
5623 ERR("Out of memory!\n");
5624 return E_OUTOFMEMORY;
5628 for (j = 0; j < 256; ++j) {
5629 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5630 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5631 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5632 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5634 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5635 TRACE("(%p) : returning\n", This);
5636 return WINED3D_OK;
5639 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641 int j;
5642 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5643 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5644 /* What happens in such situation isn't documented; Native seems to silently abort
5645 on such conditions. Return Invalid Call. */
5646 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5647 return WINED3DERR_INVALIDCALL;
5649 for (j = 0; j < 256; ++j) {
5650 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5651 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5652 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5653 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5655 TRACE("(%p) : returning\n", This);
5656 return WINED3D_OK;
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5662 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5663 (tested with reference rasterizer). Return Invalid Call. */
5664 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5665 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5666 return WINED3DERR_INVALIDCALL;
5668 /*TODO: stateblocks */
5669 if (This->currentPalette != PaletteNumber) {
5670 This->currentPalette = PaletteNumber;
5671 dirtify_p8_texture_samplers(This);
5673 TRACE("(%p) : returning\n", This);
5674 return WINED3D_OK;
5677 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5679 if (PaletteNumber == NULL) {
5680 WARN("(%p) : returning Invalid Call\n", This);
5681 return WINED3DERR_INVALIDCALL;
5683 /*TODO: stateblocks */
5684 *PaletteNumber = This->currentPalette;
5685 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5686 return WINED3D_OK;
5689 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5691 static BOOL showFixmes = TRUE;
5692 if (showFixmes) {
5693 FIXME("(%p) : stub\n", This);
5694 showFixmes = FALSE;
5697 This->softwareVertexProcessing = bSoftware;
5698 return WINED3D_OK;
5702 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5704 static BOOL showFixmes = TRUE;
5705 if (showFixmes) {
5706 FIXME("(%p) : stub\n", This);
5707 showFixmes = FALSE;
5709 return This->softwareVertexProcessing;
5713 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5715 IWineD3DSwapChain *swapChain;
5716 HRESULT hr;
5718 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5720 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5721 if(hr == WINED3D_OK){
5722 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5723 IWineD3DSwapChain_Release(swapChain);
5724 }else{
5725 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5727 return hr;
5731 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5733 static BOOL showfixmes = TRUE;
5734 if(nSegments != 0.0f) {
5735 if( showfixmes) {
5736 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5737 showfixmes = FALSE;
5740 return WINED3D_OK;
5743 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5745 static BOOL showfixmes = TRUE;
5746 if( showfixmes) {
5747 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5748 showfixmes = FALSE;
5750 return 0.0f;
5753 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5755 /** TODO: remove casts to IWineD3DSurfaceImpl
5756 * NOTE: move code to surface to accomplish this
5757 ****************************************/
5758 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5759 int srcWidth, srcHeight;
5760 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5761 WINED3DFORMAT destFormat, srcFormat;
5762 UINT destSize;
5763 int srcLeft, destLeft, destTop;
5764 WINED3DPOOL srcPool, destPool;
5765 int offset = 0;
5766 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5767 glDescriptor *glDescription = NULL;
5768 GLenum dummy;
5769 int sampler;
5770 int bpp;
5771 CONVERT_TYPES convert = NO_CONVERSION;
5773 WINED3DSURFACE_DESC winedesc;
5775 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5776 memset(&winedesc, 0, sizeof(winedesc));
5777 winedesc.Width = &srcSurfaceWidth;
5778 winedesc.Height = &srcSurfaceHeight;
5779 winedesc.Pool = &srcPool;
5780 winedesc.Format = &srcFormat;
5782 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5784 winedesc.Width = &destSurfaceWidth;
5785 winedesc.Height = &destSurfaceHeight;
5786 winedesc.Pool = &destPool;
5787 winedesc.Format = &destFormat;
5788 winedesc.Size = &destSize;
5790 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5792 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5793 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5794 return WINED3DERR_INVALIDCALL;
5797 /* This call loads the opengl surface directly, instead of copying the surface to the
5798 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5799 * copy in sysmem and use regular surface loading.
5801 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5802 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5803 if(convert != NO_CONVERSION) {
5804 return IWineD3DSurface_BltFast(pDestinationSurface,
5805 pDestPoint ? pDestPoint->x : 0,
5806 pDestPoint ? pDestPoint->y : 0,
5807 pSourceSurface, (RECT *) pSourceRect, 0);
5810 if (destFormat == WINED3DFMT_UNKNOWN) {
5811 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5812 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5814 /* Get the update surface description */
5815 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5818 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5820 ENTER_GL();
5822 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5823 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5824 checkGLcall("glActiveTextureARB");
5827 /* Make sure the surface is loaded and up to date */
5828 IWineD3DSurface_PreLoad(pDestinationSurface);
5830 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5832 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5833 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5834 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5835 srcLeft = pSourceRect ? pSourceRect->left : 0;
5836 destLeft = pDestPoint ? pDestPoint->x : 0;
5837 destTop = pDestPoint ? pDestPoint->y : 0;
5840 /* This function doesn't support compressed textures
5841 the pitch is just bytesPerPixel * width */
5842 if(srcWidth != srcSurfaceWidth || srcLeft ){
5843 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5844 offset += srcLeft * pSrcSurface->bytesPerPixel;
5845 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5847 /* TODO DXT formats */
5849 if(pSourceRect != NULL && pSourceRect->top != 0){
5850 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5852 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5853 ,This
5854 ,glDescription->level
5855 ,destLeft
5856 ,destTop
5857 ,srcWidth
5858 ,srcHeight
5859 ,glDescription->glFormat
5860 ,glDescription->glType
5861 ,IWineD3DSurface_GetData(pSourceSurface)
5864 /* Sanity check */
5865 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5867 /* need to lock the surface to get the data */
5868 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5871 /* TODO: Cube and volume support */
5872 if(rowoffset != 0){
5873 /* not a whole row so we have to do it a line at a time */
5874 int j;
5876 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5877 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5879 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5881 glTexSubImage2D(glDescription->target
5882 ,glDescription->level
5883 ,destLeft
5885 ,srcWidth
5887 ,glDescription->glFormat
5888 ,glDescription->glType
5889 ,data /* could be quicker using */
5891 data += rowoffset;
5894 } else { /* Full width, so just write out the whole texture */
5896 if (WINED3DFMT_DXT1 == destFormat ||
5897 WINED3DFMT_DXT2 == destFormat ||
5898 WINED3DFMT_DXT3 == destFormat ||
5899 WINED3DFMT_DXT4 == destFormat ||
5900 WINED3DFMT_DXT5 == destFormat) {
5901 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5902 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5903 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5904 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5905 } if (destFormat != srcFormat) {
5906 FIXME("Updating mixed format compressed texture is not curretly support\n");
5907 } else {
5908 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5909 glDescription->level,
5910 glDescription->glFormatInternal,
5911 srcWidth,
5912 srcHeight,
5914 destSize,
5915 IWineD3DSurface_GetData(pSourceSurface));
5917 } else {
5918 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5922 } else {
5923 glTexSubImage2D(glDescription->target
5924 ,glDescription->level
5925 ,destLeft
5926 ,destTop
5927 ,srcWidth
5928 ,srcHeight
5929 ,glDescription->glFormat
5930 ,glDescription->glType
5931 ,IWineD3DSurface_GetData(pSourceSurface)
5935 checkGLcall("glTexSubImage2D");
5937 LEAVE_GL();
5939 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5940 sampler = This->rev_tex_unit_map[0];
5941 if (sampler != -1) {
5942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5945 return WINED3D_OK;
5948 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5950 struct WineD3DRectPatch *patch;
5951 unsigned int i;
5952 struct list *e;
5953 BOOL found;
5954 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5956 if(!(Handle || pRectPatchInfo)) {
5957 /* TODO: Write a test for the return value, thus the FIXME */
5958 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5959 return WINED3DERR_INVALIDCALL;
5962 if(Handle) {
5963 i = PATCHMAP_HASHFUNC(Handle);
5964 found = FALSE;
5965 LIST_FOR_EACH(e, &This->patches[i]) {
5966 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5967 if(patch->Handle == Handle) {
5968 found = TRUE;
5969 break;
5973 if(!found) {
5974 TRACE("Patch does not exist. Creating a new one\n");
5975 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5976 patch->Handle = Handle;
5977 list_add_head(&This->patches[i], &patch->entry);
5978 } else {
5979 TRACE("Found existing patch %p\n", patch);
5981 } else {
5982 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5983 * attributes we have to tesselate, read back, and draw. This needs a patch
5984 * management structure instance. Create one.
5986 * A possible improvement is to check if a vertex shader is used, and if not directly
5987 * draw the patch.
5989 FIXME("Drawing an uncached patch. This is slow\n");
5990 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5993 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5994 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5995 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5996 HRESULT hr;
5997 TRACE("Tesselation density or patch info changed, retesselating\n");
5999 if(pRectPatchInfo) {
6000 patch->RectPatchInfo = *pRectPatchInfo;
6002 patch->numSegs[0] = pNumSegs[0];
6003 patch->numSegs[1] = pNumSegs[1];
6004 patch->numSegs[2] = pNumSegs[2];
6005 patch->numSegs[3] = pNumSegs[3];
6007 hr = tesselate_rectpatch(This, patch);
6008 if(FAILED(hr)) {
6009 WARN("Patch tesselation failed\n");
6011 /* Do not release the handle to store the params of the patch */
6012 if(!Handle) {
6013 HeapFree(GetProcessHeap(), 0, patch);
6015 return hr;
6019 This->currentPatch = patch;
6020 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6021 This->currentPatch = NULL;
6023 /* Destroy uncached patches */
6024 if(!Handle) {
6025 HeapFree(GetProcessHeap(), 0, patch->mem);
6026 HeapFree(GetProcessHeap(), 0, patch);
6028 return WINED3D_OK;
6031 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6033 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6034 FIXME("(%p) : Stub\n", This);
6035 return WINED3D_OK;
6038 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6040 int i;
6041 struct WineD3DRectPatch *patch;
6042 struct list *e;
6043 TRACE("(%p) Handle(%d)\n", This, Handle);
6045 i = PATCHMAP_HASHFUNC(Handle);
6046 LIST_FOR_EACH(e, &This->patches[i]) {
6047 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6048 if(patch->Handle == Handle) {
6049 TRACE("Deleting patch %p\n", patch);
6050 list_remove(&patch->entry);
6051 HeapFree(GetProcessHeap(), 0, patch->mem);
6052 HeapFree(GetProcessHeap(), 0, patch);
6053 return WINED3D_OK;
6057 /* TODO: Write a test for the return value */
6058 FIXME("Attempt to destroy nonexistent patch\n");
6059 return WINED3DERR_INVALIDCALL;
6062 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6063 HRESULT hr;
6064 IWineD3DSwapChain *swapchain;
6066 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6067 if (SUCCEEDED(hr)) {
6068 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6069 return swapchain;
6072 return NULL;
6075 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6078 if (!*fbo) {
6079 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6080 checkGLcall("glGenFramebuffersEXT()");
6082 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6083 checkGLcall("glBindFramebuffer()");
6086 /* TODO: Handle stencil attachments */
6087 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6088 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6090 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6091 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6092 checkGLcall("glFramebufferRenderbufferEXT()");
6093 } else {
6094 IWineD3DBaseTextureImpl *texture_impl;
6095 GLenum texttarget, target;
6096 GLint old_binding = 0;
6098 texttarget = depth_stencil_impl->glDescription.target;
6099 if(texttarget == GL_TEXTURE_2D) {
6100 target = GL_TEXTURE_2D;
6101 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6102 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6103 target = GL_TEXTURE_RECTANGLE_ARB;
6104 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6105 } else {
6106 target = GL_TEXTURE_CUBE_MAP_ARB;
6107 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6110 IWineD3DSurface_PreLoad(depth_stencil);
6112 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6113 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6114 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6115 glBindTexture(target, old_binding);
6117 /* Update base texture states array */
6118 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6119 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6120 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6121 if (texture_impl->baseTexture.bindCount) {
6122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6125 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6128 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6129 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6130 checkGLcall("glFramebufferTexture2DEXT()");
6134 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6135 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6136 IWineD3DBaseTextureImpl *texture_impl;
6137 GLenum texttarget, target;
6138 GLint old_binding;
6140 texttarget = surface_impl->glDescription.target;
6141 if(texttarget == GL_TEXTURE_2D) {
6142 target = GL_TEXTURE_2D;
6143 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6144 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6145 target = GL_TEXTURE_RECTANGLE_ARB;
6146 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6147 } else {
6148 target = GL_TEXTURE_CUBE_MAP_ARB;
6149 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6152 IWineD3DSurface_PreLoad(surface);
6154 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6155 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6156 glBindTexture(target, old_binding);
6158 /* Update base texture states array */
6159 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6160 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6161 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6162 if (texture_impl->baseTexture.bindCount) {
6163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6166 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6169 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6170 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6172 checkGLcall("attach_surface_fbo");
6175 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6177 IWineD3DSwapChain *swapchain;
6179 swapchain = get_swapchain(surface);
6180 if (swapchain) {
6181 GLenum buffer;
6183 TRACE("Surface %p is onscreen\n", surface);
6185 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6186 ENTER_GL();
6187 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6188 buffer = surface_get_gl_buffer(surface, swapchain);
6189 glDrawBuffer(buffer);
6190 checkGLcall("glDrawBuffer()");
6191 } else {
6192 TRACE("Surface %p is offscreen\n", surface);
6194 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6195 ENTER_GL();
6196 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6197 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6198 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6199 checkGLcall("glFramebufferRenderbufferEXT");
6202 if (rect) {
6203 glEnable(GL_SCISSOR_TEST);
6204 if(!swapchain) {
6205 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6206 } else {
6207 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6208 rect->x2 - rect->x1, rect->y2 - rect->y1);
6210 checkGLcall("glScissor");
6211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6212 } else {
6213 glDisable(GL_SCISSOR_TEST);
6215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6217 glDisable(GL_BLEND);
6218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6220 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6223 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6224 glClear(GL_COLOR_BUFFER_BIT);
6225 checkGLcall("glClear");
6227 if (This->render_offscreen) {
6228 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6229 } else {
6230 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6231 checkGLcall("glBindFramebuffer()");
6234 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6235 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6236 glDrawBuffer(GL_BACK);
6237 checkGLcall("glDrawBuffer()");
6240 LEAVE_GL();
6243 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6244 unsigned int r, g, b, a;
6245 DWORD ret;
6247 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6248 destfmt == WINED3DFMT_R8G8B8)
6249 return color;
6251 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6253 a = (color & 0xff000000) >> 24;
6254 r = (color & 0x00ff0000) >> 16;
6255 g = (color & 0x0000ff00) >> 8;
6256 b = (color & 0x000000ff) >> 0;
6258 switch(destfmt)
6260 case WINED3DFMT_R5G6B5:
6261 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6262 r = (r * 32) / 256;
6263 g = (g * 64) / 256;
6264 b = (b * 32) / 256;
6265 ret = r << 11;
6266 ret |= g << 5;
6267 ret |= b;
6268 TRACE("Returning %08x\n", ret);
6269 return ret;
6271 case WINED3DFMT_X1R5G5B5:
6272 case WINED3DFMT_A1R5G5B5:
6273 a = (a * 2) / 256;
6274 r = (r * 32) / 256;
6275 g = (g * 32) / 256;
6276 b = (b * 32) / 256;
6277 ret = a << 15;
6278 ret |= r << 10;
6279 ret |= g << 5;
6280 ret |= b << 0;
6281 TRACE("Returning %08x\n", ret);
6282 return ret;
6284 case WINED3DFMT_A8:
6285 TRACE("Returning %08x\n", a);
6286 return a;
6288 case WINED3DFMT_X4R4G4B4:
6289 case WINED3DFMT_A4R4G4B4:
6290 a = (a * 16) / 256;
6291 r = (r * 16) / 256;
6292 g = (g * 16) / 256;
6293 b = (b * 16) / 256;
6294 ret = a << 12;
6295 ret |= r << 8;
6296 ret |= g << 4;
6297 ret |= b << 0;
6298 TRACE("Returning %08x\n", ret);
6299 return ret;
6301 case WINED3DFMT_R3G3B2:
6302 r = (r * 8) / 256;
6303 g = (g * 8) / 256;
6304 b = (b * 4) / 256;
6305 ret = r << 5;
6306 ret |= g << 2;
6307 ret |= b << 0;
6308 TRACE("Returning %08x\n", ret);
6309 return ret;
6311 case WINED3DFMT_X8B8G8R8:
6312 case WINED3DFMT_A8B8G8R8:
6313 ret = a << 24;
6314 ret |= b << 16;
6315 ret |= g << 8;
6316 ret |= r << 0;
6317 TRACE("Returning %08x\n", ret);
6318 return ret;
6320 case WINED3DFMT_A2R10G10B10:
6321 a = (a * 4) / 256;
6322 r = (r * 1024) / 256;
6323 g = (g * 1024) / 256;
6324 b = (b * 1024) / 256;
6325 ret = a << 30;
6326 ret |= r << 20;
6327 ret |= g << 10;
6328 ret |= b << 0;
6329 TRACE("Returning %08x\n", ret);
6330 return ret;
6332 case WINED3DFMT_A2B10G10R10:
6333 a = (a * 4) / 256;
6334 r = (r * 1024) / 256;
6335 g = (g * 1024) / 256;
6336 b = (b * 1024) / 256;
6337 ret = a << 30;
6338 ret |= b << 20;
6339 ret |= g << 10;
6340 ret |= r << 0;
6341 TRACE("Returning %08x\n", ret);
6342 return ret;
6344 default:
6345 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6346 return 0;
6350 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6352 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6353 WINEDDBLTFX BltFx;
6354 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6356 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6357 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6358 return WINED3DERR_INVALIDCALL;
6361 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6362 color_fill_fbo(iface, pSurface, pRect, color);
6363 return WINED3D_OK;
6364 } else {
6365 /* Just forward this to the DirectDraw blitting engine */
6366 memset(&BltFx, 0, sizeof(BltFx));
6367 BltFx.dwSize = sizeof(BltFx);
6368 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6369 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6373 /* rendertarget and depth stencil functions */
6374 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6377 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6378 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6379 return WINED3DERR_INVALIDCALL;
6382 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6383 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6384 /* Note inc ref on returned surface */
6385 if(*ppRenderTarget != NULL)
6386 IWineD3DSurface_AddRef(*ppRenderTarget);
6387 return WINED3D_OK;
6390 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6392 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6393 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6394 IWineD3DSwapChainImpl *Swapchain;
6395 HRESULT hr;
6397 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6399 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6400 if(hr != WINED3D_OK) {
6401 ERR("Can't get the swapchain\n");
6402 return hr;
6405 /* Make sure to release the swapchain */
6406 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6408 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6409 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6410 return WINED3DERR_INVALIDCALL;
6412 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6413 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6414 return WINED3DERR_INVALIDCALL;
6417 if(Swapchain->frontBuffer != Front) {
6418 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6420 if(Swapchain->frontBuffer)
6421 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6422 Swapchain->frontBuffer = Front;
6424 if(Swapchain->frontBuffer) {
6425 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6429 if(Back && !Swapchain->backBuffer) {
6430 /* We need memory for the back buffer array - only one back buffer this way */
6431 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6432 if(!Swapchain->backBuffer) {
6433 ERR("Out of memory\n");
6434 return E_OUTOFMEMORY;
6438 if(Swapchain->backBuffer[0] != Back) {
6439 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6441 /* What to do about the context here in the case of multithreading? Not sure.
6442 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6444 ENTER_GL();
6445 if(!Swapchain->backBuffer[0]) {
6446 /* GL was told to draw to the front buffer at creation,
6447 * undo that
6449 glDrawBuffer(GL_BACK);
6450 checkGLcall("glDrawBuffer(GL_BACK)");
6451 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6452 Swapchain->presentParms.BackBufferCount = 1;
6453 } else if (!Back) {
6454 /* That makes problems - disable for now */
6455 /* glDrawBuffer(GL_FRONT); */
6456 checkGLcall("glDrawBuffer(GL_FRONT)");
6457 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6458 Swapchain->presentParms.BackBufferCount = 0;
6460 LEAVE_GL();
6462 if(Swapchain->backBuffer[0])
6463 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6464 Swapchain->backBuffer[0] = Back;
6466 if(Swapchain->backBuffer[0]) {
6467 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6468 } else {
6469 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6470 Swapchain->backBuffer = NULL;
6475 return WINED3D_OK;
6478 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6480 *ppZStencilSurface = This->stencilBufferTarget;
6481 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6483 if(*ppZStencilSurface != NULL) {
6484 /* Note inc ref on returned surface */
6485 IWineD3DSurface_AddRef(*ppZStencilSurface);
6486 return WINED3D_OK;
6487 } else {
6488 return WINED3DERR_NOTFOUND;
6492 /* TODO: Handle stencil attachments */
6493 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6496 TRACE("Set depth stencil to %p\n", depth_stencil);
6498 if (depth_stencil) {
6499 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6500 } else {
6501 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6502 checkGLcall("glFramebufferTexture2DEXT()");
6506 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6509 TRACE("Set render target %u to %p\n", idx, render_target);
6511 if (render_target) {
6512 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6513 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6514 } else {
6515 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6516 checkGLcall("glFramebufferTexture2DEXT()");
6518 This->draw_buffers[idx] = GL_NONE;
6522 static void check_fbo_status(IWineD3DDevice *iface) {
6523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6524 GLenum status;
6526 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6527 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6528 TRACE("FBO complete\n");
6529 } else {
6530 IWineD3DSurfaceImpl *attachment;
6531 int i;
6532 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6534 /* Dump the FBO attachments */
6535 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6536 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6537 if (attachment) {
6538 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6539 attachment->pow2Width, attachment->pow2Height);
6542 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6543 if (attachment) {
6544 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6545 attachment->pow2Width, attachment->pow2Height);
6550 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6552 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6553 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6555 if (!ds_impl) return FALSE;
6557 if (ds_impl->current_renderbuffer) {
6558 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6559 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6562 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6563 rt_impl->pow2Height != ds_impl->pow2Height);
6566 void apply_fbo_state(IWineD3DDevice *iface) {
6567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6568 unsigned int i;
6570 if (This->render_offscreen) {
6571 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6573 /* Apply render targets */
6574 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6575 IWineD3DSurface *render_target = This->render_targets[i];
6576 if (This->fbo_color_attachments[i] != render_target) {
6577 set_render_target_fbo(iface, i, render_target);
6578 This->fbo_color_attachments[i] = render_target;
6582 /* Apply depth targets */
6583 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6584 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6585 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6587 if (This->stencilBufferTarget) {
6588 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6590 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6591 This->fbo_depth_attachment = This->stencilBufferTarget;
6594 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6595 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6596 checkGLcall("glDrawBuffers()");
6597 } else {
6598 glDrawBuffer(This->draw_buffers[0]);
6599 checkGLcall("glDrawBuffer()");
6601 } else {
6602 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6605 check_fbo_status(iface);
6608 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6609 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6611 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6612 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6613 GLenum gl_filter;
6614 POINT offset = {0, 0};
6616 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6617 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6618 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6619 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6621 switch (filter) {
6622 case WINED3DTEXF_LINEAR:
6623 gl_filter = GL_LINEAR;
6624 break;
6626 default:
6627 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6628 case WINED3DTEXF_NONE:
6629 case WINED3DTEXF_POINT:
6630 gl_filter = GL_NEAREST;
6631 break;
6634 /* Attach src surface to src fbo */
6635 src_swapchain = get_swapchain(src_surface);
6636 if (src_swapchain) {
6637 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6639 TRACE("Source surface %p is onscreen\n", src_surface);
6640 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6641 /* Make sure the drawable is up to date. In the offscreen case
6642 * attach_surface_fbo() implicitly takes care of this. */
6643 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6645 if(buffer == GL_FRONT) {
6646 RECT windowsize;
6647 UINT h;
6648 ClientToScreen(This->ddraw_window, &offset);
6649 GetClientRect(This->ddraw_window, &windowsize);
6650 h = windowsize.bottom - windowsize.top;
6651 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6652 src_rect->y1 = offset.y + h - src_rect->y1;
6653 src_rect->y2 = offset.y + h - src_rect->y2;
6654 } else {
6655 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6656 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6659 ENTER_GL();
6660 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6661 glReadBuffer(buffer);
6662 checkGLcall("glReadBuffer()");
6663 } else {
6664 TRACE("Source surface %p is offscreen\n", src_surface);
6665 ENTER_GL();
6666 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6667 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6668 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6669 checkGLcall("glReadBuffer()");
6670 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6671 checkGLcall("glFramebufferRenderbufferEXT");
6673 LEAVE_GL();
6675 /* Attach dst surface to dst fbo */
6676 dst_swapchain = get_swapchain(dst_surface);
6677 if (dst_swapchain) {
6678 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6680 TRACE("Destination surface %p is onscreen\n", dst_surface);
6681 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6682 /* Make sure the drawable is up to date. In the offscreen case
6683 * attach_surface_fbo() implicitly takes care of this. */
6684 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6686 if(buffer == GL_FRONT) {
6687 RECT windowsize;
6688 UINT h;
6689 ClientToScreen(This->ddraw_window, &offset);
6690 GetClientRect(This->ddraw_window, &windowsize);
6691 h = windowsize.bottom - windowsize.top;
6692 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6693 dst_rect->y1 = offset.y + h - dst_rect->y1;
6694 dst_rect->y2 = offset.y + h - dst_rect->y2;
6695 } else {
6696 /* Screen coords = window coords, surface height = window height */
6697 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6698 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6701 ENTER_GL();
6702 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6703 glDrawBuffer(buffer);
6704 checkGLcall("glDrawBuffer()");
6705 } else {
6706 TRACE("Destination surface %p is offscreen\n", dst_surface);
6708 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6709 if(!src_swapchain) {
6710 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6713 ENTER_GL();
6714 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6715 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6716 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6717 checkGLcall("glDrawBuffer()");
6718 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6719 checkGLcall("glFramebufferRenderbufferEXT");
6721 glDisable(GL_SCISSOR_TEST);
6722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6724 if (flip) {
6725 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6726 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6727 checkGLcall("glBlitFramebuffer()");
6728 } else {
6729 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6730 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6731 checkGLcall("glBlitFramebuffer()");
6734 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6736 if (This->render_offscreen) {
6737 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6738 } else {
6739 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6740 checkGLcall("glBindFramebuffer()");
6743 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6744 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6745 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6746 glDrawBuffer(GL_BACK);
6747 checkGLcall("glDrawBuffer()");
6749 LEAVE_GL();
6752 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6754 WINED3DVIEWPORT viewport;
6756 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6758 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6759 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6760 This, RenderTargetIndex, GL_LIMITS(buffers));
6761 return WINED3DERR_INVALIDCALL;
6764 /* MSDN says that null disables the render target
6765 but a device must always be associated with a render target
6766 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6768 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6769 FIXME("Trying to set render target 0 to NULL\n");
6770 return WINED3DERR_INVALIDCALL;
6772 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6773 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);
6774 return WINED3DERR_INVALIDCALL;
6777 /* If we are trying to set what we already have, don't bother */
6778 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6779 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6780 return WINED3D_OK;
6782 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6783 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6784 This->render_targets[RenderTargetIndex] = pRenderTarget;
6786 /* Render target 0 is special */
6787 if(RenderTargetIndex == 0) {
6788 /* Finally, reset the viewport as the MSDN states. */
6789 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6790 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6791 viewport.X = 0;
6792 viewport.Y = 0;
6793 viewport.MaxZ = 1.0f;
6794 viewport.MinZ = 0.0f;
6795 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6796 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6797 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6799 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6801 return WINED3D_OK;
6804 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6806 HRESULT hr = WINED3D_OK;
6807 IWineD3DSurface *tmp;
6809 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6811 if (pNewZStencil == This->stencilBufferTarget) {
6812 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6813 } else {
6814 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6815 * depending on the renter target implementation being used.
6816 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6817 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6818 * stencil buffer and incur an extra memory overhead
6819 ******************************************************/
6821 if (This->stencilBufferTarget) {
6822 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6823 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6824 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6827 tmp = This->stencilBufferTarget;
6828 This->stencilBufferTarget = pNewZStencil;
6829 /* should we be calling the parent or the wined3d surface? */
6830 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6831 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6832 hr = WINED3D_OK;
6834 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6835 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6842 return hr;
6845 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6846 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6848 /* TODO: the use of Impl is deprecated. */
6849 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6850 WINED3DLOCKED_RECT lockedRect;
6852 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6854 /* some basic validation checks */
6855 if(This->cursorTexture) {
6856 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6857 ENTER_GL();
6858 glDeleteTextures(1, &This->cursorTexture);
6859 LEAVE_GL();
6860 This->cursorTexture = 0;
6863 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6864 This->haveHardwareCursor = TRUE;
6865 else
6866 This->haveHardwareCursor = FALSE;
6868 if(pCursorBitmap) {
6869 WINED3DLOCKED_RECT rect;
6871 /* MSDN: Cursor must be A8R8G8B8 */
6872 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6873 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6874 return WINED3DERR_INVALIDCALL;
6877 /* MSDN: Cursor must be smaller than the display mode */
6878 if(pSur->currentDesc.Width > This->ddraw_width ||
6879 pSur->currentDesc.Height > This->ddraw_height) {
6880 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);
6881 return WINED3DERR_INVALIDCALL;
6884 if (!This->haveHardwareCursor) {
6885 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6887 /* Do not store the surface's pointer because the application may
6888 * release it after setting the cursor image. Windows doesn't
6889 * addref the set surface, so we can't do this either without
6890 * creating circular refcount dependencies. Copy out the gl texture
6891 * instead.
6893 This->cursorWidth = pSur->currentDesc.Width;
6894 This->cursorHeight = pSur->currentDesc.Height;
6895 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6897 const GlPixelFormatDesc *glDesc;
6898 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6899 char *mem, *bits = (char *)rect.pBits;
6900 GLint intfmt = glDesc->glInternal;
6901 GLint format = glDesc->glFormat;
6902 GLint type = glDesc->glType;
6903 INT height = This->cursorHeight;
6904 INT width = This->cursorWidth;
6905 INT bpp = tableEntry->bpp;
6906 INT i, sampler;
6908 /* Reformat the texture memory (pitch and width can be
6909 * different) */
6910 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6911 for(i = 0; i < height; i++)
6912 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6913 IWineD3DSurface_UnlockRect(pCursorBitmap);
6914 ENTER_GL();
6916 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6917 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6918 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6921 /* Make sure that a proper texture unit is selected */
6922 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6923 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6924 checkGLcall("glActiveTextureARB");
6926 sampler = This->rev_tex_unit_map[0];
6927 if (sampler != -1) {
6928 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6930 /* Create a new cursor texture */
6931 glGenTextures(1, &This->cursorTexture);
6932 checkGLcall("glGenTextures");
6933 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6934 checkGLcall("glBindTexture");
6935 /* Copy the bitmap memory into the cursor texture */
6936 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6937 HeapFree(GetProcessHeap(), 0, mem);
6938 checkGLcall("glTexImage2D");
6940 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6941 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6942 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6945 LEAVE_GL();
6947 else
6949 FIXME("A cursor texture was not returned.\n");
6950 This->cursorTexture = 0;
6953 else
6955 /* Draw a hardware cursor */
6956 ICONINFO cursorInfo;
6957 HCURSOR cursor;
6958 /* Create and clear maskBits because it is not needed for
6959 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6960 * chunks. */
6961 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6962 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6963 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6964 WINED3DLOCK_NO_DIRTY_UPDATE |
6965 WINED3DLOCK_READONLY
6967 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6968 pSur->currentDesc.Height);
6970 cursorInfo.fIcon = FALSE;
6971 cursorInfo.xHotspot = XHotSpot;
6972 cursorInfo.yHotspot = YHotSpot;
6973 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6974 pSur->currentDesc.Height, 1,
6975 1, &maskBits);
6976 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6977 pSur->currentDesc.Height, 1,
6978 32, lockedRect.pBits);
6979 IWineD3DSurface_UnlockRect(pCursorBitmap);
6980 /* Create our cursor and clean up. */
6981 cursor = CreateIconIndirect(&cursorInfo);
6982 SetCursor(cursor);
6983 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6984 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6985 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6986 This->hardwareCursor = cursor;
6987 HeapFree(GetProcessHeap(), 0, maskBits);
6991 This->xHotSpot = XHotSpot;
6992 This->yHotSpot = YHotSpot;
6993 return WINED3D_OK;
6996 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6998 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7000 This->xScreenSpace = XScreenSpace;
7001 This->yScreenSpace = YScreenSpace;
7003 return;
7007 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7009 BOOL oldVisible = This->bCursorVisible;
7010 POINT pt;
7012 TRACE("(%p) : visible(%d)\n", This, bShow);
7015 * When ShowCursor is first called it should make the cursor appear at the OS's last
7016 * known cursor position. Because of this, some applications just repetitively call
7017 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7019 GetCursorPos(&pt);
7020 This->xScreenSpace = pt.x;
7021 This->yScreenSpace = pt.y;
7023 if (This->haveHardwareCursor) {
7024 This->bCursorVisible = bShow;
7025 if (bShow)
7026 SetCursor(This->hardwareCursor);
7027 else
7028 SetCursor(NULL);
7030 else
7032 if (This->cursorTexture)
7033 This->bCursorVisible = bShow;
7036 return oldVisible;
7039 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7041 IWineD3DResourceImpl *resource;
7042 TRACE("(%p) : state (%u)\n", This, This->state);
7044 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7045 switch (This->state) {
7046 case WINED3D_OK:
7047 return WINED3D_OK;
7048 case WINED3DERR_DEVICELOST:
7050 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7051 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7052 return WINED3DERR_DEVICENOTRESET;
7054 return WINED3DERR_DEVICELOST;
7056 case WINED3DERR_DRIVERINTERNALERROR:
7057 return WINED3DERR_DRIVERINTERNALERROR;
7060 /* Unknown state */
7061 return WINED3DERR_DRIVERINTERNALERROR;
7065 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7067 /** FIXME: Resource tracking needs to be done,
7068 * The closes we can do to this is set the priorities of all managed textures low
7069 * and then reset them.
7070 ***********************************************************/
7071 FIXME("(%p) : stub\n", This);
7072 return WINED3D_OK;
7075 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7076 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7078 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7079 if(surface->Flags & SFLAG_DIBSECTION) {
7080 /* Release the DC */
7081 SelectObject(surface->hDC, surface->dib.holdbitmap);
7082 DeleteDC(surface->hDC);
7083 /* Release the DIB section */
7084 DeleteObject(surface->dib.DIBsection);
7085 surface->dib.bitmap_data = NULL;
7086 surface->resource.allocatedMemory = NULL;
7087 surface->Flags &= ~SFLAG_DIBSECTION;
7089 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7090 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7091 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7092 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7093 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7094 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7095 } else {
7096 surface->pow2Width = surface->pow2Height = 1;
7097 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7098 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7100 surface->glRect.left = 0;
7101 surface->glRect.top = 0;
7102 surface->glRect.right = surface->pow2Width;
7103 surface->glRect.bottom = surface->pow2Height;
7105 if(surface->glDescription.textureName) {
7106 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7107 ENTER_GL();
7108 glDeleteTextures(1, &surface->glDescription.textureName);
7109 LEAVE_GL();
7110 surface->glDescription.textureName = 0;
7111 surface->Flags &= ~SFLAG_CLIENT;
7113 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7114 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7115 surface->Flags |= SFLAG_NONPOW2;
7116 } else {
7117 surface->Flags &= ~SFLAG_NONPOW2;
7119 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7120 surface->resource.allocatedMemory = NULL;
7121 surface->resource.heapMemory = NULL;
7122 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7123 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7124 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7125 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7126 } else {
7127 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7131 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7132 TRACE("Unloading resource %p\n", resource);
7133 IWineD3DResource_UnLoad(resource);
7134 IWineD3DResource_Release(resource);
7135 return S_OK;
7138 static void reset_fbo_state(IWineD3DDevice *iface) {
7139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7140 unsigned int i;
7142 ENTER_GL();
7143 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7144 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7146 if (This->fbo) {
7147 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7148 This->fbo = 0;
7150 if (This->src_fbo) {
7151 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7152 This->src_fbo = 0;
7154 if (This->dst_fbo) {
7155 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7156 This->dst_fbo = 0;
7158 checkGLcall("Tear down FBOs\n");
7159 LEAVE_GL();
7161 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7162 This->fbo_color_attachments[i] = NULL;
7164 This->fbo_depth_attachment = NULL;
7167 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7168 UINT i, count;
7169 WINED3DDISPLAYMODE m;
7170 HRESULT hr;
7172 /* All Windowed modes are supported, as is leaving the current mode */
7173 if(pp->Windowed) return TRUE;
7174 if(!pp->BackBufferWidth) return TRUE;
7175 if(!pp->BackBufferHeight) return TRUE;
7177 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7178 for(i = 0; i < count; i++) {
7179 memset(&m, 0, sizeof(m));
7180 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7181 if(FAILED(hr)) {
7182 ERR("EnumAdapterModes failed\n");
7184 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7185 /* Mode found, it is supported */
7186 return TRUE;
7189 /* Mode not found -> not supported */
7190 return FALSE;
7193 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7195 IWineD3DSwapChainImpl *swapchain;
7196 HRESULT hr;
7197 BOOL DisplayModeChanged = FALSE;
7198 WINED3DDISPLAYMODE mode;
7199 IWineD3DBaseShaderImpl *shader;
7200 IWineD3DSurfaceImpl *target;
7201 UINT i;
7202 TRACE("(%p)\n", This);
7204 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7205 if(FAILED(hr)) {
7206 ERR("Failed to get the first implicit swapchain\n");
7207 return hr;
7210 if(!is_display_mode_supported(This, pPresentationParameters)) {
7211 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7212 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7213 pPresentationParameters->BackBufferHeight);
7214 return WINED3DERR_INVALIDCALL;
7217 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7218 * on an existing gl context, so there's no real need for recreation.
7220 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7222 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7224 TRACE("New params:\n");
7225 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7226 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7227 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7228 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7229 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7230 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7231 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7232 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7233 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7234 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7235 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7236 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7237 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7239 /* No special treatment of these parameters. Just store them */
7240 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7241 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7242 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7243 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7245 /* What to do about these? */
7246 if(pPresentationParameters->BackBufferCount != 0 &&
7247 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7248 ERR("Cannot change the back buffer count yet\n");
7250 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7251 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7252 ERR("Cannot change the back buffer format yet\n");
7254 if(pPresentationParameters->hDeviceWindow != NULL &&
7255 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7256 ERR("Cannot change the device window yet\n");
7258 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7259 ERR("What do do about a changed auto depth stencil parameter?\n");
7262 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7263 reset_fbo_state((IWineD3DDevice *) This);
7266 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7267 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7268 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7271 ENTER_GL();
7272 if(This->depth_blt_texture) {
7273 glDeleteTextures(1, &This->depth_blt_texture);
7274 This->depth_blt_texture = 0;
7276 if (This->depth_blt_rb) {
7277 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7278 This->depth_blt_rb = 0;
7279 This->depth_blt_rb_w = 0;
7280 This->depth_blt_rb_h = 0;
7282 This->frag_pipe->free_private(iface);
7283 This->shader_backend->shader_free_private(iface);
7285 for (i = 0; i < GL_LIMITS(textures); i++) {
7286 /* Textures are recreated below */
7287 glDeleteTextures(1, &This->dummyTextureName[i]);
7288 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7289 This->dummyTextureName[i] = 0;
7291 LEAVE_GL();
7293 while(This->numContexts) {
7294 DestroyContext(This, This->contexts[0]);
7296 This->activeContext = NULL;
7297 HeapFree(GetProcessHeap(), 0, swapchain->context);
7298 swapchain->context = NULL;
7299 swapchain->num_contexts = 0;
7301 if(pPresentationParameters->Windowed) {
7302 mode.Width = swapchain->orig_width;
7303 mode.Height = swapchain->orig_height;
7304 mode.RefreshRate = 0;
7305 mode.Format = swapchain->presentParms.BackBufferFormat;
7306 } else {
7307 mode.Width = pPresentationParameters->BackBufferWidth;
7308 mode.Height = pPresentationParameters->BackBufferHeight;
7309 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7310 mode.Format = swapchain->presentParms.BackBufferFormat;
7313 /* Should Width == 800 && Height == 0 set 800x600? */
7314 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7315 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7316 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7318 WINED3DVIEWPORT vp;
7319 int i;
7321 vp.X = 0;
7322 vp.Y = 0;
7323 vp.Width = pPresentationParameters->BackBufferWidth;
7324 vp.Height = pPresentationParameters->BackBufferHeight;
7325 vp.MinZ = 0;
7326 vp.MaxZ = 1;
7328 if(!pPresentationParameters->Windowed) {
7329 DisplayModeChanged = TRUE;
7331 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7332 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7334 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7335 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7336 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7338 if(This->auto_depth_stencil_buffer) {
7339 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7343 /* Now set the new viewport */
7344 IWineD3DDevice_SetViewport(iface, &vp);
7347 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7348 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7349 DisplayModeChanged) {
7351 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7352 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7353 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7354 } else if(!pPresentationParameters->Windowed) {
7355 DWORD style = This->style, exStyle = This->exStyle;
7356 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7357 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7358 * Reset to clear up their mess. Guild Wars also loses the device during that.
7360 This->style = 0;
7361 This->exStyle = 0;
7362 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7363 This->style = style;
7364 This->exStyle = exStyle;
7367 /* Recreate the primary swapchain's context */
7368 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7369 if(swapchain->backBuffer) {
7370 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7371 } else {
7372 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7374 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7375 &swapchain->presentParms);
7376 swapchain->num_contexts = 1;
7377 This->activeContext = swapchain->context[0];
7378 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7380 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7381 if(FAILED(hr)) {
7382 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7384 create_dummy_textures(This);
7387 hr = This->shader_backend->shader_alloc_private(iface);
7388 if(FAILED(hr)) {
7389 ERR("Failed to recreate shader private data\n");
7390 return hr;
7392 hr = This->frag_pipe->alloc_private(iface);
7393 if(FAILED(hr)) {
7394 TRACE("Fragment pipeline private data couldn't be allocated\n");
7395 return hr;
7398 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7399 * first use
7401 return WINED3D_OK;
7404 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7406 /** FIXME: always true at the moment **/
7407 if(!bEnableDialogs) {
7408 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7410 return WINED3D_OK;
7414 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7416 TRACE("(%p) : pParameters %p\n", This, pParameters);
7418 *pParameters = This->createParms;
7419 return WINED3D_OK;
7422 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7423 IWineD3DSwapChain *swapchain;
7425 TRACE("Relaying to swapchain\n");
7427 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7428 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7429 IWineD3DSwapChain_Release(swapchain);
7431 return;
7434 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7435 IWineD3DSwapChain *swapchain;
7437 TRACE("Relaying to swapchain\n");
7439 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7440 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7441 IWineD3DSwapChain_Release(swapchain);
7443 return;
7447 /** ********************************************************
7448 * Notification functions
7449 ** ********************************************************/
7450 /** This function must be called in the release of a resource when ref == 0,
7451 * the contents of resource must still be correct,
7452 * any handles to other resource held by the caller must be closed
7453 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7454 *****************************************************/
7455 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7458 TRACE("(%p) : Adding Resource %p\n", This, resource);
7459 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7462 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7465 TRACE("(%p) : Removing resource %p\n", This, resource);
7467 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7471 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7473 int counter;
7475 TRACE("(%p) : resource %p\n", This, resource);
7476 switch(IWineD3DResource_GetType(resource)){
7477 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7478 case WINED3DRTYPE_SURFACE: {
7479 unsigned int i;
7481 /* Cleanup any FBO attachments if d3d is enabled */
7482 if(This->d3d_initialized) {
7483 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7484 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7486 TRACE("Last active render target destroyed\n");
7487 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7488 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7489 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7490 * and the lastActiveRenderTarget member shouldn't matter
7492 if(swapchain) {
7493 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7494 TRACE("Activating primary back buffer\n");
7495 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7496 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7497 /* Single buffering environment */
7498 TRACE("Activating primary front buffer\n");
7499 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7500 } else {
7501 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7502 /* Implicit render target destroyed, that means the device is being destroyed
7503 * whatever we set here, it shouldn't matter
7505 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7507 } else {
7508 /* May happen during ddraw uninitialization */
7509 TRACE("Render target set, but swapchain does not exist!\n");
7510 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7514 ENTER_GL();
7515 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7516 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7517 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7518 set_render_target_fbo(iface, i, NULL);
7519 This->fbo_color_attachments[i] = NULL;
7522 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7523 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7524 set_depth_stencil_fbo(iface, NULL);
7525 This->fbo_depth_attachment = NULL;
7527 LEAVE_GL();
7530 break;
7532 case WINED3DRTYPE_TEXTURE:
7533 case WINED3DRTYPE_CUBETEXTURE:
7534 case WINED3DRTYPE_VOLUMETEXTURE:
7535 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7536 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7537 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7538 This->stateBlock->textures[counter] = NULL;
7540 if (This->updateStateBlock != This->stateBlock ){
7541 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7542 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7543 This->updateStateBlock->textures[counter] = NULL;
7547 break;
7548 case WINED3DRTYPE_VOLUME:
7549 /* TODO: nothing really? */
7550 break;
7551 case WINED3DRTYPE_VERTEXBUFFER:
7552 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7554 int streamNumber;
7555 TRACE("Cleaning up stream pointers\n");
7557 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7558 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7559 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7561 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7562 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7563 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7564 This->updateStateBlock->streamSource[streamNumber] = 0;
7565 /* Set changed flag? */
7568 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) */
7569 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7570 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7571 This->stateBlock->streamSource[streamNumber] = 0;
7574 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7575 else { /* This shouldn't happen */
7576 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7578 #endif
7582 break;
7583 case WINED3DRTYPE_INDEXBUFFER:
7584 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7585 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7586 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7587 This->updateStateBlock->pIndexData = NULL;
7590 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7591 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7592 This->stateBlock->pIndexData = NULL;
7596 break;
7597 default:
7598 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7599 break;
7603 /* Remove the resource from the resourceStore */
7604 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7606 TRACE("Resource released\n");
7610 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7612 IWineD3DResourceImpl *resource, *cursor;
7613 HRESULT ret;
7614 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7616 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7617 TRACE("enumerating resource %p\n", resource);
7618 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7619 ret = pCallback((IWineD3DResource *) resource, pData);
7620 if(ret == S_FALSE) {
7621 TRACE("Canceling enumeration\n");
7622 break;
7625 return WINED3D_OK;
7628 /**********************************************************
7629 * IWineD3DDevice VTbl follows
7630 **********************************************************/
7632 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7634 /*** IUnknown methods ***/
7635 IWineD3DDeviceImpl_QueryInterface,
7636 IWineD3DDeviceImpl_AddRef,
7637 IWineD3DDeviceImpl_Release,
7638 /*** IWineD3DDevice methods ***/
7639 IWineD3DDeviceImpl_GetParent,
7640 /*** Creation methods**/
7641 IWineD3DDeviceImpl_CreateVertexBuffer,
7642 IWineD3DDeviceImpl_CreateIndexBuffer,
7643 IWineD3DDeviceImpl_CreateStateBlock,
7644 IWineD3DDeviceImpl_CreateSurface,
7645 IWineD3DDeviceImpl_CreateTexture,
7646 IWineD3DDeviceImpl_CreateVolumeTexture,
7647 IWineD3DDeviceImpl_CreateVolume,
7648 IWineD3DDeviceImpl_CreateCubeTexture,
7649 IWineD3DDeviceImpl_CreateQuery,
7650 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7651 IWineD3DDeviceImpl_CreateVertexDeclaration,
7652 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7653 IWineD3DDeviceImpl_CreateVertexShader,
7654 IWineD3DDeviceImpl_CreatePixelShader,
7655 IWineD3DDeviceImpl_CreatePalette,
7656 /*** Odd functions **/
7657 IWineD3DDeviceImpl_Init3D,
7658 IWineD3DDeviceImpl_Uninit3D,
7659 IWineD3DDeviceImpl_SetFullscreen,
7660 IWineD3DDeviceImpl_SetMultithreaded,
7661 IWineD3DDeviceImpl_EvictManagedResources,
7662 IWineD3DDeviceImpl_GetAvailableTextureMem,
7663 IWineD3DDeviceImpl_GetBackBuffer,
7664 IWineD3DDeviceImpl_GetCreationParameters,
7665 IWineD3DDeviceImpl_GetDeviceCaps,
7666 IWineD3DDeviceImpl_GetDirect3D,
7667 IWineD3DDeviceImpl_GetDisplayMode,
7668 IWineD3DDeviceImpl_SetDisplayMode,
7669 IWineD3DDeviceImpl_GetHWND,
7670 IWineD3DDeviceImpl_SetHWND,
7671 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7672 IWineD3DDeviceImpl_GetRasterStatus,
7673 IWineD3DDeviceImpl_GetSwapChain,
7674 IWineD3DDeviceImpl_Reset,
7675 IWineD3DDeviceImpl_SetDialogBoxMode,
7676 IWineD3DDeviceImpl_SetCursorProperties,
7677 IWineD3DDeviceImpl_SetCursorPosition,
7678 IWineD3DDeviceImpl_ShowCursor,
7679 IWineD3DDeviceImpl_TestCooperativeLevel,
7680 /*** Getters and setters **/
7681 IWineD3DDeviceImpl_SetClipPlane,
7682 IWineD3DDeviceImpl_GetClipPlane,
7683 IWineD3DDeviceImpl_SetClipStatus,
7684 IWineD3DDeviceImpl_GetClipStatus,
7685 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7686 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7687 IWineD3DDeviceImpl_SetDepthStencilSurface,
7688 IWineD3DDeviceImpl_GetDepthStencilSurface,
7689 IWineD3DDeviceImpl_SetFVF,
7690 IWineD3DDeviceImpl_GetFVF,
7691 IWineD3DDeviceImpl_SetGammaRamp,
7692 IWineD3DDeviceImpl_GetGammaRamp,
7693 IWineD3DDeviceImpl_SetIndices,
7694 IWineD3DDeviceImpl_GetIndices,
7695 IWineD3DDeviceImpl_SetBaseVertexIndex,
7696 IWineD3DDeviceImpl_GetBaseVertexIndex,
7697 IWineD3DDeviceImpl_SetLight,
7698 IWineD3DDeviceImpl_GetLight,
7699 IWineD3DDeviceImpl_SetLightEnable,
7700 IWineD3DDeviceImpl_GetLightEnable,
7701 IWineD3DDeviceImpl_SetMaterial,
7702 IWineD3DDeviceImpl_GetMaterial,
7703 IWineD3DDeviceImpl_SetNPatchMode,
7704 IWineD3DDeviceImpl_GetNPatchMode,
7705 IWineD3DDeviceImpl_SetPaletteEntries,
7706 IWineD3DDeviceImpl_GetPaletteEntries,
7707 IWineD3DDeviceImpl_SetPixelShader,
7708 IWineD3DDeviceImpl_GetPixelShader,
7709 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7710 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7711 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7712 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7713 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7714 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7715 IWineD3DDeviceImpl_SetRenderState,
7716 IWineD3DDeviceImpl_GetRenderState,
7717 IWineD3DDeviceImpl_SetRenderTarget,
7718 IWineD3DDeviceImpl_GetRenderTarget,
7719 IWineD3DDeviceImpl_SetFrontBackBuffers,
7720 IWineD3DDeviceImpl_SetSamplerState,
7721 IWineD3DDeviceImpl_GetSamplerState,
7722 IWineD3DDeviceImpl_SetScissorRect,
7723 IWineD3DDeviceImpl_GetScissorRect,
7724 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7725 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7726 IWineD3DDeviceImpl_SetStreamSource,
7727 IWineD3DDeviceImpl_GetStreamSource,
7728 IWineD3DDeviceImpl_SetStreamSourceFreq,
7729 IWineD3DDeviceImpl_GetStreamSourceFreq,
7730 IWineD3DDeviceImpl_SetTexture,
7731 IWineD3DDeviceImpl_GetTexture,
7732 IWineD3DDeviceImpl_SetTextureStageState,
7733 IWineD3DDeviceImpl_GetTextureStageState,
7734 IWineD3DDeviceImpl_SetTransform,
7735 IWineD3DDeviceImpl_GetTransform,
7736 IWineD3DDeviceImpl_SetVertexDeclaration,
7737 IWineD3DDeviceImpl_GetVertexDeclaration,
7738 IWineD3DDeviceImpl_SetVertexShader,
7739 IWineD3DDeviceImpl_GetVertexShader,
7740 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7741 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7742 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7743 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7744 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7745 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7746 IWineD3DDeviceImpl_SetViewport,
7747 IWineD3DDeviceImpl_GetViewport,
7748 IWineD3DDeviceImpl_MultiplyTransform,
7749 IWineD3DDeviceImpl_ValidateDevice,
7750 IWineD3DDeviceImpl_ProcessVertices,
7751 /*** State block ***/
7752 IWineD3DDeviceImpl_BeginStateBlock,
7753 IWineD3DDeviceImpl_EndStateBlock,
7754 /*** Scene management ***/
7755 IWineD3DDeviceImpl_BeginScene,
7756 IWineD3DDeviceImpl_EndScene,
7757 IWineD3DDeviceImpl_Present,
7758 IWineD3DDeviceImpl_Clear,
7759 /*** Drawing ***/
7760 IWineD3DDeviceImpl_DrawPrimitive,
7761 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7762 IWineD3DDeviceImpl_DrawPrimitiveUP,
7763 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7764 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7765 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7766 IWineD3DDeviceImpl_DrawRectPatch,
7767 IWineD3DDeviceImpl_DrawTriPatch,
7768 IWineD3DDeviceImpl_DeletePatch,
7769 IWineD3DDeviceImpl_ColorFill,
7770 IWineD3DDeviceImpl_UpdateTexture,
7771 IWineD3DDeviceImpl_UpdateSurface,
7772 IWineD3DDeviceImpl_GetFrontBufferData,
7773 /*** object tracking ***/
7774 IWineD3DDeviceImpl_ResourceReleased,
7775 IWineD3DDeviceImpl_EnumResources
7778 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7780 /*** IUnknown methods ***/
7781 IWineD3DDeviceImpl_QueryInterface,
7782 IWineD3DDeviceImpl_AddRef,
7783 IWineD3DDeviceImpl_Release,
7784 /*** IWineD3DDevice methods ***/
7785 IWineD3DDeviceImpl_GetParent,
7786 /*** Creation methods**/
7787 IWineD3DDeviceImpl_CreateVertexBuffer,
7788 IWineD3DDeviceImpl_CreateIndexBuffer,
7789 IWineD3DDeviceImpl_CreateStateBlock,
7790 IWineD3DDeviceImpl_CreateSurface,
7791 IWineD3DDeviceImpl_CreateTexture,
7792 IWineD3DDeviceImpl_CreateVolumeTexture,
7793 IWineD3DDeviceImpl_CreateVolume,
7794 IWineD3DDeviceImpl_CreateCubeTexture,
7795 IWineD3DDeviceImpl_CreateQuery,
7796 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7797 IWineD3DDeviceImpl_CreateVertexDeclaration,
7798 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7799 IWineD3DDeviceImpl_CreateVertexShader,
7800 IWineD3DDeviceImpl_CreatePixelShader,
7801 IWineD3DDeviceImpl_CreatePalette,
7802 /*** Odd functions **/
7803 IWineD3DDeviceImpl_Init3D,
7804 IWineD3DDeviceImpl_Uninit3D,
7805 IWineD3DDeviceImpl_SetFullscreen,
7806 IWineD3DDeviceImpl_SetMultithreaded,
7807 IWineD3DDeviceImpl_EvictManagedResources,
7808 IWineD3DDeviceImpl_GetAvailableTextureMem,
7809 IWineD3DDeviceImpl_GetBackBuffer,
7810 IWineD3DDeviceImpl_GetCreationParameters,
7811 IWineD3DDeviceImpl_GetDeviceCaps,
7812 IWineD3DDeviceImpl_GetDirect3D,
7813 IWineD3DDeviceImpl_GetDisplayMode,
7814 IWineD3DDeviceImpl_SetDisplayMode,
7815 IWineD3DDeviceImpl_GetHWND,
7816 IWineD3DDeviceImpl_SetHWND,
7817 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7818 IWineD3DDeviceImpl_GetRasterStatus,
7819 IWineD3DDeviceImpl_GetSwapChain,
7820 IWineD3DDeviceImpl_Reset,
7821 IWineD3DDeviceImpl_SetDialogBoxMode,
7822 IWineD3DDeviceImpl_SetCursorProperties,
7823 IWineD3DDeviceImpl_SetCursorPosition,
7824 IWineD3DDeviceImpl_ShowCursor,
7825 IWineD3DDeviceImpl_TestCooperativeLevel,
7826 /*** Getters and setters **/
7827 IWineD3DDeviceImpl_SetClipPlane,
7828 IWineD3DDeviceImpl_GetClipPlane,
7829 IWineD3DDeviceImpl_SetClipStatus,
7830 IWineD3DDeviceImpl_GetClipStatus,
7831 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7832 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7833 IWineD3DDeviceImpl_SetDepthStencilSurface,
7834 IWineD3DDeviceImpl_GetDepthStencilSurface,
7835 IWineD3DDeviceImpl_SetFVF,
7836 IWineD3DDeviceImpl_GetFVF,
7837 IWineD3DDeviceImpl_SetGammaRamp,
7838 IWineD3DDeviceImpl_GetGammaRamp,
7839 IWineD3DDeviceImpl_SetIndices,
7840 IWineD3DDeviceImpl_GetIndices,
7841 IWineD3DDeviceImpl_SetBaseVertexIndex,
7842 IWineD3DDeviceImpl_GetBaseVertexIndex,
7843 IWineD3DDeviceImpl_SetLight,
7844 IWineD3DDeviceImpl_GetLight,
7845 IWineD3DDeviceImpl_SetLightEnable,
7846 IWineD3DDeviceImpl_GetLightEnable,
7847 IWineD3DDeviceImpl_SetMaterial,
7848 IWineD3DDeviceImpl_GetMaterial,
7849 IWineD3DDeviceImpl_SetNPatchMode,
7850 IWineD3DDeviceImpl_GetNPatchMode,
7851 IWineD3DDeviceImpl_SetPaletteEntries,
7852 IWineD3DDeviceImpl_GetPaletteEntries,
7853 IWineD3DDeviceImpl_SetPixelShader,
7854 IWineD3DDeviceImpl_GetPixelShader,
7855 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7856 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7857 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7858 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7859 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7860 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7861 IWineD3DDeviceImpl_SetRenderState,
7862 IWineD3DDeviceImpl_GetRenderState,
7863 IWineD3DDeviceImpl_SetRenderTarget,
7864 IWineD3DDeviceImpl_GetRenderTarget,
7865 IWineD3DDeviceImpl_SetFrontBackBuffers,
7866 IWineD3DDeviceImpl_SetSamplerState,
7867 IWineD3DDeviceImpl_GetSamplerState,
7868 IWineD3DDeviceImpl_SetScissorRect,
7869 IWineD3DDeviceImpl_GetScissorRect,
7870 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7871 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7872 IWineD3DDeviceImpl_SetStreamSource,
7873 IWineD3DDeviceImpl_GetStreamSource,
7874 IWineD3DDeviceImpl_SetStreamSourceFreq,
7875 IWineD3DDeviceImpl_GetStreamSourceFreq,
7876 IWineD3DDeviceImpl_SetTexture,
7877 IWineD3DDeviceImpl_GetTexture,
7878 IWineD3DDeviceImpl_SetTextureStageState,
7879 IWineD3DDeviceImpl_GetTextureStageState,
7880 IWineD3DDeviceImpl_SetTransform,
7881 IWineD3DDeviceImpl_GetTransform,
7882 IWineD3DDeviceImpl_SetVertexDeclaration,
7883 IWineD3DDeviceImpl_GetVertexDeclaration,
7884 IWineD3DDeviceImpl_SetVertexShader,
7885 IWineD3DDeviceImpl_GetVertexShader,
7886 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7887 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7888 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7889 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7890 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7891 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7892 IWineD3DDeviceImpl_SetViewport,
7893 IWineD3DDeviceImpl_GetViewport,
7894 IWineD3DDeviceImpl_MultiplyTransform,
7895 IWineD3DDeviceImpl_ValidateDevice,
7896 IWineD3DDeviceImpl_ProcessVertices,
7897 /*** State block ***/
7898 IWineD3DDeviceImpl_BeginStateBlock,
7899 IWineD3DDeviceImpl_EndStateBlock,
7900 /*** Scene management ***/
7901 IWineD3DDeviceImpl_BeginScene,
7902 IWineD3DDeviceImpl_EndScene,
7903 IWineD3DDeviceImpl_Present,
7904 IWineD3DDeviceImpl_Clear,
7905 /*** Drawing ***/
7906 IWineD3DDeviceImpl_DrawPrimitive,
7907 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7908 IWineD3DDeviceImpl_DrawPrimitiveUP,
7909 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7910 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7911 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7912 IWineD3DDeviceImpl_DrawRectPatch,
7913 IWineD3DDeviceImpl_DrawTriPatch,
7914 IWineD3DDeviceImpl_DeletePatch,
7915 IWineD3DDeviceImpl_ColorFill,
7916 IWineD3DDeviceImpl_UpdateTexture,
7917 IWineD3DDeviceImpl_UpdateSurface,
7918 IWineD3DDeviceImpl_GetFrontBufferData,
7919 /*** object tracking ***/
7920 IWineD3DDeviceImpl_ResourceReleased,
7921 IWineD3DDeviceImpl_EnumResources
7924 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7925 WINED3DRS_ALPHABLENDENABLE ,
7926 WINED3DRS_ALPHAFUNC ,
7927 WINED3DRS_ALPHAREF ,
7928 WINED3DRS_ALPHATESTENABLE ,
7929 WINED3DRS_BLENDOP ,
7930 WINED3DRS_COLORWRITEENABLE ,
7931 WINED3DRS_DESTBLEND ,
7932 WINED3DRS_DITHERENABLE ,
7933 WINED3DRS_FILLMODE ,
7934 WINED3DRS_FOGDENSITY ,
7935 WINED3DRS_FOGEND ,
7936 WINED3DRS_FOGSTART ,
7937 WINED3DRS_LASTPIXEL ,
7938 WINED3DRS_SHADEMODE ,
7939 WINED3DRS_SRCBLEND ,
7940 WINED3DRS_STENCILENABLE ,
7941 WINED3DRS_STENCILFAIL ,
7942 WINED3DRS_STENCILFUNC ,
7943 WINED3DRS_STENCILMASK ,
7944 WINED3DRS_STENCILPASS ,
7945 WINED3DRS_STENCILREF ,
7946 WINED3DRS_STENCILWRITEMASK ,
7947 WINED3DRS_STENCILZFAIL ,
7948 WINED3DRS_TEXTUREFACTOR ,
7949 WINED3DRS_WRAP0 ,
7950 WINED3DRS_WRAP1 ,
7951 WINED3DRS_WRAP2 ,
7952 WINED3DRS_WRAP3 ,
7953 WINED3DRS_WRAP4 ,
7954 WINED3DRS_WRAP5 ,
7955 WINED3DRS_WRAP6 ,
7956 WINED3DRS_WRAP7 ,
7957 WINED3DRS_ZENABLE ,
7958 WINED3DRS_ZFUNC ,
7959 WINED3DRS_ZWRITEENABLE
7962 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7963 WINED3DTSS_ADDRESSW ,
7964 WINED3DTSS_ALPHAARG0 ,
7965 WINED3DTSS_ALPHAARG1 ,
7966 WINED3DTSS_ALPHAARG2 ,
7967 WINED3DTSS_ALPHAOP ,
7968 WINED3DTSS_BUMPENVLOFFSET ,
7969 WINED3DTSS_BUMPENVLSCALE ,
7970 WINED3DTSS_BUMPENVMAT00 ,
7971 WINED3DTSS_BUMPENVMAT01 ,
7972 WINED3DTSS_BUMPENVMAT10 ,
7973 WINED3DTSS_BUMPENVMAT11 ,
7974 WINED3DTSS_COLORARG0 ,
7975 WINED3DTSS_COLORARG1 ,
7976 WINED3DTSS_COLORARG2 ,
7977 WINED3DTSS_COLOROP ,
7978 WINED3DTSS_RESULTARG ,
7979 WINED3DTSS_TEXCOORDINDEX ,
7980 WINED3DTSS_TEXTURETRANSFORMFLAGS
7983 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7984 WINED3DSAMP_ADDRESSU ,
7985 WINED3DSAMP_ADDRESSV ,
7986 WINED3DSAMP_ADDRESSW ,
7987 WINED3DSAMP_BORDERCOLOR ,
7988 WINED3DSAMP_MAGFILTER ,
7989 WINED3DSAMP_MINFILTER ,
7990 WINED3DSAMP_MIPFILTER ,
7991 WINED3DSAMP_MIPMAPLODBIAS ,
7992 WINED3DSAMP_MAXMIPLEVEL ,
7993 WINED3DSAMP_MAXANISOTROPY ,
7994 WINED3DSAMP_SRGBTEXTURE ,
7995 WINED3DSAMP_ELEMENTINDEX
7998 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7999 WINED3DRS_AMBIENT ,
8000 WINED3DRS_AMBIENTMATERIALSOURCE ,
8001 WINED3DRS_CLIPPING ,
8002 WINED3DRS_CLIPPLANEENABLE ,
8003 WINED3DRS_COLORVERTEX ,
8004 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8005 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8006 WINED3DRS_FOGDENSITY ,
8007 WINED3DRS_FOGEND ,
8008 WINED3DRS_FOGSTART ,
8009 WINED3DRS_FOGTABLEMODE ,
8010 WINED3DRS_FOGVERTEXMODE ,
8011 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8012 WINED3DRS_LIGHTING ,
8013 WINED3DRS_LOCALVIEWER ,
8014 WINED3DRS_MULTISAMPLEANTIALIAS ,
8015 WINED3DRS_MULTISAMPLEMASK ,
8016 WINED3DRS_NORMALIZENORMALS ,
8017 WINED3DRS_PATCHEDGESTYLE ,
8018 WINED3DRS_POINTSCALE_A ,
8019 WINED3DRS_POINTSCALE_B ,
8020 WINED3DRS_POINTSCALE_C ,
8021 WINED3DRS_POINTSCALEENABLE ,
8022 WINED3DRS_POINTSIZE ,
8023 WINED3DRS_POINTSIZE_MAX ,
8024 WINED3DRS_POINTSIZE_MIN ,
8025 WINED3DRS_POINTSPRITEENABLE ,
8026 WINED3DRS_RANGEFOGENABLE ,
8027 WINED3DRS_SPECULARMATERIALSOURCE ,
8028 WINED3DRS_TWEENFACTOR ,
8029 WINED3DRS_VERTEXBLEND ,
8030 WINED3DRS_CULLMODE ,
8031 WINED3DRS_FOGCOLOR
8034 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8035 WINED3DTSS_TEXCOORDINDEX ,
8036 WINED3DTSS_TEXTURETRANSFORMFLAGS
8039 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8040 WINED3DSAMP_DMAPOFFSET
8043 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8044 DWORD rep = This->StateTable[state].representative;
8045 DWORD idx;
8046 BYTE shift;
8047 UINT i;
8048 WineD3DContext *context;
8050 if(!rep) return;
8051 for(i = 0; i < This->numContexts; i++) {
8052 context = This->contexts[i];
8053 if(isStateDirty(context, rep)) continue;
8055 context->dirtyArray[context->numDirtyEntries++] = rep;
8056 idx = rep >> 5;
8057 shift = rep & 0x1f;
8058 context->isStateDirty[idx] |= (1 << shift);
8062 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8063 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8064 /* The drawable size of a pbuffer render target is the current pbuffer size
8066 *width = dev->pbufferWidth;
8067 *height = dev->pbufferHeight;
8070 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8071 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8073 *width = This->pow2Width;
8074 *height = This->pow2Height;
8077 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8078 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8079 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8080 * current context's drawable, which is the size of the back buffer of the swapchain
8081 * the active context belongs to. The back buffer of the swapchain is stored as the
8082 * surface the context belongs to.
8084 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8085 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;