wined3d: RENDERTARGET | AUTOGENMIPMAP are compatible.
[wine/multimedia.git] / dlls / wined3d / device.c
blob416e82815c98b4feb80ddd8406c99b099f7d5747
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 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
195 This = NULL;
197 return refCount;
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
207 return WINED3D_OK;
210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
211 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
212 IUnknown *parent) {
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 IWineD3DVertexBufferImpl *object;
215 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
216 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
217 BOOL conv;
219 if(Size == 0) {
220 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
221 *ppVertexBuffer = NULL;
222 return WINED3DERR_INVALIDCALL;
223 } else if(Pool == WINED3DPOOL_SCRATCH) {
224 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
225 * anyway, SCRATCH vertex buffers aren't usable anywhere
227 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
228 *ppVertexBuffer = NULL;
229 return WINED3DERR_INVALIDCALL;
232 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
234 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);
235 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
237 object->fvf = FVF;
239 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
240 * drawStridedFast (half-life 2).
242 * Basically converting the vertices in the buffer is quite expensive, and observations
243 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
244 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
246 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
247 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
248 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
249 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
250 * dx7 apps.
251 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
252 * more. In this call we can convert dx7 buffers too.
254 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
255 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
256 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
257 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
258 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
259 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
260 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
261 } else if(dxVersion <= 7 && conv) {
262 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
263 } else {
264 object->Flags |= VBFLAG_CREATEVBO;
266 return WINED3D_OK;
269 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
270 GLenum error, glUsage;
271 TRACE("Creating VBO for Index Buffer %p\n", object);
273 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
274 * restored on the next draw
276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
278 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
279 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
280 ENTER_GL();
282 while(glGetError());
284 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
285 error = glGetError();
286 if(error != GL_NO_ERROR || object->vbo == 0) {
287 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
288 goto out;
291 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
295 goto out;
298 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
299 * copy no readback will be needed
301 glUsage = GL_STATIC_DRAW_ARB;
302 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
303 error = glGetError();
304 if(error != GL_NO_ERROR) {
305 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
306 goto out;
308 LEAVE_GL();
309 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
310 return;
312 out:
313 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
314 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
315 LEAVE_GL();
316 object->vbo = 0;
319 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
320 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
321 HANDLE *sharedHandle, IUnknown *parent) {
322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
323 IWineD3DIndexBufferImpl *object;
324 TRACE("(%p) Creating index buffer\n", This);
326 /* Allocate the storage for the device */
327 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
329 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
330 CreateIndexBufferVBO(This, object);
333 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
334 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
335 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
337 return WINED3D_OK;
340 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
343 IWineD3DStateBlockImpl *object;
344 int i, j;
345 HRESULT temp_result;
347 D3DCREATEOBJECTINSTANCE(object, StateBlock)
348 object->blockType = Type;
350 for(i = 0; i < LIGHTMAP_SIZE; i++) {
351 list_init(&object->lightMap[i]);
354 /* Special case - Used during initialization to produce a placeholder stateblock
355 so other functions called can update a state block */
356 if (Type == WINED3DSBT_INIT) {
357 /* Don't bother increasing the reference count otherwise a device will never
358 be freed due to circular dependencies */
359 return WINED3D_OK;
362 temp_result = allocate_shader_constants(object);
363 if (WINED3D_OK != temp_result)
364 return temp_result;
366 /* Otherwise, might as well set the whole state block to the appropriate values */
367 if (This->stateBlock != NULL)
368 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
369 else
370 memset(object->streamFreq, 1, sizeof(object->streamFreq));
372 /* Reset the ref and type after kludging it */
373 object->wineD3DDevice = This;
374 object->ref = 1;
375 object->blockType = Type;
377 TRACE("Updating changed flags appropriate for type %d\n", Type);
379 if (Type == WINED3DSBT_ALL) {
381 TRACE("ALL => Pretend everything has changed\n");
382 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
384 /* Lights are not part of the changed / set structure */
385 for(j = 0; j < LIGHTMAP_SIZE; j++) {
386 struct list *e;
387 LIST_FOR_EACH(e, &object->lightMap[j]) {
388 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
389 light->changed = TRUE;
390 light->enabledChanged = TRUE;
393 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
394 object->contained_render_states[j - 1] = j;
396 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
397 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
398 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
399 object->contained_transform_states[j - 1] = j;
401 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
402 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
403 object->contained_vs_consts_f[j] = j;
405 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_vs_consts_i[j] = j;
409 object->num_contained_vs_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_vs_consts_b[j] = j;
413 object->num_contained_vs_consts_b = MAX_CONST_B;
414 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
415 object->contained_ps_consts_f[j] = j;
417 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
418 for(j = 0; j < MAX_CONST_I; j++) {
419 object->contained_ps_consts_i[j] = j;
421 object->num_contained_ps_consts_i = MAX_CONST_I;
422 for(j = 0; j < MAX_CONST_B; j++) {
423 object->contained_ps_consts_b[j] = j;
425 object->num_contained_ps_consts_b = MAX_CONST_B;
426 for(i = 0; i < MAX_TEXTURES; i++) {
427 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
428 object->contained_tss_states[object->num_contained_tss_states].stage = i;
429 object->contained_tss_states[object->num_contained_tss_states].state = j;
430 object->num_contained_tss_states++;
433 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
434 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
435 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
436 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
437 object->num_contained_sampler_states++;
441 for(i = 0; i < MAX_STREAMS; i++) {
442 if(object->streamSource[i]) {
443 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
446 if(object->pIndexData) {
447 IWineD3DIndexBuffer_AddRef(object->pIndexData);
449 if(object->vertexShader) {
450 IWineD3DVertexShader_AddRef(object->vertexShader);
452 if(object->pixelShader) {
453 IWineD3DPixelShader_AddRef(object->pixelShader);
456 } else if (Type == WINED3DSBT_PIXELSTATE) {
458 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
461 object->changed.pixelShader = TRUE;
463 /* Pixel Shader Constants */
464 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
465 object->contained_ps_consts_f[i] = i;
466 object->changed.pixelShaderConstantsF[i] = TRUE;
468 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
469 for (i = 0; i < MAX_CONST_B; ++i) {
470 object->contained_ps_consts_b[i] = i;
471 object->changed.pixelShaderConstantsB[i] = TRUE;
473 object->num_contained_ps_consts_b = MAX_CONST_B;
474 for (i = 0; i < MAX_CONST_I; ++i) {
475 object->contained_ps_consts_i[i] = i;
476 object->changed.pixelShaderConstantsI[i] = TRUE;
478 object->num_contained_ps_consts_i = MAX_CONST_I;
480 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
481 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
482 object->contained_render_states[i] = SavedPixelStates_R[i];
484 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
485 for (j = 0; j < MAX_TEXTURES; j++) {
486 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
487 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
488 object->contained_tss_states[object->num_contained_tss_states].stage = j;
489 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
490 object->num_contained_tss_states++;
493 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
494 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
495 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
496 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
497 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
498 object->num_contained_sampler_states++;
501 if(object->pixelShader) {
502 IWineD3DPixelShader_AddRef(object->pixelShader);
505 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
506 * on them. This makes releasing the buffer easier
508 for(i = 0; i < MAX_STREAMS; i++) {
509 object->streamSource[i] = NULL;
511 object->pIndexData = NULL;
512 object->vertexShader = NULL;
514 } else if (Type == WINED3DSBT_VERTEXSTATE) {
516 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
517 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
519 object->changed.vertexShader = TRUE;
521 /* Vertex Shader Constants */
522 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
523 object->changed.vertexShaderConstantsF[i] = TRUE;
524 object->contained_vs_consts_f[i] = i;
526 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
527 for (i = 0; i < MAX_CONST_B; ++i) {
528 object->changed.vertexShaderConstantsB[i] = TRUE;
529 object->contained_vs_consts_b[i] = i;
531 object->num_contained_vs_consts_b = MAX_CONST_B;
532 for (i = 0; i < MAX_CONST_I; ++i) {
533 object->changed.vertexShaderConstantsI[i] = TRUE;
534 object->contained_vs_consts_i[i] = i;
536 object->num_contained_vs_consts_i = MAX_CONST_I;
537 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
538 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
539 object->contained_render_states[i] = SavedVertexStates_R[i];
541 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
542 for (j = 0; j < MAX_TEXTURES; j++) {
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
544 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
545 object->contained_tss_states[object->num_contained_tss_states].stage = j;
546 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
547 object->num_contained_tss_states++;
550 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
551 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
552 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
553 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
554 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
555 object->num_contained_sampler_states++;
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
560 struct list *e;
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
568 for(i = 0; i < MAX_STREAMS; i++) {
569 if(object->streamSource[i]) {
570 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
573 if(object->vertexShader) {
574 IWineD3DVertexShader_AddRef(object->vertexShader);
576 object->pIndexData = NULL;
577 object->pixelShader = NULL;
578 } else {
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
583 return WINED3D_OK;
586 /* ************************************
587 MSDN:
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
590 Discard
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 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) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int Size = 1;
601 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
602 TRACE("(%p) Create surface\n",This);
604 /** FIXME: Check ranges on the inputs are valid
605 * MSDN
606 * MultisampleQuality
607 * [in] Quality level. The valid range is between zero and one less than the level
608 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
609 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
610 * values of paired render targets, depth stencil surfaces, and the MultiSample type
611 * must all match.
612 *******************************/
616 * TODO: Discard MSDN
617 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
619 * If this flag is set, the contents of the depth stencil buffer will be
620 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
621 * with a different depth surface.
623 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
624 ***************************/
626 if(MultisampleQuality > 0) {
627 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
628 MultisampleQuality=0;
631 /** FIXME: Check that the format is supported
632 * by the device.
633 *******************************/
635 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
636 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
637 * space!
638 *********************************/
639 if (WINED3DFMT_UNKNOWN == Format) {
640 Size = 0;
641 } else if (Format == WINED3DFMT_DXT1) {
642 /* DXT1 is half byte per pixel */
643 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
645 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
646 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
647 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
648 } else {
649 /* The pitch is a multiple of 4 bytes */
650 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
651 Size *= Height;
654 /** Create and initialise the surface resource **/
655 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
656 /* "Standalone" surface */
657 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
659 object->currentDesc.Width = Width;
660 object->currentDesc.Height = Height;
661 object->currentDesc.MultiSampleType = MultiSample;
662 object->currentDesc.MultiSampleQuality = MultisampleQuality;
663 object->glDescription.level = Level;
665 /* Flags */
666 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
674 } else {
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
686 switch(Pool) {
687 case WINED3DPOOL_SCRATCH:
688 if(!Lockable)
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
691 Lockable = TRUE;
692 break;
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
700 break;
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 break;
706 default:
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
708 break;
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
722 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
723 This->ddraw_primary = (IWineD3DSurface *) object;
725 /* Look at the implementation and set the correct Vtable */
726 switch(Impl) {
727 case SURFACE_OPENGL:
728 /* Check if a 3D adapter is available when creating gl surfaces */
729 if(!This->adapter) {
730 ERR("OpenGL surfaces are not available without opengl\n");
731 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
732 HeapFree(GetProcessHeap(), 0, object);
733 return WINED3DERR_NOTAVAILABLE;
735 break;
737 case SURFACE_GDI:
738 object->lpVtbl = &IWineGDISurface_Vtbl;
739 break;
741 default:
742 /* To be sure to catch this */
743 ERR("Unknown requested surface implementation %d!\n", Impl);
744 IWineD3DSurface_Release((IWineD3DSurface *) object);
745 return WINED3DERR_INVALIDCALL;
748 list_init(&object->renderbuffers);
750 /* Call the private setup routine */
751 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
756 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
757 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
758 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DTextureImpl *object;
762 unsigned int i;
763 UINT tmpW;
764 UINT tmpH;
765 HRESULT hr;
766 unsigned int pow2Width;
767 unsigned int pow2Height;
768 const GlPixelFormatDesc *glDesc;
769 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
771 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
772 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
773 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
775 /* TODO: It should only be possible to create textures for formats
776 that are reported as supported */
777 if (WINED3DFMT_UNKNOWN >= Format) {
778 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
779 return WINED3DERR_INVALIDCALL;
782 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
783 D3DINITIALIZEBASETEXTURE(object->baseTexture);
784 object->width = Width;
785 object->height = Height;
787 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
788 object->baseTexture.minMipLookup = &minMipLookup;
789 object->baseTexture.magLookup = &magLookup;
790 } else {
791 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
792 object->baseTexture.magLookup = &magLookup_noFilter;
795 /** Non-power2 support **/
796 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
797 pow2Width = Width;
798 pow2Height = Height;
799 } else {
800 /* Find the nearest pow2 match */
801 pow2Width = pow2Height = 1;
802 while (pow2Width < Width) pow2Width <<= 1;
803 while (pow2Height < Height) pow2Height <<= 1;
805 if(pow2Width != Width || pow2Height != Height) {
806 if(Levels > 1) {
807 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
808 HeapFree(GetProcessHeap(), 0, object);
809 *ppTexture = NULL;
810 return WINED3DERR_INVALIDCALL;
811 } else {
812 Levels = 1;
817 /** FIXME: add support for real non-power-two if it's provided by the video card **/
818 /* Precalculated scaling for 'faked' non power of two texture coords.
819 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
820 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
821 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
823 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
824 (Width != pow2Width || Height != pow2Height) &&
825 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
827 object->baseTexture.pow2Matrix[0] = (float)Width;
828 object->baseTexture.pow2Matrix[5] = (float)Height;
829 object->baseTexture.pow2Matrix[10] = 1.0;
830 object->baseTexture.pow2Matrix[15] = 1.0;
831 object->target = GL_TEXTURE_RECTANGLE_ARB;
832 } else {
833 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
834 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
835 object->baseTexture.pow2Matrix[10] = 1.0;
836 object->baseTexture.pow2Matrix[15] = 1.0;
837 object->target = GL_TEXTURE_2D;
839 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
841 /* Calculate levels for mip mapping */
842 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
843 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
844 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
845 return WINED3DERR_INVALIDCALL;
847 if(Levels > 1) {
848 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
849 return WINED3DERR_INVALIDCALL;
851 object->baseTexture.levels = 1;
852 } else if (Levels == 0) {
853 TRACE("calculating levels %d\n", object->baseTexture.levels);
854 object->baseTexture.levels++;
855 tmpW = Width;
856 tmpH = Height;
857 while (tmpW > 1 || tmpH > 1) {
858 tmpW = max(1, tmpW >> 1);
859 tmpH = max(1, tmpH >> 1);
860 object->baseTexture.levels++;
862 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
865 /* Generate all the surfaces */
866 tmpW = Width;
867 tmpH = Height;
868 for (i = 0; i < object->baseTexture.levels; i++)
870 /* use the callback to create the texture surface */
871 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
872 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
873 FIXME("Failed to create surface %p\n", object);
874 /* clean up */
875 object->surfaces[i] = NULL;
876 IWineD3DTexture_Release((IWineD3DTexture *)object);
878 *ppTexture = NULL;
879 return hr;
882 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
883 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
884 /* calculate the next mipmap level */
885 tmpW = max(1, tmpW >> 1);
886 tmpH = max(1, tmpH >> 1);
888 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
890 TRACE("(%p) : Created texture %p\n", This, object);
891 return WINED3D_OK;
894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
895 UINT Width, UINT Height, UINT Depth,
896 UINT Levels, DWORD Usage,
897 WINED3DFORMAT Format, WINED3DPOOL Pool,
898 IWineD3DVolumeTexture **ppVolumeTexture,
899 HANDLE *pSharedHandle, IUnknown *parent,
900 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
903 IWineD3DVolumeTextureImpl *object;
904 unsigned int i;
905 UINT tmpW;
906 UINT tmpH;
907 UINT tmpD;
908 const GlPixelFormatDesc *glDesc;
910 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
912 /* TODO: It should only be possible to create textures for formats
913 that are reported as supported */
914 if (WINED3DFMT_UNKNOWN >= Format) {
915 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
916 return WINED3DERR_INVALIDCALL;
918 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
919 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
920 return WINED3DERR_INVALIDCALL;
923 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
924 D3DINITIALIZEBASETEXTURE(object->baseTexture);
926 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
927 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
929 object->width = Width;
930 object->height = Height;
931 object->depth = Depth;
933 /* Is NP2 support for volumes needed? */
934 object->baseTexture.pow2Matrix[ 0] = 1.0;
935 object->baseTexture.pow2Matrix[ 5] = 1.0;
936 object->baseTexture.pow2Matrix[10] = 1.0;
937 object->baseTexture.pow2Matrix[15] = 1.0;
939 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
940 object->baseTexture.minMipLookup = &minMipLookup;
941 object->baseTexture.magLookup = &magLookup;
942 } else {
943 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
944 object->baseTexture.magLookup = &magLookup_noFilter;
947 /* Calculate levels for mip mapping */
948 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
949 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
950 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
951 return WINED3DERR_INVALIDCALL;
953 if(Levels > 1) {
954 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
955 return WINED3DERR_INVALIDCALL;
957 Levels = 1;
958 } else if (Levels == 0) {
959 object->baseTexture.levels++;
960 tmpW = Width;
961 tmpH = Height;
962 tmpD = Depth;
963 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
964 tmpW = max(1, tmpW >> 1);
965 tmpH = max(1, tmpH >> 1);
966 tmpD = max(1, tmpD >> 1);
967 object->baseTexture.levels++;
969 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
972 /* Generate all the surfaces */
973 tmpW = Width;
974 tmpH = Height;
975 tmpD = Depth;
977 for (i = 0; i < object->baseTexture.levels; i++)
979 HRESULT hr;
980 /* Create the volume */
981 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
982 &object->volumes[i], pSharedHandle);
984 if(FAILED(hr)) {
985 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
986 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
987 *ppVolumeTexture = NULL;
988 return hr;
991 /* Set its container to this object */
992 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
994 /* calculate the next mipmap level */
995 tmpW = max(1, tmpW >> 1);
996 tmpH = max(1, tmpH >> 1);
997 tmpD = max(1, tmpD >> 1);
999 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1001 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1002 TRACE("(%p) : Created volume texture %p\n", This, object);
1003 return WINED3D_OK;
1006 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1007 UINT Width, UINT Height, UINT Depth,
1008 DWORD Usage,
1009 WINED3DFORMAT Format, WINED3DPOOL Pool,
1010 IWineD3DVolume** ppVolume,
1011 HANDLE* pSharedHandle, IUnknown *parent) {
1013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1014 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1015 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1017 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1018 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1019 return WINED3DERR_INVALIDCALL;
1022 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1024 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1025 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1027 object->currentDesc.Width = Width;
1028 object->currentDesc.Height = Height;
1029 object->currentDesc.Depth = Depth;
1030 object->bytesPerPixel = formatDesc->bpp;
1032 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1033 object->lockable = TRUE;
1034 object->locked = FALSE;
1035 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1036 object->dirty = TRUE;
1038 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1041 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1042 UINT Levels, DWORD Usage,
1043 WINED3DFORMAT Format, WINED3DPOOL Pool,
1044 IWineD3DCubeTexture **ppCubeTexture,
1045 HANDLE *pSharedHandle, IUnknown *parent,
1046 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1049 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1050 unsigned int i, j;
1051 UINT tmpW;
1052 HRESULT hr;
1053 unsigned int pow2EdgeLength = EdgeLength;
1054 const GlPixelFormatDesc *glDesc;
1055 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1057 /* TODO: It should only be possible to create textures for formats
1058 that are reported as supported */
1059 if (WINED3DFMT_UNKNOWN >= Format) {
1060 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1061 return WINED3DERR_INVALIDCALL;
1064 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1065 WARN("(%p) : Tried to create not supported cube texture\n", This);
1066 return WINED3DERR_INVALIDCALL;
1069 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1070 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1072 TRACE("(%p) Create Cube Texture\n", This);
1074 /** Non-power2 support **/
1076 /* Find the nearest pow2 match */
1077 pow2EdgeLength = 1;
1078 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1080 object->edgeLength = EdgeLength;
1081 /* TODO: support for native non-power 2 */
1082 /* Precalculated scaling for 'faked' non power of two texture coords */
1083 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1085 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1086 object->baseTexture.pow2Matrix[15] = 1.0;
1088 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1089 object->baseTexture.minMipLookup = &minMipLookup;
1090 object->baseTexture.magLookup = &magLookup;
1091 } else {
1092 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1093 object->baseTexture.magLookup = &magLookup_noFilter;
1096 /* Calculate levels for mip mapping */
1097 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1098 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1099 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1100 HeapFree(GetProcessHeap(), 0, object);
1101 *ppCubeTexture = NULL;
1103 return WINED3DERR_INVALIDCALL;
1105 if(Levels > 1) {
1106 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1107 HeapFree(GetProcessHeap(), 0, object);
1108 *ppCubeTexture = NULL;
1110 return WINED3DERR_INVALIDCALL;
1112 Levels = 1;
1113 } else if (Levels == 0) {
1114 object->baseTexture.levels++;
1115 tmpW = EdgeLength;
1116 while (tmpW > 1) {
1117 tmpW = max(1, tmpW >> 1);
1118 object->baseTexture.levels++;
1120 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1123 /* Generate all the surfaces */
1124 tmpW = EdgeLength;
1125 for (i = 0; i < object->baseTexture.levels; i++) {
1127 /* Create the 6 faces */
1128 for (j = 0; j < 6; j++) {
1130 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1131 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1133 if(hr!= WINED3D_OK) {
1134 /* clean up */
1135 int k;
1136 int l;
1137 for (l = 0; l < j; l++) {
1138 IWineD3DSurface_Release(object->surfaces[l][i]);
1140 for (k = 0; k < i; k++) {
1141 for (l = 0; l < 6; l++) {
1142 IWineD3DSurface_Release(object->surfaces[l][k]);
1146 FIXME("(%p) Failed to create surface\n",object);
1147 HeapFree(GetProcessHeap(),0,object);
1148 *ppCubeTexture = NULL;
1149 return hr;
1151 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1152 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1154 tmpW = max(1, tmpW >> 1);
1156 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1158 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1159 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1160 return WINED3D_OK;
1163 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1165 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1166 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1167 const IWineD3DQueryVtbl *vtable;
1169 /* Just a check to see if we support this type of query */
1170 switch(Type) {
1171 case WINED3DQUERYTYPE_OCCLUSION:
1172 TRACE("(%p) occlusion query\n", This);
1173 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1174 hr = WINED3D_OK;
1175 else
1176 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1178 vtable = &IWineD3DOcclusionQuery_Vtbl;
1179 break;
1181 case WINED3DQUERYTYPE_EVENT:
1182 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1183 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1184 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1186 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1188 vtable = &IWineD3DEventQuery_Vtbl;
1189 hr = WINED3D_OK;
1190 break;
1192 case WINED3DQUERYTYPE_VCACHE:
1193 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1194 case WINED3DQUERYTYPE_VERTEXSTATS:
1195 case WINED3DQUERYTYPE_TIMESTAMP:
1196 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1197 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1198 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1199 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1200 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1201 case WINED3DQUERYTYPE_PIXELTIMINGS:
1202 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1203 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1204 default:
1205 /* Use the base Query vtable until we have a special one for each query */
1206 vtable = &IWineD3DQuery_Vtbl;
1207 FIXME("(%p) Unhandled query type %d\n", This, Type);
1209 if(NULL == ppQuery || hr != WINED3D_OK) {
1210 return hr;
1213 D3DCREATEOBJECTINSTANCE(object, Query)
1214 object->lpVtbl = vtable;
1215 object->type = Type;
1216 object->state = QUERY_CREATED;
1217 /* allocated the 'extended' data based on the type of query requested */
1218 switch(Type){
1219 case WINED3DQUERYTYPE_OCCLUSION:
1220 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1221 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1223 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1224 TRACE("(%p) Allocating data for an occlusion query\n", This);
1225 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1226 break;
1228 case WINED3DQUERYTYPE_EVENT:
1229 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1230 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1232 if(GL_SUPPORT(APPLE_FENCE)) {
1233 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1234 checkGLcall("glGenFencesAPPLE");
1235 } else if(GL_SUPPORT(NV_FENCE)) {
1236 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1237 checkGLcall("glGenFencesNV");
1239 break;
1241 case WINED3DQUERYTYPE_VCACHE:
1242 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1243 case WINED3DQUERYTYPE_VERTEXSTATS:
1244 case WINED3DQUERYTYPE_TIMESTAMP:
1245 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1246 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1247 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1248 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1249 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1250 case WINED3DQUERYTYPE_PIXELTIMINGS:
1251 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1252 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1253 default:
1254 object->extendedData = 0;
1255 FIXME("(%p) Unhandled query type %d\n",This , Type);
1257 TRACE("(%p) : Created Query %p\n", This, object);
1258 return WINED3D_OK;
1261 /*****************************************************************************
1262 * IWineD3DDeviceImpl_SetupFullscreenWindow
1264 * Helper function that modifies a HWND's Style and ExStyle for proper
1265 * fullscreen use.
1267 * Params:
1268 * iface: Pointer to the IWineD3DDevice interface
1269 * window: Window to setup
1271 *****************************************************************************/
1272 static LONG fullscreen_style(LONG orig_style) {
1273 LONG style = orig_style;
1274 style &= ~WS_CAPTION;
1275 style &= ~WS_THICKFRAME;
1277 /* Make sure the window is managed, otherwise we won't get keyboard input */
1278 style |= WS_POPUP | WS_SYSMENU;
1280 return style;
1283 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1284 LONG exStyle = orig_exStyle;
1286 /* Filter out window decorations */
1287 exStyle &= ~WS_EX_WINDOWEDGE;
1288 exStyle &= ~WS_EX_CLIENTEDGE;
1290 return exStyle;
1293 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 LONG style, exStyle;
1297 /* Don't do anything if an original style is stored.
1298 * That shouldn't happen
1300 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1301 if (This->style || This->exStyle) {
1302 ERR("(%p): Want to change the window parameters of HWND %p, but "
1303 "another style is stored for restoration afterwards\n", This, window);
1306 /* Get the parameters and save them */
1307 style = GetWindowLongW(window, GWL_STYLE);
1308 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1309 This->style = style;
1310 This->exStyle = exStyle;
1312 style = fullscreen_style(style);
1313 exStyle = fullscreen_exStyle(exStyle);
1315 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1316 This->style, This->exStyle, style, exStyle);
1318 SetWindowLongW(window, GWL_STYLE, style);
1319 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1321 /* Inform the window about the update. */
1322 SetWindowPos(window, HWND_TOP, 0, 0,
1323 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1324 ShowWindow(window, SW_NORMAL);
1327 /*****************************************************************************
1328 * IWineD3DDeviceImpl_RestoreWindow
1330 * Helper function that restores a windows' properties when taking it out
1331 * of fullscreen mode
1333 * Params:
1334 * iface: Pointer to the IWineD3DDevice interface
1335 * window: Window to setup
1337 *****************************************************************************/
1338 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1340 LONG style, exStyle;
1342 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1343 * switch, do nothing
1345 if (!This->style && !This->exStyle) return;
1347 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1348 This, window, This->style, This->exStyle);
1350 style = GetWindowLongW(window, GWL_STYLE);
1351 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1353 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1354 * Some applications change it before calling Reset() when switching between windowed and
1355 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1357 if(style == fullscreen_style(This->style) &&
1358 exStyle == fullscreen_style(This->exStyle)) {
1359 SetWindowLongW(window, GWL_STYLE, This->style);
1360 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1363 /* Delete the old values */
1364 This->style = 0;
1365 This->exStyle = 0;
1367 /* Inform the window about the update */
1368 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1369 0, 0, 0, 0, /* Pos, Size, ignored */
1370 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1373 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1374 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1375 IUnknown* parent,
1376 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1377 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1380 HDC hDc;
1381 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1382 HRESULT hr = WINED3D_OK;
1383 IUnknown *bufferParent;
1384 BOOL displaymode_set = FALSE;
1385 WINED3DDISPLAYMODE Mode;
1386 const StaticPixelFormatDesc *formatDesc;
1388 TRACE("(%p) : Created Additional Swap Chain\n", This);
1390 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1391 * does a device hold a reference to a swap chain giving them a lifetime of the device
1392 * or does the swap chain notify the device of its destruction.
1393 *******************************/
1395 /* Check the params */
1396 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1397 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1398 return WINED3DERR_INVALIDCALL;
1399 } else if (pPresentationParameters->BackBufferCount > 1) {
1400 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");
1403 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1405 /*********************
1406 * Lookup the window Handle and the relating X window handle
1407 ********************/
1409 /* Setup hwnd we are using, plus which display this equates to */
1410 object->win_handle = pPresentationParameters->hDeviceWindow;
1411 if (!object->win_handle) {
1412 object->win_handle = This->createParms.hFocusWindow;
1414 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1416 hDc = GetDC(object->win_handle);
1417 TRACE("Using hDc %p\n", hDc);
1419 if (NULL == hDc) {
1420 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1421 return WINED3DERR_NOTAVAILABLE;
1424 /* Get info on the current display setup */
1425 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1426 object->orig_width = Mode.Width;
1427 object->orig_height = Mode.Height;
1428 object->orig_fmt = Mode.Format;
1429 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1431 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1432 * then the corresponding dimension of the client area of the hDeviceWindow
1433 * (or the focus window, if hDeviceWindow is NULL) is taken.
1434 **********************/
1436 if (pPresentationParameters->Windowed &&
1437 ((pPresentationParameters->BackBufferWidth == 0) ||
1438 (pPresentationParameters->BackBufferHeight == 0) ||
1439 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1441 RECT Rect;
1442 GetClientRect(object->win_handle, &Rect);
1444 if (pPresentationParameters->BackBufferWidth == 0) {
1445 pPresentationParameters->BackBufferWidth = Rect.right;
1446 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1448 if (pPresentationParameters->BackBufferHeight == 0) {
1449 pPresentationParameters->BackBufferHeight = Rect.bottom;
1450 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1452 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1453 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1454 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1458 /* Put the correct figures in the presentation parameters */
1459 TRACE("Copying across presentation parameters\n");
1460 object->presentParms = *pPresentationParameters;
1462 TRACE("calling rendertarget CB\n");
1463 hr = D3DCB_CreateRenderTarget(This->parent,
1464 parent,
1465 object->presentParms.BackBufferWidth,
1466 object->presentParms.BackBufferHeight,
1467 object->presentParms.BackBufferFormat,
1468 object->presentParms.MultiSampleType,
1469 object->presentParms.MultiSampleQuality,
1470 TRUE /* Lockable */,
1471 &object->frontBuffer,
1472 NULL /* pShared (always null)*/);
1473 if (object->frontBuffer != NULL) {
1474 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1475 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1476 } else {
1477 ERR("Failed to create the front buffer\n");
1478 goto error;
1481 /*********************
1482 * Windowed / Fullscreen
1483 *******************/
1486 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1487 * so we should really check to see if there is a fullscreen swapchain already
1488 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1489 **************************************/
1491 if (!pPresentationParameters->Windowed) {
1492 WINED3DDISPLAYMODE mode;
1495 /* Change the display settings */
1496 mode.Width = pPresentationParameters->BackBufferWidth;
1497 mode.Height = pPresentationParameters->BackBufferHeight;
1498 mode.Format = pPresentationParameters->BackBufferFormat;
1499 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1501 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1502 displaymode_set = TRUE;
1503 IWineD3DDevice_SetFullscreen(iface, TRUE);
1507 * Create an opengl context for the display visual
1508 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1509 * use different properties after that point in time. FIXME: How to handle when requested format
1510 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1511 * it chooses is identical to the one already being used!
1512 **********************************/
1513 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1515 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1516 if(!object->context)
1517 return E_OUTOFMEMORY;
1518 object->num_contexts = 1;
1520 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1521 if (!object->context[0]) {
1522 ERR("Failed to create a new context\n");
1523 hr = WINED3DERR_NOTAVAILABLE;
1524 goto error;
1525 } else {
1526 TRACE("Context created (HWND=%p, glContext=%p)\n",
1527 object->win_handle, object->context[0]->glCtx);
1530 /*********************
1531 * Create the back, front and stencil buffers
1532 *******************/
1533 if(object->presentParms.BackBufferCount > 0) {
1534 int i;
1536 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1537 if(!object->backBuffer) {
1538 ERR("Out of memory\n");
1539 hr = E_OUTOFMEMORY;
1540 goto error;
1543 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1544 TRACE("calling rendertarget CB\n");
1545 hr = D3DCB_CreateRenderTarget(This->parent,
1546 parent,
1547 object->presentParms.BackBufferWidth,
1548 object->presentParms.BackBufferHeight,
1549 object->presentParms.BackBufferFormat,
1550 object->presentParms.MultiSampleType,
1551 object->presentParms.MultiSampleQuality,
1552 TRUE /* Lockable */,
1553 &object->backBuffer[i],
1554 NULL /* pShared (always null)*/);
1555 if(hr == WINED3D_OK && object->backBuffer[i]) {
1556 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1557 } else {
1558 ERR("Cannot create new back buffer\n");
1559 goto error;
1561 ENTER_GL();
1562 glDrawBuffer(GL_BACK);
1563 checkGLcall("glDrawBuffer(GL_BACK)");
1564 LEAVE_GL();
1566 } else {
1567 object->backBuffer = NULL;
1569 /* Single buffering - draw to front buffer */
1570 ENTER_GL();
1571 glDrawBuffer(GL_FRONT);
1572 checkGLcall("glDrawBuffer(GL_FRONT)");
1573 LEAVE_GL();
1576 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1577 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1578 TRACE("Creating depth stencil buffer\n");
1579 if (This->auto_depth_stencil_buffer == NULL ) {
1580 hr = D3DCB_CreateDepthStencil(This->parent,
1581 parent,
1582 object->presentParms.BackBufferWidth,
1583 object->presentParms.BackBufferHeight,
1584 object->presentParms.AutoDepthStencilFormat,
1585 object->presentParms.MultiSampleType,
1586 object->presentParms.MultiSampleQuality,
1587 FALSE /* FIXME: Discard */,
1588 &This->auto_depth_stencil_buffer,
1589 NULL /* pShared (always null)*/ );
1590 if (This->auto_depth_stencil_buffer != NULL)
1591 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1594 /** TODO: A check on width, height and multisample types
1595 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1596 ****************************/
1597 object->wantsDepthStencilBuffer = TRUE;
1598 } else {
1599 object->wantsDepthStencilBuffer = FALSE;
1602 TRACE("Created swapchain %p\n", object);
1603 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1604 return WINED3D_OK;
1606 error:
1607 if (displaymode_set) {
1608 DEVMODEW devmode;
1609 RECT clip_rc;
1611 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1612 ClipCursor(NULL);
1614 /* Change the display settings */
1615 memset(&devmode, 0, sizeof(devmode));
1616 devmode.dmSize = sizeof(devmode);
1617 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1618 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1619 devmode.dmPelsWidth = object->orig_width;
1620 devmode.dmPelsHeight = object->orig_height;
1621 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1624 if (object->backBuffer) {
1625 int i;
1626 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1627 if(object->backBuffer[i]) {
1628 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1629 IUnknown_Release(bufferParent); /* once for the get parent */
1630 if (IUnknown_Release(bufferParent) > 0) {
1631 FIXME("(%p) Something's still holding the back buffer\n",This);
1635 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1636 object->backBuffer = NULL;
1638 if(object->context[0])
1639 DestroyContext(This, object->context[0]);
1640 if(object->frontBuffer) {
1641 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1642 IUnknown_Release(bufferParent); /* once for the get parent */
1643 if (IUnknown_Release(bufferParent) > 0) {
1644 FIXME("(%p) Something's still holding the front buffer\n",This);
1647 HeapFree(GetProcessHeap(), 0, object);
1648 return hr;
1651 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1652 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1653 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1654 TRACE("(%p)\n", This);
1656 return This->NumberOfSwapChains;
1659 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1661 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1663 if(iSwapChain < This->NumberOfSwapChains) {
1664 *pSwapChain = This->swapchains[iSwapChain];
1665 IWineD3DSwapChain_AddRef(*pSwapChain);
1666 TRACE("(%p) returning %p\n", This, *pSwapChain);
1667 return WINED3D_OK;
1668 } else {
1669 TRACE("Swapchain out of range\n");
1670 *pSwapChain = NULL;
1671 return WINED3DERR_INVALIDCALL;
1675 /*****
1676 * Vertex Declaration
1677 *****/
1678 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1679 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1681 IWineD3DVertexDeclarationImpl *object = NULL;
1682 HRESULT hr = WINED3D_OK;
1684 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1685 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1687 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1689 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1690 if(FAILED(hr)) {
1691 *ppVertexDeclaration = NULL;
1692 HeapFree(GetProcessHeap(), 0, object);
1695 return hr;
1698 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1699 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1701 unsigned int idx, idx2;
1702 unsigned int offset;
1703 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1704 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1705 BOOL has_blend_idx = has_blend &&
1706 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1707 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1708 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1709 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1710 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1711 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1712 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1714 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1715 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1717 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1718 WINED3DVERTEXELEMENT *elements = NULL;
1720 unsigned int size;
1721 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1722 if (has_blend_idx) num_blends--;
1724 /* Compute declaration size */
1725 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1726 has_psize + has_diffuse + has_specular + num_textures + 1;
1728 /* convert the declaration */
1729 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1730 if (!elements)
1731 return 0;
1733 elements[size-1] = end_element;
1734 idx = 0;
1735 if (has_pos) {
1736 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1737 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1738 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1740 else {
1741 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1742 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1744 elements[idx].UsageIndex = 0;
1745 idx++;
1747 if (has_blend && (num_blends > 0)) {
1748 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1749 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1750 else
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1752 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1753 elements[idx].UsageIndex = 0;
1754 idx++;
1756 if (has_blend_idx) {
1757 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1758 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1759 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1760 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1761 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1762 else
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1764 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1765 elements[idx].UsageIndex = 0;
1766 idx++;
1768 if (has_normal) {
1769 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1770 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1771 elements[idx].UsageIndex = 0;
1772 idx++;
1774 if (has_psize) {
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1776 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1777 elements[idx].UsageIndex = 0;
1778 idx++;
1780 if (has_diffuse) {
1781 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1782 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1783 elements[idx].UsageIndex = 0;
1784 idx++;
1786 if (has_specular) {
1787 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1788 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1789 elements[idx].UsageIndex = 1;
1790 idx++;
1792 for (idx2 = 0; idx2 < num_textures; idx2++) {
1793 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1794 switch (numcoords) {
1795 case WINED3DFVF_TEXTUREFORMAT1:
1796 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1797 break;
1798 case WINED3DFVF_TEXTUREFORMAT2:
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1800 break;
1801 case WINED3DFVF_TEXTUREFORMAT3:
1802 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1803 break;
1804 case WINED3DFVF_TEXTUREFORMAT4:
1805 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1806 break;
1808 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1809 elements[idx].UsageIndex = idx2;
1810 idx++;
1813 /* Now compute offsets, and initialize the rest of the fields */
1814 for (idx = 0, offset = 0; idx < size-1; idx++) {
1815 elements[idx].Stream = 0;
1816 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1817 elements[idx].Offset = offset;
1818 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1821 *ppVertexElements = elements;
1822 return size;
1825 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1826 WINED3DVERTEXELEMENT* elements = NULL;
1827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1828 unsigned int size;
1829 DWORD hr;
1831 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1832 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1834 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1835 HeapFree(GetProcessHeap(), 0, elements);
1836 if (hr != S_OK) return hr;
1838 return WINED3D_OK;
1841 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1843 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1844 HRESULT hr = WINED3D_OK;
1845 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1846 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1848 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1850 if (vertex_declaration) {
1851 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1854 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1856 if (WINED3D_OK != hr) {
1857 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1858 IWineD3DVertexShader_Release(*ppVertexShader);
1859 return WINED3DERR_INVALIDCALL;
1861 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1863 return WINED3D_OK;
1866 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1868 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1869 HRESULT hr = WINED3D_OK;
1871 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1872 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1873 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1874 if (WINED3D_OK == hr) {
1875 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1876 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1877 } else {
1878 WARN("(%p) : Failed to create pixel shader\n", This);
1881 return hr;
1884 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1886 IWineD3DPaletteImpl *object;
1887 HRESULT hr;
1888 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1890 /* Create the new object */
1891 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1892 if(!object) {
1893 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1894 return E_OUTOFMEMORY;
1897 object->lpVtbl = &IWineD3DPalette_Vtbl;
1898 object->ref = 1;
1899 object->Flags = Flags;
1900 object->parent = Parent;
1901 object->wineD3DDevice = This;
1902 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1904 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1906 if(!object->hpal) {
1907 HeapFree( GetProcessHeap(), 0, object);
1908 return E_OUTOFMEMORY;
1911 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1912 if(FAILED(hr)) {
1913 IWineD3DPalette_Release((IWineD3DPalette *) object);
1914 return hr;
1917 *Palette = (IWineD3DPalette *) object;
1919 return WINED3D_OK;
1922 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1923 HBITMAP hbm;
1924 BITMAP bm;
1925 HRESULT hr;
1926 HDC dcb = NULL, dcs = NULL;
1927 WINEDDCOLORKEY colorkey;
1929 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1930 if(hbm)
1932 GetObjectA(hbm, sizeof(BITMAP), &bm);
1933 dcb = CreateCompatibleDC(NULL);
1934 if(!dcb) goto out;
1935 SelectObject(dcb, hbm);
1937 else
1939 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1940 * couldn't be loaded
1942 memset(&bm, 0, sizeof(bm));
1943 bm.bmWidth = 32;
1944 bm.bmHeight = 32;
1947 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1948 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1949 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1950 if(FAILED(hr)) {
1951 ERR("Wine logo requested, but failed to create surface\n");
1952 goto out;
1955 if(dcb) {
1956 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1957 if(FAILED(hr)) goto out;
1958 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1959 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1961 colorkey.dwColorSpaceLowValue = 0;
1962 colorkey.dwColorSpaceHighValue = 0;
1963 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1964 } else {
1965 /* Fill the surface with a white color to show that wined3d is there */
1966 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1969 out:
1970 if(dcb) {
1971 DeleteDC(dcb);
1973 if(hbm) {
1974 DeleteObject(hbm);
1976 return;
1979 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1980 unsigned int i;
1981 /* Under DirectX you can have texture stage operations even if no texture is
1982 bound, whereas opengl will only do texture operations when a valid texture is
1983 bound. We emulate this by creating dummy textures and binding them to each
1984 texture stage, but disable all stages by default. Hence if a stage is enabled
1985 then the default texture will kick in until replaced by a SetTexture call */
1986 ENTER_GL();
1988 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1989 /* The dummy texture does not have client storage backing */
1990 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1991 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1993 for (i = 0; i < GL_LIMITS(textures); i++) {
1994 GLubyte white = 255;
1996 /* Make appropriate texture active */
1997 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1998 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1999 checkGLcall("glActiveTextureARB");
2000 } else if (i > 0) {
2001 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2004 /* Generate an opengl texture name */
2005 glGenTextures(1, &This->dummyTextureName[i]);
2006 checkGLcall("glGenTextures");
2007 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2009 /* Generate a dummy 2d texture (not using 1d because they cause many
2010 * DRI drivers fall back to sw) */
2011 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2012 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2013 checkGLcall("glBindTexture");
2015 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2016 checkGLcall("glTexImage2D");
2018 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2019 /* Reenable because if supported it is enabled by default */
2020 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2021 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2024 LEAVE_GL();
2027 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2029 IWineD3DSwapChainImpl *swapchain = NULL;
2030 HRESULT hr;
2031 DWORD state;
2032 unsigned int i;
2034 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2035 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2036 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2038 /* TODO: Test if OpenGL is compiled in and loaded */
2040 TRACE("(%p) : Creating stateblock\n", This);
2041 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2042 hr = IWineD3DDevice_CreateStateBlock(iface,
2043 WINED3DSBT_INIT,
2044 (IWineD3DStateBlock **)&This->stateBlock,
2045 NULL);
2046 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2047 WARN("Failed to create stateblock\n");
2048 goto err_out;
2050 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2051 This->updateStateBlock = This->stateBlock;
2052 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2054 hr = allocate_shader_constants(This->updateStateBlock);
2055 if (WINED3D_OK != hr) {
2056 goto err_out;
2059 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2060 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2061 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2063 This->NumberOfPalettes = 1;
2064 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2065 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2066 ERR("Out of memory!\n");
2067 goto err_out;
2069 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2070 if(!This->palettes[0]) {
2071 ERR("Out of memory!\n");
2072 goto err_out;
2074 for (i = 0; i < 256; ++i) {
2075 This->palettes[0][i].peRed = 0xFF;
2076 This->palettes[0][i].peGreen = 0xFF;
2077 This->palettes[0][i].peBlue = 0xFF;
2078 This->palettes[0][i].peFlags = 0xFF;
2080 This->currentPalette = 0;
2082 /* Initialize the texture unit mapping to a 1:1 mapping */
2083 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2084 if (state < GL_LIMITS(fragment_samplers)) {
2085 This->texUnitMap[state] = state;
2086 This->rev_tex_unit_map[state] = state;
2087 } else {
2088 This->texUnitMap[state] = -1;
2089 This->rev_tex_unit_map[state] = -1;
2093 /* Setup the implicit swapchain */
2094 TRACE("Creating implicit swapchain\n");
2095 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2096 if (FAILED(hr) || !swapchain) {
2097 WARN("Failed to create implicit swapchain\n");
2098 goto err_out;
2101 This->NumberOfSwapChains = 1;
2102 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2103 if(!This->swapchains) {
2104 ERR("Out of memory!\n");
2105 goto err_out;
2107 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2109 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2110 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2111 This->render_targets[0] = swapchain->backBuffer[0];
2112 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2114 else {
2115 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2116 This->render_targets[0] = swapchain->frontBuffer;
2117 This->lastActiveRenderTarget = swapchain->frontBuffer;
2119 IWineD3DSurface_AddRef(This->render_targets[0]);
2120 This->activeContext = swapchain->context[0];
2121 This->lastThread = GetCurrentThreadId();
2123 /* Depth Stencil support */
2124 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2125 if (NULL != This->stencilBufferTarget) {
2126 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2129 hr = This->shader_backend->shader_alloc_private(iface);
2130 if(FAILED(hr)) {
2131 TRACE("Shader private data couldn't be allocated\n");
2132 goto err_out;
2135 /* Set up some starting GL setup */
2137 /* Setup all the devices defaults */
2138 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2139 create_dummy_textures(This);
2141 ENTER_GL();
2143 #if 0
2144 IWineD3DImpl_CheckGraphicsMemory();
2145 #endif
2147 { /* Set a default viewport */
2148 WINED3DVIEWPORT vp;
2149 vp.X = 0;
2150 vp.Y = 0;
2151 vp.Width = pPresentationParameters->BackBufferWidth;
2152 vp.Height = pPresentationParameters->BackBufferHeight;
2153 vp.MinZ = 0.0f;
2154 vp.MaxZ = 1.0f;
2155 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2158 /* Initialize the current view state */
2159 This->view_ident = 1;
2160 This->contexts[0]->last_was_rhw = 0;
2161 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2162 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2164 switch(wined3d_settings.offscreen_rendering_mode) {
2165 case ORM_FBO:
2166 case ORM_PBUFFER:
2167 This->offscreenBuffer = GL_BACK;
2168 break;
2170 case ORM_BACKBUFFER:
2172 if(This->activeContext->aux_buffers > 0) {
2173 TRACE("Using auxilliary buffer for offscreen rendering\n");
2174 This->offscreenBuffer = GL_AUX0;
2175 } else {
2176 TRACE("Using back buffer for offscreen rendering\n");
2177 This->offscreenBuffer = GL_BACK;
2182 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2183 LEAVE_GL();
2185 /* Clear the screen */
2186 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2187 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2188 0x00, 1.0, 0);
2190 This->d3d_initialized = TRUE;
2192 if(wined3d_settings.logo) {
2193 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2195 This->highest_dirty_ps_const = 0;
2196 This->highest_dirty_vs_const = 0;
2197 return WINED3D_OK;
2199 err_out:
2200 This->shader_backend->shader_free_private(iface);
2201 HeapFree(GetProcessHeap(), 0, This->render_targets);
2202 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2203 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2204 HeapFree(GetProcessHeap(), 0, This->swapchains);
2205 This->NumberOfSwapChains = 0;
2206 if(This->palettes) {
2207 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2208 HeapFree(GetProcessHeap(), 0, This->palettes);
2210 This->NumberOfPalettes = 0;
2211 if(swapchain) {
2212 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2214 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2215 if(This->stateBlock) {
2216 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2217 This->stateBlock = NULL;
2219 return hr;
2222 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2224 int sampler;
2225 UINT i;
2226 TRACE("(%p)\n", This);
2228 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2230 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2231 * it was created. Thus make sure a context is active for the glDelete* calls
2233 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2235 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2237 TRACE("Deleting high order patches\n");
2238 for(i = 0; i < PATCHMAP_SIZE; i++) {
2239 struct list *e1, *e2;
2240 struct WineD3DRectPatch *patch;
2241 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2242 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2243 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2247 /* Delete the palette conversion shader if it is around */
2248 if(This->paletteConversionShader) {
2249 ENTER_GL();
2250 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2251 LEAVE_GL();
2252 This->paletteConversionShader = 0;
2255 /* Delete the pbuffer context if there is any */
2256 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2258 /* Delete the mouse cursor texture */
2259 if(This->cursorTexture) {
2260 ENTER_GL();
2261 glDeleteTextures(1, &This->cursorTexture);
2262 LEAVE_GL();
2263 This->cursorTexture = 0;
2266 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2267 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2269 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2270 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2273 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2274 * private data, it might contain opengl pointers
2276 if(This->depth_blt_texture) {
2277 glDeleteTextures(1, &This->depth_blt_texture);
2278 This->depth_blt_texture = 0;
2280 This->shader_backend->shader_destroy_depth_blt(iface);
2281 This->shader_backend->shader_free_private(iface);
2283 /* Release the update stateblock */
2284 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2285 if(This->updateStateBlock != This->stateBlock)
2286 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2288 This->updateStateBlock = NULL;
2290 { /* because were not doing proper internal refcounts releasing the primary state block
2291 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2292 to set this->stateBlock = NULL; first */
2293 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2294 This->stateBlock = NULL;
2296 /* Release the stateblock */
2297 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2298 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2302 /* Release the buffers (with sanity checks)*/
2303 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2304 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2305 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2306 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2308 This->stencilBufferTarget = NULL;
2310 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2311 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2312 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2314 TRACE("Setting rendertarget to NULL\n");
2315 This->render_targets[0] = NULL;
2317 if (This->auto_depth_stencil_buffer) {
2318 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2319 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2321 This->auto_depth_stencil_buffer = NULL;
2324 for(i=0; i < This->NumberOfSwapChains; i++) {
2325 TRACE("Releasing the implicit swapchain %d\n", i);
2326 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2327 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2331 HeapFree(GetProcessHeap(), 0, This->swapchains);
2332 This->swapchains = NULL;
2333 This->NumberOfSwapChains = 0;
2335 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2336 HeapFree(GetProcessHeap(), 0, This->palettes);
2337 This->palettes = NULL;
2338 This->NumberOfPalettes = 0;
2340 HeapFree(GetProcessHeap(), 0, This->render_targets);
2341 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2342 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2343 This->render_targets = NULL;
2344 This->fbo_color_attachments = NULL;
2345 This->draw_buffers = NULL;
2347 This->d3d_initialized = FALSE;
2348 return WINED3D_OK;
2351 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2353 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2355 /* Setup the window for fullscreen mode */
2356 if(fullscreen && !This->ddraw_fullscreen) {
2357 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2358 } else if(!fullscreen && This->ddraw_fullscreen) {
2359 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2362 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2363 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2364 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2365 * separately.
2367 This->ddraw_fullscreen = fullscreen;
2370 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2371 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2372 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2374 * There is no way to deactivate thread safety once it is enabled.
2376 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2379 /*For now just store the flag(needed in case of ddraw) */
2380 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2382 return;
2385 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2386 DEVMODEW devmode;
2387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2388 LONG ret;
2389 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2390 RECT clip_rc;
2392 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2394 /* Resize the screen even without a window:
2395 * The app could have unset it with SetCooperativeLevel, but not called
2396 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2397 * but we don't have any hwnd
2400 memset(&devmode, 0, sizeof(devmode));
2401 devmode.dmSize = sizeof(devmode);
2402 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2403 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2404 devmode.dmPelsWidth = pMode->Width;
2405 devmode.dmPelsHeight = pMode->Height;
2407 devmode.dmDisplayFrequency = pMode->RefreshRate;
2408 if (pMode->RefreshRate != 0) {
2409 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2412 /* Only change the mode if necessary */
2413 if( (This->ddraw_width == pMode->Width) &&
2414 (This->ddraw_height == pMode->Height) &&
2415 (This->ddraw_format == pMode->Format) &&
2416 (pMode->RefreshRate == 0) ) {
2417 return WINED3D_OK;
2420 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2421 if (ret != DISP_CHANGE_SUCCESSFUL) {
2422 if(devmode.dmDisplayFrequency != 0) {
2423 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2424 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2425 devmode.dmDisplayFrequency = 0;
2426 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2428 if(ret != DISP_CHANGE_SUCCESSFUL) {
2429 return WINED3DERR_NOTAVAILABLE;
2433 /* Store the new values */
2434 This->ddraw_width = pMode->Width;
2435 This->ddraw_height = pMode->Height;
2436 This->ddraw_format = pMode->Format;
2438 /* Only do this with a window of course, and only if we're fullscreened */
2439 if(This->ddraw_window && This->ddraw_fullscreen)
2440 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2442 /* And finally clip mouse to our screen */
2443 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2444 ClipCursor(&clip_rc);
2446 return WINED3D_OK;
2449 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2451 *ppD3D= This->wineD3D;
2452 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2453 IWineD3D_AddRef(*ppD3D);
2454 return WINED3D_OK;
2457 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2460 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2461 (This->adapter->TextureRam/(1024*1024)),
2462 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2463 /* return simulated texture memory left */
2464 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2469 /*****
2470 * Get / Set FVF
2471 *****/
2472 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2475 /* Update the current state block */
2476 This->updateStateBlock->changed.fvf = TRUE;
2478 if(This->updateStateBlock->fvf == fvf) {
2479 TRACE("Application is setting the old fvf over, nothing to do\n");
2480 return WINED3D_OK;
2483 This->updateStateBlock->fvf = fvf;
2484 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2485 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2486 return WINED3D_OK;
2490 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2492 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2493 *pfvf = This->stateBlock->fvf;
2494 return WINED3D_OK;
2497 /*****
2498 * Get / Set Stream Source
2499 *****/
2500 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2502 IWineD3DVertexBuffer *oldSrc;
2504 if (StreamNumber >= MAX_STREAMS) {
2505 WARN("Stream out of range %d\n", StreamNumber);
2506 return WINED3DERR_INVALIDCALL;
2507 } else if(OffsetInBytes & 0x3) {
2508 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2509 return WINED3DERR_INVALIDCALL;
2512 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2513 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2515 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2517 if(oldSrc == pStreamData &&
2518 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2519 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2520 TRACE("Application is setting the old values over, nothing to do\n");
2521 return WINED3D_OK;
2524 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2525 if (pStreamData) {
2526 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2527 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2530 /* Handle recording of state blocks */
2531 if (This->isRecordingState) {
2532 TRACE("Recording... not performing anything\n");
2533 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2534 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2535 return WINED3D_OK;
2538 /* Need to do a getParent and pass the references up */
2539 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2540 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2541 so for now, just count internally */
2542 if (pStreamData != NULL) {
2543 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2544 InterlockedIncrement(&vbImpl->bindCount);
2545 IWineD3DVertexBuffer_AddRef(pStreamData);
2547 if (oldSrc != NULL) {
2548 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2549 IWineD3DVertexBuffer_Release(oldSrc);
2552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2554 return WINED3D_OK;
2557 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2560 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2561 This->stateBlock->streamSource[StreamNumber],
2562 This->stateBlock->streamOffset[StreamNumber],
2563 This->stateBlock->streamStride[StreamNumber]);
2565 if (StreamNumber >= MAX_STREAMS) {
2566 WARN("Stream out of range %d\n", StreamNumber);
2567 return WINED3DERR_INVALIDCALL;
2569 *pStream = This->stateBlock->streamSource[StreamNumber];
2570 *pStride = This->stateBlock->streamStride[StreamNumber];
2571 if (pOffset) {
2572 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2575 if (*pStream != NULL) {
2576 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2578 return WINED3D_OK;
2581 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2584 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2586 /* Verify input at least in d3d9 this is invalid*/
2587 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2588 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2589 return WINED3DERR_INVALIDCALL;
2591 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2592 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2593 return WINED3DERR_INVALIDCALL;
2595 if( Divider == 0 ){
2596 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2597 return WINED3DERR_INVALIDCALL;
2600 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2601 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2603 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2604 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2606 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2607 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2611 return WINED3D_OK;
2614 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2617 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2618 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2620 TRACE("(%p) : returning %d\n", This, *Divider);
2622 return WINED3D_OK;
2625 /*****
2626 * Get / Set & Multiply Transform
2627 *****/
2628 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2631 /* Most of this routine, comments included copied from ddraw tree initially: */
2632 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2634 /* Handle recording of state blocks */
2635 if (This->isRecordingState) {
2636 TRACE("Recording... not performing anything\n");
2637 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2638 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2639 return WINED3D_OK;
2643 * If the new matrix is the same as the current one,
2644 * we cut off any further processing. this seems to be a reasonable
2645 * optimization because as was noticed, some apps (warcraft3 for example)
2646 * tend towards setting the same matrix repeatedly for some reason.
2648 * From here on we assume that the new matrix is different, wherever it matters.
2650 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2651 TRACE("The app is setting the same matrix over again\n");
2652 return WINED3D_OK;
2653 } else {
2654 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2658 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2659 where ViewMat = Camera space, WorldMat = world space.
2661 In OpenGL, camera and world space is combined into GL_MODELVIEW
2662 matrix. The Projection matrix stay projection matrix.
2665 /* Capture the times we can just ignore the change for now */
2666 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2667 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2668 /* Handled by the state manager */
2671 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2672 return WINED3D_OK;
2675 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2677 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2678 *pMatrix = This->stateBlock->transforms[State];
2679 return WINED3D_OK;
2682 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2683 WINED3DMATRIX *mat = NULL;
2684 WINED3DMATRIX temp;
2686 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2687 * below means it will be recorded in a state block change, but it
2688 * works regardless where it is recorded.
2689 * If this is found to be wrong, change to StateBlock.
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2692 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2694 if (State < HIGHEST_TRANSFORMSTATE)
2696 mat = &This->updateStateBlock->transforms[State];
2697 } else {
2698 FIXME("Unhandled transform state!!\n");
2701 multiply_matrix(&temp, mat, pMatrix);
2703 /* Apply change via set transform - will reapply to eg. lights this way */
2704 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2707 /*****
2708 * Get / Set Light
2709 *****/
2710 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2711 you can reference any indexes you want as long as that number max are enabled at any
2712 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2713 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2714 but when recording, just build a chain pretty much of commands to be replayed. */
2716 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2717 float rho;
2718 PLIGHTINFOEL *object = NULL;
2719 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2720 struct list *e;
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2725 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2726 * the gl driver.
2728 if(!pLight) {
2729 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2730 return WINED3DERR_INVALIDCALL;
2733 switch(pLight->Type) {
2734 case WINED3DLIGHT_POINT:
2735 case WINED3DLIGHT_SPOT:
2736 case WINED3DLIGHT_PARALLELPOINT:
2737 case WINED3DLIGHT_GLSPOT:
2738 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2739 * most wanted
2741 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2742 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2743 return WINED3DERR_INVALIDCALL;
2745 break;
2747 case WINED3DLIGHT_DIRECTIONAL:
2748 /* Ignores attenuation */
2749 break;
2751 default:
2752 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2753 return WINED3DERR_INVALIDCALL;
2756 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2757 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2758 if(object->OriginalIndex == Index) break;
2759 object = NULL;
2762 if(!object) {
2763 TRACE("Adding new light\n");
2764 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2765 if(!object) {
2766 ERR("Out of memory error when allocating a light\n");
2767 return E_OUTOFMEMORY;
2769 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2770 object->glIndex = -1;
2771 object->OriginalIndex = Index;
2772 object->changed = TRUE;
2775 /* Initialize the object */
2776 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,
2777 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2778 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2779 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2780 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2781 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2782 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2784 /* Save away the information */
2785 object->OriginalParms = *pLight;
2787 switch (pLight->Type) {
2788 case WINED3DLIGHT_POINT:
2789 /* Position */
2790 object->lightPosn[0] = pLight->Position.x;
2791 object->lightPosn[1] = pLight->Position.y;
2792 object->lightPosn[2] = pLight->Position.z;
2793 object->lightPosn[3] = 1.0f;
2794 object->cutoff = 180.0f;
2795 /* FIXME: Range */
2796 break;
2798 case WINED3DLIGHT_DIRECTIONAL:
2799 /* Direction */
2800 object->lightPosn[0] = -pLight->Direction.x;
2801 object->lightPosn[1] = -pLight->Direction.y;
2802 object->lightPosn[2] = -pLight->Direction.z;
2803 object->lightPosn[3] = 0.0;
2804 object->exponent = 0.0f;
2805 object->cutoff = 180.0f;
2806 break;
2808 case WINED3DLIGHT_SPOT:
2809 /* Position */
2810 object->lightPosn[0] = pLight->Position.x;
2811 object->lightPosn[1] = pLight->Position.y;
2812 object->lightPosn[2] = pLight->Position.z;
2813 object->lightPosn[3] = 1.0;
2815 /* Direction */
2816 object->lightDirn[0] = pLight->Direction.x;
2817 object->lightDirn[1] = pLight->Direction.y;
2818 object->lightDirn[2] = pLight->Direction.z;
2819 object->lightDirn[3] = 1.0;
2822 * opengl-ish and d3d-ish spot lights use too different models for the
2823 * light "intensity" as a function of the angle towards the main light direction,
2824 * so we only can approximate very roughly.
2825 * however spot lights are rather rarely used in games (if ever used at all).
2826 * furthermore if still used, probably nobody pays attention to such details.
2828 if (pLight->Falloff == 0) {
2829 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2830 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2831 * will always be 1.0 for both of them, and we don't have to care for the
2832 * rest of the rather complex calculation
2834 object->exponent = 0;
2835 } else {
2836 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2837 if (rho < 0.0001) rho = 0.0001f;
2838 object->exponent = -0.3/log(cos(rho/2));
2840 if (object->exponent > 128.0) {
2841 object->exponent = 128.0;
2843 object->cutoff = pLight->Phi*90/M_PI;
2845 /* FIXME: Range */
2846 break;
2848 default:
2849 FIXME("Unrecognized light type %d\n", pLight->Type);
2852 /* Update the live definitions if the light is currently assigned a glIndex */
2853 if (object->glIndex != -1 && !This->isRecordingState) {
2854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2856 return WINED3D_OK;
2859 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2860 PLIGHTINFOEL *lightInfo = NULL;
2861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2862 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2863 struct list *e;
2864 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2866 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2867 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2868 if(lightInfo->OriginalIndex == Index) break;
2869 lightInfo = NULL;
2872 if (lightInfo == NULL) {
2873 TRACE("Light information requested but light not defined\n");
2874 return WINED3DERR_INVALIDCALL;
2877 *pLight = lightInfo->OriginalParms;
2878 return WINED3D_OK;
2881 /*****
2882 * Get / Set Light Enable
2883 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2884 *****/
2885 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2886 PLIGHTINFOEL *lightInfo = NULL;
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2889 struct list *e;
2890 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2892 /* Tests show true = 128...not clear why */
2893 Enable = Enable? 128: 0;
2895 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2896 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2897 if(lightInfo->OriginalIndex == Index) break;
2898 lightInfo = NULL;
2900 TRACE("Found light: %p\n", lightInfo);
2902 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2903 if (lightInfo == NULL) {
2905 TRACE("Light enabled requested but light not defined, so defining one!\n");
2906 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2908 /* Search for it again! Should be fairly quick as near head of list */
2909 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2910 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2911 if(lightInfo->OriginalIndex == Index) break;
2912 lightInfo = NULL;
2914 if (lightInfo == NULL) {
2915 FIXME("Adding default lights has failed dismally\n");
2916 return WINED3DERR_INVALIDCALL;
2920 lightInfo->enabledChanged = TRUE;
2921 if(!Enable) {
2922 if(lightInfo->glIndex != -1) {
2923 if(!This->isRecordingState) {
2924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2927 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2928 lightInfo->glIndex = -1;
2929 } else {
2930 TRACE("Light already disabled, nothing to do\n");
2932 lightInfo->enabled = FALSE;
2933 } else {
2934 lightInfo->enabled = TRUE;
2935 if (lightInfo->glIndex != -1) {
2936 /* nop */
2937 TRACE("Nothing to do as light was enabled\n");
2938 } else {
2939 int i;
2940 /* Find a free gl light */
2941 for(i = 0; i < This->maxConcurrentLights; i++) {
2942 if(This->stateBlock->activeLights[i] == NULL) {
2943 This->stateBlock->activeLights[i] = lightInfo;
2944 lightInfo->glIndex = i;
2945 break;
2948 if(lightInfo->glIndex == -1) {
2949 /* Our tests show that Windows returns D3D_OK in this situation, even with
2950 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2951 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2952 * as well for those lights.
2954 * TODO: Test how this affects rendering
2956 FIXME("Too many concurrently active lights\n");
2957 return WINED3D_OK;
2960 /* i == lightInfo->glIndex */
2961 if(!This->isRecordingState) {
2962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2967 return WINED3D_OK;
2970 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2972 PLIGHTINFOEL *lightInfo = NULL;
2973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 struct list *e;
2975 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2976 TRACE("(%p) : for idx(%d)\n", This, Index);
2978 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2979 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2980 if(lightInfo->OriginalIndex == Index) break;
2981 lightInfo = NULL;
2984 if (lightInfo == NULL) {
2985 TRACE("Light enabled state requested but light not defined\n");
2986 return WINED3DERR_INVALIDCALL;
2988 /* true is 128 according to SetLightEnable */
2989 *pEnable = lightInfo->enabled ? 128 : 0;
2990 return WINED3D_OK;
2993 /*****
2994 * Get / Set Clip Planes
2995 *****/
2996 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2998 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3000 /* Validate Index */
3001 if (Index >= GL_LIMITS(clipplanes)) {
3002 TRACE("Application has requested clipplane this device doesn't support\n");
3003 return WINED3DERR_INVALIDCALL;
3006 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3008 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3009 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3010 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3011 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3012 TRACE("Application is setting old values over, nothing to do\n");
3013 return WINED3D_OK;
3016 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3017 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3018 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3019 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3021 /* Handle recording of state blocks */
3022 if (This->isRecordingState) {
3023 TRACE("Recording... not performing anything\n");
3024 return WINED3D_OK;
3027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3029 return WINED3D_OK;
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3034 TRACE("(%p) : for idx %d\n", This, Index);
3036 /* Validate Index */
3037 if (Index >= GL_LIMITS(clipplanes)) {
3038 TRACE("Application has requested clipplane this device doesn't support\n");
3039 return WINED3DERR_INVALIDCALL;
3042 pPlane[0] = This->stateBlock->clipplane[Index][0];
3043 pPlane[1] = This->stateBlock->clipplane[Index][1];
3044 pPlane[2] = This->stateBlock->clipplane[Index][2];
3045 pPlane[3] = This->stateBlock->clipplane[Index][3];
3046 return WINED3D_OK;
3049 /*****
3050 * Get / Set Clip Plane Status
3051 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3052 *****/
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 FIXME("(%p) : stub\n", This);
3056 if (NULL == pClipStatus) {
3057 return WINED3DERR_INVALIDCALL;
3059 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3060 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3061 return WINED3D_OK;
3064 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3066 FIXME("(%p) : stub\n", This);
3067 if (NULL == pClipStatus) {
3068 return WINED3DERR_INVALIDCALL;
3070 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3071 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3072 return WINED3D_OK;
3075 /*****
3076 * Get / Set Material
3077 *****/
3078 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3081 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3083 This->updateStateBlock->changed.material = TRUE;
3084 This->updateStateBlock->material = *pMaterial;
3086 /* Handle recording of state blocks */
3087 if (This->isRecordingState) {
3088 TRACE("Recording... not performing anything\n");
3089 return WINED3D_OK;
3092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3093 return WINED3D_OK;
3096 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 *pMaterial = This->updateStateBlock->material;
3099 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3100 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3101 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3102 pMaterial->Ambient.b, pMaterial->Ambient.a);
3103 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3104 pMaterial->Specular.b, pMaterial->Specular.a);
3105 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3106 pMaterial->Emissive.b, pMaterial->Emissive.a);
3107 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3109 return WINED3D_OK;
3112 /*****
3113 * Get / Set Indices
3114 *****/
3115 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3117 IWineD3DIndexBuffer *oldIdxs;
3119 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3120 oldIdxs = This->updateStateBlock->pIndexData;
3122 This->updateStateBlock->changed.indices = TRUE;
3123 This->updateStateBlock->pIndexData = pIndexData;
3125 /* Handle recording of state blocks */
3126 if (This->isRecordingState) {
3127 TRACE("Recording... not performing anything\n");
3128 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3129 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3130 return WINED3D_OK;
3133 if(oldIdxs != pIndexData) {
3134 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3135 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3136 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3138 return WINED3D_OK;
3141 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 *ppIndexData = This->stateBlock->pIndexData;
3146 /* up ref count on ppindexdata */
3147 if (*ppIndexData) {
3148 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3149 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3150 }else{
3151 TRACE("(%p) No index data set\n", This);
3153 TRACE("Returning %p\n", *ppIndexData);
3155 return WINED3D_OK;
3158 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3159 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3161 TRACE("(%p)->(%d)\n", This, BaseIndex);
3163 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3164 TRACE("Application is setting the old value over, nothing to do\n");
3165 return WINED3D_OK;
3168 This->updateStateBlock->baseVertexIndex = BaseIndex;
3170 if (This->isRecordingState) {
3171 TRACE("Recording... not performing anything\n");
3172 return WINED3D_OK;
3174 /* The base vertex index affects the stream sources */
3175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3176 return WINED3D_OK;
3179 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 TRACE("(%p) : base_index %p\n", This, base_index);
3183 *base_index = This->stateBlock->baseVertexIndex;
3185 TRACE("Returning %u\n", *base_index);
3187 return WINED3D_OK;
3190 /*****
3191 * Get / Set Viewports
3192 *****/
3193 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3196 TRACE("(%p)\n", This);
3197 This->updateStateBlock->changed.viewport = TRUE;
3198 This->updateStateBlock->viewport = *pViewport;
3200 /* Handle recording of state blocks */
3201 if (This->isRecordingState) {
3202 TRACE("Recording... not performing anything\n");
3203 return WINED3D_OK;
3206 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3207 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3210 return WINED3D_OK;
3214 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3216 TRACE("(%p)\n", This);
3217 *pViewport = This->stateBlock->viewport;
3218 return WINED3D_OK;
3221 /*****
3222 * Get / Set Render States
3223 * TODO: Verify against dx9 definitions
3224 *****/
3225 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 DWORD oldValue = This->stateBlock->renderState[State];
3230 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3232 This->updateStateBlock->changed.renderState[State] = TRUE;
3233 This->updateStateBlock->renderState[State] = Value;
3235 /* Handle recording of state blocks */
3236 if (This->isRecordingState) {
3237 TRACE("Recording... not performing anything\n");
3238 return WINED3D_OK;
3241 /* Compared here and not before the assignment to allow proper stateblock recording */
3242 if(Value == oldValue) {
3243 TRACE("Application is setting the old value over, nothing to do\n");
3244 } else {
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3248 return WINED3D_OK;
3251 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3254 *pValue = This->stateBlock->renderState[State];
3255 return WINED3D_OK;
3258 /*****
3259 * Get / Set Sampler States
3260 * TODO: Verify against dx9 definitions
3261 *****/
3263 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 DWORD oldValue;
3267 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3268 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3270 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3271 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3274 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3275 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3276 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3279 * SetSampler is designed to allow for more than the standard up to 8 textures
3280 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3281 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3283 * http://developer.nvidia.com/object/General_FAQ.html#t6
3285 * There are two new settings for GForce
3286 * the sampler one:
3287 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3288 * and the texture one:
3289 * GL_MAX_TEXTURE_COORDS_ARB.
3290 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3291 ******************/
3293 oldValue = This->stateBlock->samplerState[Sampler][Type];
3294 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3295 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3297 /* Handle recording of state blocks */
3298 if (This->isRecordingState) {
3299 TRACE("Recording... not performing anything\n");
3300 return WINED3D_OK;
3303 if(oldValue == Value) {
3304 TRACE("Application is setting the old value over, nothing to do\n");
3305 return WINED3D_OK;
3308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3310 return WINED3D_OK;
3313 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3316 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3317 This, Sampler, debug_d3dsamplerstate(Type), Type);
3319 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3320 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3323 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3324 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3325 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3327 *Value = This->stateBlock->samplerState[Sampler][Type];
3328 TRACE("(%p) : Returning %#x\n", This, *Value);
3330 return WINED3D_OK;
3333 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3336 This->updateStateBlock->changed.scissorRect = TRUE;
3337 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3338 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3339 return WINED3D_OK;
3341 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3343 if(This->isRecordingState) {
3344 TRACE("Recording... not performing anything\n");
3345 return WINED3D_OK;
3348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3350 return WINED3D_OK;
3353 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 *pRect = This->updateStateBlock->scissorRect;
3357 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3358 return WINED3D_OK;
3361 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3363 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3365 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3367 This->updateStateBlock->vertexDecl = pDecl;
3368 This->updateStateBlock->changed.vertexDecl = TRUE;
3370 if (This->isRecordingState) {
3371 TRACE("Recording... not performing anything\n");
3372 return WINED3D_OK;
3373 } else if(pDecl == oldDecl) {
3374 /* Checked after the assignment to allow proper stateblock recording */
3375 TRACE("Application is setting the old declaration over, nothing to do\n");
3376 return WINED3D_OK;
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3380 return WINED3D_OK;
3383 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3386 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3388 *ppDecl = This->stateBlock->vertexDecl;
3389 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3390 return WINED3D_OK;
3393 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3397 This->updateStateBlock->vertexShader = pShader;
3398 This->updateStateBlock->changed.vertexShader = TRUE;
3400 if (This->isRecordingState) {
3401 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3402 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3403 TRACE("Recording... not performing anything\n");
3404 return WINED3D_OK;
3405 } else if(oldShader == pShader) {
3406 /* Checked here to allow proper stateblock recording */
3407 TRACE("App is setting the old shader over, nothing to do\n");
3408 return WINED3D_OK;
3411 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3412 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3413 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3415 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3417 return WINED3D_OK;
3420 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3423 if (NULL == ppShader) {
3424 return WINED3DERR_INVALIDCALL;
3426 *ppShader = This->stateBlock->vertexShader;
3427 if( NULL != *ppShader)
3428 IWineD3DVertexShader_AddRef(*ppShader);
3430 TRACE("(%p) : returning %p\n", This, *ppShader);
3431 return WINED3D_OK;
3434 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3435 IWineD3DDevice *iface,
3436 UINT start,
3437 CONST BOOL *srcData,
3438 UINT count) {
3440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3441 int i, cnt = min(count, MAX_CONST_B - start);
3443 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3444 iface, srcData, start, count);
3446 if (srcData == NULL || cnt < 0)
3447 return WINED3DERR_INVALIDCALL;
3449 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3450 for (i = 0; i < cnt; i++)
3451 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3453 for (i = start; i < cnt + start; ++i) {
3454 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3457 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3459 return WINED3D_OK;
3462 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3463 IWineD3DDevice *iface,
3464 UINT start,
3465 BOOL *dstData,
3466 UINT count) {
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3469 int cnt = min(count, MAX_CONST_B - start);
3471 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3472 iface, dstData, start, count);
3474 if (dstData == NULL || cnt < 0)
3475 return WINED3DERR_INVALIDCALL;
3477 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3478 return WINED3D_OK;
3481 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3482 IWineD3DDevice *iface,
3483 UINT start,
3484 CONST int *srcData,
3485 UINT count) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488 int i, cnt = min(count, MAX_CONST_I - start);
3490 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3491 iface, srcData, start, count);
3493 if (srcData == NULL || cnt < 0)
3494 return WINED3DERR_INVALIDCALL;
3496 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3497 for (i = 0; i < cnt; i++)
3498 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3499 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3501 for (i = start; i < cnt + start; ++i) {
3502 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3507 return WINED3D_OK;
3510 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3511 IWineD3DDevice *iface,
3512 UINT start,
3513 int *dstData,
3514 UINT count) {
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 int cnt = min(count, MAX_CONST_I - start);
3519 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3520 iface, dstData, start, count);
3522 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3523 return WINED3DERR_INVALIDCALL;
3525 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3526 return WINED3D_OK;
3529 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3530 IWineD3DDevice *iface,
3531 UINT start,
3532 CONST float *srcData,
3533 UINT count) {
3535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3536 int i;
3538 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3539 iface, srcData, start, count);
3541 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3542 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3543 return WINED3DERR_INVALIDCALL;
3545 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3546 if(TRACE_ON(d3d)) {
3547 for (i = 0; i < count; i++)
3548 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3549 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3552 for (i = start; i < count + start; ++i) {
3553 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3554 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3555 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3556 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3557 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3559 ptr->idx[ptr->count++] = i;
3560 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3566 return WINED3D_OK;
3569 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3570 IWineD3DDevice *iface,
3571 UINT start,
3572 CONST float *srcData,
3573 UINT count) {
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3576 int i;
3578 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3579 iface, srcData, start, count);
3581 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3582 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3583 return WINED3DERR_INVALIDCALL;
3585 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3586 if(TRACE_ON(d3d)) {
3587 for (i = 0; i < count; i++)
3588 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3589 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3592 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3593 * context. On a context switch the old context will be fully dirtified
3595 memset(This->activeContext->vshader_const_dirty + start, 1,
3596 sizeof(*This->activeContext->vshader_const_dirty) * count);
3597 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3601 return WINED3D_OK;
3604 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3605 IWineD3DDevice *iface,
3606 UINT start,
3607 float *dstData,
3608 UINT count) {
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3611 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3613 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3614 iface, dstData, start, count);
3616 if (dstData == NULL || cnt < 0)
3617 return WINED3DERR_INVALIDCALL;
3619 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3620 return WINED3D_OK;
3623 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3624 DWORD i;
3625 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3630 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3631 int i = This->rev_tex_unit_map[unit];
3632 int j = This->texUnitMap[stage];
3634 This->texUnitMap[stage] = unit;
3635 if (i != -1 && i != stage) {
3636 This->texUnitMap[i] = -1;
3639 This->rev_tex_unit_map[unit] = stage;
3640 if (j != -1 && j != unit) {
3641 This->rev_tex_unit_map[j] = -1;
3645 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3646 int i;
3648 for (i = 0; i < MAX_TEXTURES; ++i) {
3649 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3650 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3651 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3652 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3653 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3654 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3655 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3656 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3658 if (color_op == WINED3DTOP_DISABLE) {
3659 /* Not used, and disable higher stages */
3660 while (i < MAX_TEXTURES) {
3661 This->fixed_function_usage_map[i] = FALSE;
3662 ++i;
3664 break;
3667 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3668 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3669 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3670 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3671 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3672 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3673 This->fixed_function_usage_map[i] = TRUE;
3674 } else {
3675 This->fixed_function_usage_map[i] = FALSE;
3678 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3679 This->fixed_function_usage_map[i+1] = TRUE;
3684 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3685 int i, tex;
3687 device_update_fixed_function_usage_map(This);
3689 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3690 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3691 if (!This->fixed_function_usage_map[i]) continue;
3693 if (This->texUnitMap[i] != i) {
3694 device_map_stage(This, i, i);
3695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3696 markTextureStagesDirty(This, i);
3699 return;
3702 /* Now work out the mapping */
3703 tex = 0;
3704 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3705 if (!This->fixed_function_usage_map[i]) continue;
3707 if (This->texUnitMap[i] != tex) {
3708 device_map_stage(This, i, tex);
3709 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3710 markTextureStagesDirty(This, i);
3713 ++tex;
3717 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3718 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3719 int i;
3721 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3722 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3723 device_map_stage(This, i, i);
3724 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3725 if (i < MAX_TEXTURES) {
3726 markTextureStagesDirty(This, i);
3732 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3733 int current_mapping = This->rev_tex_unit_map[unit];
3735 if (current_mapping == -1) {
3736 /* Not currently used */
3737 return TRUE;
3740 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3741 /* Used by a fragment sampler */
3743 if (!pshader_sampler_tokens) {
3744 /* No pixel shader, check fixed function */
3745 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3748 /* Pixel shader, check the shader's sampler map */
3749 return !pshader_sampler_tokens[current_mapping];
3752 /* Used by a vertex sampler */
3753 return !vshader_sampler_tokens[current_mapping];
3756 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3757 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3758 DWORD *pshader_sampler_tokens = NULL;
3759 int start = GL_LIMITS(combined_samplers) - 1;
3760 int i;
3762 if (ps) {
3763 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3765 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3766 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3767 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3770 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3771 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3772 if (vshader_sampler_tokens[i]) {
3773 if (This->texUnitMap[vsampler_idx] != -1) {
3774 /* Already mapped somewhere */
3775 continue;
3778 while (start >= 0) {
3779 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3780 device_map_stage(This, vsampler_idx, start);
3781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3783 --start;
3784 break;
3787 --start;
3793 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3794 BOOL vs = use_vs(This);
3795 BOOL ps = use_ps(This);
3797 * Rules are:
3798 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3799 * that would be really messy and require shader recompilation
3800 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3801 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3803 if (ps) {
3804 device_map_psamplers(This);
3805 } else {
3806 device_map_fixed_function_samplers(This);
3809 if (vs) {
3810 device_map_vsamplers(This, ps);
3814 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3816 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3817 This->updateStateBlock->pixelShader = pShader;
3818 This->updateStateBlock->changed.pixelShader = TRUE;
3820 /* Handle recording of state blocks */
3821 if (This->isRecordingState) {
3822 TRACE("Recording... not performing anything\n");
3825 if (This->isRecordingState) {
3826 TRACE("Recording... not performing anything\n");
3827 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3828 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3829 return WINED3D_OK;
3832 if(pShader == oldShader) {
3833 TRACE("App is setting the old pixel shader over, nothing to do\n");
3834 return WINED3D_OK;
3837 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3838 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3840 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3843 return WINED3D_OK;
3846 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3849 if (NULL == ppShader) {
3850 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3851 return WINED3DERR_INVALIDCALL;
3854 *ppShader = This->stateBlock->pixelShader;
3855 if (NULL != *ppShader) {
3856 IWineD3DPixelShader_AddRef(*ppShader);
3858 TRACE("(%p) : returning %p\n", This, *ppShader);
3859 return WINED3D_OK;
3862 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3863 IWineD3DDevice *iface,
3864 UINT start,
3865 CONST BOOL *srcData,
3866 UINT count) {
3868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3869 int i, cnt = min(count, MAX_CONST_B - start);
3871 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3872 iface, srcData, start, count);
3874 if (srcData == NULL || cnt < 0)
3875 return WINED3DERR_INVALIDCALL;
3877 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3878 for (i = 0; i < cnt; i++)
3879 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3881 for (i = start; i < cnt + start; ++i) {
3882 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3887 return WINED3D_OK;
3890 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3891 IWineD3DDevice *iface,
3892 UINT start,
3893 BOOL *dstData,
3894 UINT count) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 int cnt = min(count, MAX_CONST_B - start);
3899 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3900 iface, dstData, start, count);
3902 if (dstData == NULL || cnt < 0)
3903 return WINED3DERR_INVALIDCALL;
3905 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3906 return WINED3D_OK;
3909 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3910 IWineD3DDevice *iface,
3911 UINT start,
3912 CONST int *srcData,
3913 UINT count) {
3915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3916 int i, cnt = min(count, MAX_CONST_I - start);
3918 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3919 iface, srcData, start, count);
3921 if (srcData == NULL || cnt < 0)
3922 return WINED3DERR_INVALIDCALL;
3924 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3925 for (i = 0; i < cnt; i++)
3926 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3927 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3929 for (i = start; i < cnt + start; ++i) {
3930 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3933 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3935 return WINED3D_OK;
3938 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3939 IWineD3DDevice *iface,
3940 UINT start,
3941 int *dstData,
3942 UINT count) {
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3945 int cnt = min(count, MAX_CONST_I - start);
3947 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3948 iface, dstData, start, count);
3950 if (dstData == NULL || cnt < 0)
3951 return WINED3DERR_INVALIDCALL;
3953 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3954 return WINED3D_OK;
3957 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3958 IWineD3DDevice *iface,
3959 UINT start,
3960 CONST float *srcData,
3961 UINT count) {
3963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3964 int i;
3966 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3967 iface, srcData, start, count);
3969 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3970 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3971 return WINED3DERR_INVALIDCALL;
3973 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3974 if(TRACE_ON(d3d)) {
3975 for (i = 0; i < count; i++)
3976 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3977 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3980 for (i = start; i < count + start; ++i) {
3981 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3982 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3983 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3984 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3985 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3987 ptr->idx[ptr->count++] = i;
3988 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3994 return WINED3D_OK;
3997 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
3998 IWineD3DDevice *iface,
3999 UINT start,
4000 CONST float *srcData,
4001 UINT count) {
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4004 int i;
4006 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4007 iface, srcData, start, count);
4009 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4010 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4011 return WINED3DERR_INVALIDCALL;
4013 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4014 if(TRACE_ON(d3d)) {
4015 for (i = 0; i < count; i++)
4016 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4017 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4020 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4021 * context. On a context switch the old context will be fully dirtified
4023 memset(This->activeContext->pshader_const_dirty + start, 1,
4024 sizeof(*This->activeContext->pshader_const_dirty) * count);
4025 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
4027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4029 return WINED3D_OK;
4032 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4033 IWineD3DDevice *iface,
4034 UINT start,
4035 float *dstData,
4036 UINT count) {
4038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4039 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4041 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4042 iface, dstData, start, count);
4044 if (dstData == NULL || cnt < 0)
4045 return WINED3DERR_INVALIDCALL;
4047 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4048 return WINED3D_OK;
4051 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4052 static HRESULT
4053 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4054 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4055 unsigned int i;
4056 DWORD DestFVF = dest->fvf;
4057 WINED3DVIEWPORT vp;
4058 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4059 BOOL doClip;
4060 int numTextures;
4062 if (lpStrideData->u.s.normal.lpData) {
4063 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4066 if (lpStrideData->u.s.position.lpData == NULL) {
4067 ERR("Source has no position mask\n");
4068 return WINED3DERR_INVALIDCALL;
4071 /* We might access VBOs from this code, so hold the lock */
4072 ENTER_GL();
4074 if (dest->resource.allocatedMemory == NULL) {
4075 /* This may happen if we do direct locking into a vbo. Unlikely,
4076 * but theoretically possible(ddraw processvertices test)
4078 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4079 if(!dest->resource.allocatedMemory) {
4080 LEAVE_GL();
4081 ERR("Out of memory\n");
4082 return E_OUTOFMEMORY;
4084 if(dest->vbo) {
4085 void *src;
4086 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4087 checkGLcall("glBindBufferARB");
4088 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4089 if(src) {
4090 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4092 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4093 checkGLcall("glUnmapBufferARB");
4097 /* Get a pointer into the destination vbo(create one if none exists) and
4098 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4100 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4101 dest->Flags |= VBFLAG_CREATEVBO;
4102 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4105 if(dest->vbo) {
4106 unsigned char extrabytes = 0;
4107 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4108 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4109 * this may write 4 extra bytes beyond the area that should be written
4111 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4112 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4113 if(!dest_conv_addr) {
4114 ERR("Out of memory\n");
4115 /* Continue without storing converted vertices */
4117 dest_conv = dest_conv_addr;
4120 /* Should I clip?
4121 * a) WINED3DRS_CLIPPING is enabled
4122 * b) WINED3DVOP_CLIP is passed
4124 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4125 static BOOL warned = FALSE;
4127 * The clipping code is not quite correct. Some things need
4128 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4129 * so disable clipping for now.
4130 * (The graphics in Half-Life are broken, and my processvertices
4131 * test crashes with IDirect3DDevice3)
4132 doClip = TRUE;
4134 doClip = FALSE;
4135 if(!warned) {
4136 warned = TRUE;
4137 FIXME("Clipping is broken and disabled for now\n");
4139 } else doClip = FALSE;
4140 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4142 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4143 WINED3DTS_VIEW,
4144 &view_mat);
4145 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4146 WINED3DTS_PROJECTION,
4147 &proj_mat);
4148 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4149 WINED3DTS_WORLDMATRIX(0),
4150 &world_mat);
4152 TRACE("View mat:\n");
4153 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);
4154 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);
4155 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);
4156 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);
4158 TRACE("Proj mat:\n");
4159 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);
4160 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);
4161 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);
4162 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);
4164 TRACE("World mat:\n");
4165 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);
4166 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);
4167 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);
4168 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);
4170 /* Get the viewport */
4171 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4172 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4173 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4175 multiply_matrix(&mat,&view_mat,&world_mat);
4176 multiply_matrix(&mat,&proj_mat,&mat);
4178 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4180 for (i = 0; i < dwCount; i+= 1) {
4181 unsigned int tex_index;
4183 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4184 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4185 /* The position first */
4186 float *p =
4187 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4188 float x, y, z, rhw;
4189 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4191 /* Multiplication with world, view and projection matrix */
4192 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);
4193 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);
4194 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);
4195 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);
4197 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4199 /* WARNING: The following things are taken from d3d7 and were not yet checked
4200 * against d3d8 or d3d9!
4203 /* Clipping conditions: From msdn
4205 * A vertex is clipped if it does not match the following requirements
4206 * -rhw < x <= rhw
4207 * -rhw < y <= rhw
4208 * 0 < z <= rhw
4209 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4211 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4212 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4216 if( !doClip ||
4217 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4218 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4219 ( rhw > eps ) ) ) {
4221 /* "Normal" viewport transformation (not clipped)
4222 * 1) The values are divided by rhw
4223 * 2) The y axis is negative, so multiply it with -1
4224 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4225 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4226 * 4) Multiply x with Width/2 and add Width/2
4227 * 5) The same for the height
4228 * 6) Add the viewpoint X and Y to the 2D coordinates and
4229 * The minimum Z value to z
4230 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4232 * Well, basically it's simply a linear transformation into viewport
4233 * coordinates
4236 x /= rhw;
4237 y /= rhw;
4238 z /= rhw;
4240 y *= -1;
4242 x *= vp.Width / 2;
4243 y *= vp.Height / 2;
4244 z *= vp.MaxZ - vp.MinZ;
4246 x += vp.Width / 2 + vp.X;
4247 y += vp.Height / 2 + vp.Y;
4248 z += vp.MinZ;
4250 rhw = 1 / rhw;
4251 } else {
4252 /* That vertex got clipped
4253 * Contrary to OpenGL it is not dropped completely, it just
4254 * undergoes a different calculation.
4256 TRACE("Vertex got clipped\n");
4257 x += rhw;
4258 y += rhw;
4260 x /= 2;
4261 y /= 2;
4263 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4264 * outside of the main vertex buffer memory. That needs some more
4265 * investigation...
4269 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4272 ( (float *) dest_ptr)[0] = x;
4273 ( (float *) dest_ptr)[1] = y;
4274 ( (float *) dest_ptr)[2] = z;
4275 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4277 dest_ptr += 3 * sizeof(float);
4279 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4280 dest_ptr += sizeof(float);
4283 if(dest_conv) {
4284 float w = 1 / rhw;
4285 ( (float *) dest_conv)[0] = x * w;
4286 ( (float *) dest_conv)[1] = y * w;
4287 ( (float *) dest_conv)[2] = z * w;
4288 ( (float *) dest_conv)[3] = w;
4290 dest_conv += 3 * sizeof(float);
4292 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4293 dest_conv += sizeof(float);
4297 if (DestFVF & WINED3DFVF_PSIZE) {
4298 dest_ptr += sizeof(DWORD);
4299 if(dest_conv) dest_conv += sizeof(DWORD);
4301 if (DestFVF & WINED3DFVF_NORMAL) {
4302 float *normal =
4303 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4304 /* AFAIK this should go into the lighting information */
4305 FIXME("Didn't expect the destination to have a normal\n");
4306 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4307 if(dest_conv) {
4308 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4312 if (DestFVF & WINED3DFVF_DIFFUSE) {
4313 DWORD *color_d =
4314 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4315 if(!color_d) {
4316 static BOOL warned = FALSE;
4318 if(!warned) {
4319 ERR("No diffuse color in source, but destination has one\n");
4320 warned = TRUE;
4323 *( (DWORD *) dest_ptr) = 0xffffffff;
4324 dest_ptr += sizeof(DWORD);
4326 if(dest_conv) {
4327 *( (DWORD *) dest_conv) = 0xffffffff;
4328 dest_conv += sizeof(DWORD);
4331 else {
4332 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4333 if(dest_conv) {
4334 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4335 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4336 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4337 dest_conv += sizeof(DWORD);
4342 if (DestFVF & WINED3DFVF_SPECULAR) {
4343 /* What's the color value in the feedback buffer? */
4344 DWORD *color_s =
4345 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4346 if(!color_s) {
4347 static BOOL warned = FALSE;
4349 if(!warned) {
4350 ERR("No specular color in source, but destination has one\n");
4351 warned = TRUE;
4354 *( (DWORD *) dest_ptr) = 0xFF000000;
4355 dest_ptr += sizeof(DWORD);
4357 if(dest_conv) {
4358 *( (DWORD *) dest_conv) = 0xFF000000;
4359 dest_conv += sizeof(DWORD);
4362 else {
4363 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4364 if(dest_conv) {
4365 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4366 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4367 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4368 dest_conv += sizeof(DWORD);
4373 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4374 float *tex_coord =
4375 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4376 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4377 if(!tex_coord) {
4378 ERR("No source texture, but destination requests one\n");
4379 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4380 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4382 else {
4383 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4384 if(dest_conv) {
4385 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4391 if(dest_conv) {
4392 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4393 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4394 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4395 dwCount * get_flexible_vertex_size(DestFVF),
4396 dest_conv_addr));
4397 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4398 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4401 LEAVE_GL();
4403 return WINED3D_OK;
4405 #undef copy_and_next
4407 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4409 WineDirect3DVertexStridedData strided;
4410 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4411 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4413 if(pVertexDecl) {
4414 ERR("Output vertex declaration not implemented yet\n");
4417 /* Need any context to write to the vbo. */
4418 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4420 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4421 * control the streamIsUP flag, thus restore it afterwards.
4423 This->stateBlock->streamIsUP = FALSE;
4424 memset(&strided, 0, sizeof(strided));
4425 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4426 This->stateBlock->streamIsUP = streamWasUP;
4428 if(vbo || SrcStartIndex) {
4429 unsigned int i;
4430 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4431 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4433 * Also get the start index in, but only loop over all elements if there's something to add at all.
4435 #define FIXSRC(type) \
4436 if(strided.u.s.type.VBO) { \
4437 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4438 strided.u.s.type.VBO = 0; \
4439 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4440 ENTER_GL(); \
4441 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4442 vb->vbo = 0; \
4443 LEAVE_GL(); \
4445 if(strided.u.s.type.lpData) { \
4446 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4448 FIXSRC(position);
4449 FIXSRC(blendWeights);
4450 FIXSRC(blendMatrixIndices);
4451 FIXSRC(normal);
4452 FIXSRC(pSize);
4453 FIXSRC(diffuse);
4454 FIXSRC(specular);
4455 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4456 FIXSRC(texCoords[i]);
4458 FIXSRC(position2);
4459 FIXSRC(normal2);
4460 FIXSRC(tangent);
4461 FIXSRC(binormal);
4462 FIXSRC(tessFactor);
4463 FIXSRC(fog);
4464 FIXSRC(depth);
4465 FIXSRC(sample);
4466 #undef FIXSRC
4469 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4472 /*****
4473 * Get / Set Texture Stage States
4474 * TODO: Verify against dx9 definitions
4475 *****/
4476 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4478 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4480 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4482 if (Stage >= MAX_TEXTURES) {
4483 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4484 return WINED3D_OK;
4487 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4488 This->updateStateBlock->textureState[Stage][Type] = Value;
4490 if (This->isRecordingState) {
4491 TRACE("Recording... not performing anything\n");
4492 return WINED3D_OK;
4495 /* Checked after the assignments to allow proper stateblock recording */
4496 if(oldValue == Value) {
4497 TRACE("App is setting the old value over, nothing to do\n");
4498 return WINED3D_OK;
4501 if(Stage > This->stateBlock->lowest_disabled_stage &&
4502 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4503 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4504 * Changes in other states are important on disabled stages too
4506 return WINED3D_OK;
4509 if(Type == WINED3DTSS_COLOROP) {
4510 int i;
4512 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4513 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4514 * they have to be disabled
4516 * The current stage is dirtified below.
4518 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4519 TRACE("Additionally dirtifying stage %d\n", i);
4520 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4522 This->stateBlock->lowest_disabled_stage = Stage;
4523 TRACE("New lowest disabled: %d\n", Stage);
4524 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4525 /* Previously disabled stage enabled. Stages above it may need enabling
4526 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4527 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4529 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4532 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4533 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4534 break;
4536 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4537 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4539 This->stateBlock->lowest_disabled_stage = i;
4540 TRACE("New lowest disabled: %d\n", i);
4542 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4543 /* TODO: Built a stage -> texture unit mapping for register combiners */
4547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4549 return WINED3D_OK;
4552 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4554 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4555 *pValue = This->updateStateBlock->textureState[Stage][Type];
4556 return WINED3D_OK;
4559 /*****
4560 * Get / Set Texture
4561 *****/
4562 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4564 IWineD3DBaseTexture *oldTexture;
4566 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4568 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4569 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4572 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4573 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4574 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4577 oldTexture = This->updateStateBlock->textures[Stage];
4579 if(pTexture != NULL) {
4580 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4582 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4583 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4584 return WINED3DERR_INVALIDCALL;
4586 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4589 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4590 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4592 This->updateStateBlock->changed.textures[Stage] = TRUE;
4593 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4594 This->updateStateBlock->textures[Stage] = pTexture;
4596 /* Handle recording of state blocks */
4597 if (This->isRecordingState) {
4598 TRACE("Recording... not performing anything\n");
4599 return WINED3D_OK;
4602 if(oldTexture == pTexture) {
4603 TRACE("App is setting the same texture again, nothing to do\n");
4604 return WINED3D_OK;
4607 /** NOTE: MSDN says that setTexture increases the reference count,
4608 * and that the application must set the texture back to null (or have a leaky application),
4609 * This means we should pass the refcount up to the parent
4610 *******************************/
4611 if (NULL != This->updateStateBlock->textures[Stage]) {
4612 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4613 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4615 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4616 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4617 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4618 * so the COLOROP and ALPHAOP have to be dirtified.
4620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4623 if(bindCount == 1) {
4624 new->baseTexture.sampler = Stage;
4626 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4630 if (NULL != oldTexture) {
4631 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4632 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4634 IWineD3DBaseTexture_Release(oldTexture);
4635 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4637 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4640 if(bindCount && old->baseTexture.sampler == Stage) {
4641 int i;
4642 /* Have to do a search for the other sampler(s) where the texture is bound to
4643 * Shouldn't happen as long as apps bind a texture only to one stage
4645 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4646 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4647 if(This->updateStateBlock->textures[i] == oldTexture) {
4648 old->baseTexture.sampler = i;
4649 break;
4655 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4657 return WINED3D_OK;
4660 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4663 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4665 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4666 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4669 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4670 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4671 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4674 *ppTexture=This->stateBlock->textures[Stage];
4675 if (*ppTexture)
4676 IWineD3DBaseTexture_AddRef(*ppTexture);
4678 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4680 return WINED3D_OK;
4683 /*****
4684 * Get Back Buffer
4685 *****/
4686 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4687 IWineD3DSurface **ppBackBuffer) {
4688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4689 IWineD3DSwapChain *swapChain;
4690 HRESULT hr;
4692 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4694 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4695 if (hr == WINED3D_OK) {
4696 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4697 IWineD3DSwapChain_Release(swapChain);
4698 } else {
4699 *ppBackBuffer = NULL;
4701 return hr;
4704 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 WARN("(%p) : stub, calling idirect3d for now\n", This);
4707 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4710 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4712 IWineD3DSwapChain *swapChain;
4713 HRESULT hr;
4715 if(iSwapChain > 0) {
4716 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4717 if (hr == WINED3D_OK) {
4718 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4719 IWineD3DSwapChain_Release(swapChain);
4720 } else {
4721 FIXME("(%p) Error getting display mode\n", This);
4723 } else {
4724 /* Don't read the real display mode,
4725 but return the stored mode instead. X11 can't change the color
4726 depth, and some apps are pretty angry if they SetDisplayMode from
4727 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4729 Also don't relay to the swapchain because with ddraw it's possible
4730 that there isn't a swapchain at all */
4731 pMode->Width = This->ddraw_width;
4732 pMode->Height = This->ddraw_height;
4733 pMode->Format = This->ddraw_format;
4734 pMode->RefreshRate = 0;
4735 hr = WINED3D_OK;
4738 return hr;
4741 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4743 TRACE("(%p)->(%p)\n", This, hWnd);
4745 if(This->ddraw_fullscreen) {
4746 if(This->ddraw_window && This->ddraw_window != hWnd) {
4747 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4749 if(hWnd && This->ddraw_window != hWnd) {
4750 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4754 This->ddraw_window = hWnd;
4755 return WINED3D_OK;
4758 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 TRACE("(%p)->(%p)\n", This, hWnd);
4762 *hWnd = This->ddraw_window;
4763 return WINED3D_OK;
4766 /*****
4767 * Stateblock related functions
4768 *****/
4770 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4772 IWineD3DStateBlockImpl *object;
4773 HRESULT temp_result;
4774 int i;
4776 TRACE("(%p)\n", This);
4778 if (This->isRecordingState) {
4779 return WINED3DERR_INVALIDCALL;
4782 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4783 if (NULL == object ) {
4784 FIXME("(%p)Error allocating memory for stateblock\n", This);
4785 return E_OUTOFMEMORY;
4787 TRACE("(%p) created object %p\n", This, object);
4788 object->wineD3DDevice= This;
4789 /** FIXME: object->parent = parent; **/
4790 object->parent = NULL;
4791 object->blockType = WINED3DSBT_RECORDED;
4792 object->ref = 1;
4793 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4795 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4796 list_init(&object->lightMap[i]);
4799 temp_result = allocate_shader_constants(object);
4800 if (WINED3D_OK != temp_result)
4801 return temp_result;
4803 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4804 This->updateStateBlock = object;
4805 This->isRecordingState = TRUE;
4807 TRACE("(%p) recording stateblock %p\n",This , object);
4808 return WINED3D_OK;
4811 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4813 unsigned int i, j;
4814 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4816 if (!This->isRecordingState) {
4817 FIXME("(%p) not recording! returning error\n", This);
4818 *ppStateBlock = NULL;
4819 return WINED3DERR_INVALIDCALL;
4822 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4823 if(object->changed.renderState[i]) {
4824 object->contained_render_states[object->num_contained_render_states] = i;
4825 object->num_contained_render_states++;
4828 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4829 if(object->changed.transform[i]) {
4830 object->contained_transform_states[object->num_contained_transform_states] = i;
4831 object->num_contained_transform_states++;
4834 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4835 if(object->changed.vertexShaderConstantsF[i]) {
4836 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4837 object->num_contained_vs_consts_f++;
4840 for(i = 0; i < MAX_CONST_I; i++) {
4841 if(object->changed.vertexShaderConstantsI[i]) {
4842 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4843 object->num_contained_vs_consts_i++;
4846 for(i = 0; i < MAX_CONST_B; i++) {
4847 if(object->changed.vertexShaderConstantsB[i]) {
4848 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4849 object->num_contained_vs_consts_b++;
4852 for(i = 0; i < MAX_CONST_I; i++) {
4853 if(object->changed.pixelShaderConstantsI[i]) {
4854 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4855 object->num_contained_ps_consts_i++;
4858 for(i = 0; i < MAX_CONST_B; i++) {
4859 if(object->changed.pixelShaderConstantsB[i]) {
4860 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4861 object->num_contained_ps_consts_b++;
4864 for(i = 0; i < MAX_TEXTURES; i++) {
4865 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4866 if(object->changed.textureState[i][j]) {
4867 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4868 object->contained_tss_states[object->num_contained_tss_states].state = j;
4869 object->num_contained_tss_states++;
4873 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4874 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4875 if(object->changed.samplerState[i][j]) {
4876 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4877 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4878 object->num_contained_sampler_states++;
4883 *ppStateBlock = (IWineD3DStateBlock*) object;
4884 This->isRecordingState = FALSE;
4885 This->updateStateBlock = This->stateBlock;
4886 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4887 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4888 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4889 return WINED3D_OK;
4892 /*****
4893 * Scene related functions
4894 *****/
4895 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4896 /* At the moment we have no need for any functionality at the beginning
4897 of a scene */
4898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 TRACE("(%p)\n", This);
4901 if(This->inScene) {
4902 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4903 return WINED3DERR_INVALIDCALL;
4905 This->inScene = TRUE;
4906 return WINED3D_OK;
4909 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4911 TRACE("(%p)\n", This);
4913 if(!This->inScene) {
4914 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4915 return WINED3DERR_INVALIDCALL;
4918 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4919 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4920 ENTER_GL();
4921 glFlush();
4922 checkGLcall("glFlush");
4923 LEAVE_GL();
4925 This->inScene = FALSE;
4926 return WINED3D_OK;
4929 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4930 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4931 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4933 IWineD3DSwapChain *swapChain = NULL;
4934 int i;
4935 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4937 TRACE("(%p) Presenting the frame\n", This);
4939 for(i = 0 ; i < swapchains ; i ++) {
4941 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4942 TRACE("presentinng chain %d, %p\n", i, swapChain);
4943 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4944 IWineD3DSwapChain_Release(swapChain);
4947 return WINED3D_OK;
4950 /* Not called from the VTable (internal subroutine) */
4951 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4952 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4953 float Z, DWORD Stencil) {
4954 GLbitfield glMask = 0;
4955 unsigned int i;
4956 WINED3DRECT curRect;
4957 RECT vp_rect;
4958 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4959 UINT drawable_width, drawable_height;
4960 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4962 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4963 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4964 * for the cleared parts, and the untouched parts.
4966 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4967 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4968 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4969 * checking all this if the dest surface is in the drawable anyway.
4971 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4972 while(1) {
4973 if(vp->X != 0 || vp->Y != 0 ||
4974 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4975 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4976 break;
4978 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4979 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4980 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4981 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4982 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4983 break;
4985 if(Count > 0 && pRects && (
4986 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4987 pRects[0].x2 < target->currentDesc.Width ||
4988 pRects[0].y2 < target->currentDesc.Height)) {
4989 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4990 break;
4992 break;
4996 target->get_drawable_size(target, &drawable_width, &drawable_height);
4998 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4999 ENTER_GL();
5001 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5002 apply_fbo_state((IWineD3DDevice *) This);
5005 /* Only set the values up once, as they are not changing */
5006 if (Flags & WINED3DCLEAR_STENCIL) {
5007 glClearStencil(Stencil);
5008 checkGLcall("glClearStencil");
5009 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5010 glStencilMask(0xFFFFFFFF);
5013 if (Flags & WINED3DCLEAR_ZBUFFER) {
5014 glDepthMask(GL_TRUE);
5015 glClearDepth(Z);
5016 checkGLcall("glClearDepth");
5017 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5018 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5020 if(This->depth_copy_state == WINED3D_DCS_COPY) {
5021 if(vp->X != 0 || vp->Y != 0 ||
5022 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5023 depth_copy((IWineD3DDevice *) This);
5025 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5026 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5027 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5028 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5029 depth_copy((IWineD3DDevice *) This);
5031 else if(Count > 0 && pRects && (
5032 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5033 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5034 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5035 depth_copy((IWineD3DDevice *) This);
5038 This->depth_copy_state = WINED3D_DCS_INITIAL;
5041 if (Flags & WINED3DCLEAR_TARGET) {
5042 TRACE("Clearing screen with glClear to color %x\n", Color);
5043 glClearColor(D3DCOLOR_R(Color),
5044 D3DCOLOR_G(Color),
5045 D3DCOLOR_B(Color),
5046 D3DCOLOR_A(Color));
5047 checkGLcall("glClearColor");
5049 /* Clear ALL colors! */
5050 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5051 glMask = glMask | GL_COLOR_BUFFER_BIT;
5054 vp_rect.left = vp->X;
5055 vp_rect.top = vp->Y;
5056 vp_rect.right = vp->X + vp->Width;
5057 vp_rect.bottom = vp->Y + vp->Height;
5058 if (!(Count > 0 && pRects)) {
5059 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5060 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5062 if(This->render_offscreen) {
5063 glScissor(vp_rect.left, vp_rect.top,
5064 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5065 } else {
5066 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5067 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5069 checkGLcall("glScissor");
5070 glClear(glMask);
5071 checkGLcall("glClear");
5072 } else {
5073 /* Now process each rect in turn */
5074 for (i = 0; i < Count; i++) {
5075 /* Note gl uses lower left, width/height */
5076 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5077 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5078 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5080 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5081 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5082 curRect.x1, (target->currentDesc.Height - curRect.y2),
5083 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5085 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5086 * The rectangle is not cleared, no error is returned, but further rectanlges are
5087 * still cleared if they are valid
5089 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5090 TRACE("Rectangle with negative dimensions, ignoring\n");
5091 continue;
5094 if(This->render_offscreen) {
5095 glScissor(curRect.x1, curRect.y1,
5096 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5097 } else {
5098 glScissor(curRect.x1, drawable_height - curRect.y2,
5099 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5101 checkGLcall("glScissor");
5103 glClear(glMask);
5104 checkGLcall("glClear");
5108 /* Restore the old values (why..?) */
5109 if (Flags & WINED3DCLEAR_STENCIL) {
5110 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5112 if (Flags & WINED3DCLEAR_TARGET) {
5113 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5114 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5115 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5116 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5117 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5119 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5120 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5122 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5123 /* TODO: Move the fbo logic into ModifyLocation() */
5124 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5125 target->Flags |= SFLAG_INTEXTURE;
5128 LEAVE_GL();
5130 return WINED3D_OK;
5133 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5134 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5138 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5139 Count, pRects, Flags, Color, Z, Stencil);
5141 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5142 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5143 /* TODO: What about depth stencil buffers without stencil bits? */
5144 return WINED3DERR_INVALIDCALL;
5147 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5150 /*****
5151 * Drawing functions
5152 *****/
5153 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5154 UINT PrimitiveCount) {
5156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5158 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5159 debug_d3dprimitivetype(PrimitiveType),
5160 StartVertex, PrimitiveCount);
5162 if(!This->stateBlock->vertexDecl) {
5163 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5164 return WINED3DERR_INVALIDCALL;
5167 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5168 if(This->stateBlock->streamIsUP) {
5169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5170 This->stateBlock->streamIsUP = FALSE;
5173 if(This->stateBlock->loadBaseVertexIndex != 0) {
5174 This->stateBlock->loadBaseVertexIndex = 0;
5175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5177 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5178 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5179 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5180 return WINED3D_OK;
5183 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5184 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5185 WINED3DPRIMITIVETYPE PrimitiveType,
5186 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5189 UINT idxStride = 2;
5190 IWineD3DIndexBuffer *pIB;
5191 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5192 GLuint vbo;
5194 pIB = This->stateBlock->pIndexData;
5195 if (!pIB) {
5196 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5197 * without an index buffer set. (The first time at least...)
5198 * D3D8 simply dies, but I doubt it can do much harm to return
5199 * D3DERR_INVALIDCALL there as well. */
5200 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5201 return WINED3DERR_INVALIDCALL;
5204 if(!This->stateBlock->vertexDecl) {
5205 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5206 return WINED3DERR_INVALIDCALL;
5209 if(This->stateBlock->streamIsUP) {
5210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5211 This->stateBlock->streamIsUP = FALSE;
5213 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5215 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5216 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5217 minIndex, NumVertices, startIndex, primCount);
5219 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5220 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5221 idxStride = 2;
5222 } else {
5223 idxStride = 4;
5226 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5227 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5231 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5232 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5234 return WINED3D_OK;
5237 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5238 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5239 UINT VertexStreamZeroStride) {
5240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5241 IWineD3DVertexBuffer *vb;
5243 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5244 debug_d3dprimitivetype(PrimitiveType),
5245 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5247 if(!This->stateBlock->vertexDecl) {
5248 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5249 return WINED3DERR_INVALIDCALL;
5252 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5253 vb = This->stateBlock->streamSource[0];
5254 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5255 if(vb) IWineD3DVertexBuffer_Release(vb);
5256 This->stateBlock->streamOffset[0] = 0;
5257 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5258 This->stateBlock->streamIsUP = TRUE;
5259 This->stateBlock->loadBaseVertexIndex = 0;
5261 /* TODO: Only mark dirty if drawing from a different UP address */
5262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5264 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5265 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5267 /* MSDN specifies stream zero settings must be set to NULL */
5268 This->stateBlock->streamStride[0] = 0;
5269 This->stateBlock->streamSource[0] = NULL;
5271 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5272 * the new stream sources or use UP drawing again
5274 return WINED3D_OK;
5277 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5278 UINT MinVertexIndex, UINT NumVertices,
5279 UINT PrimitiveCount, CONST void* pIndexData,
5280 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5281 UINT VertexStreamZeroStride) {
5282 int idxStride;
5283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5284 IWineD3DVertexBuffer *vb;
5285 IWineD3DIndexBuffer *ib;
5287 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5288 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5289 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5290 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5292 if(!This->stateBlock->vertexDecl) {
5293 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5294 return WINED3DERR_INVALIDCALL;
5297 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5298 idxStride = 2;
5299 } else {
5300 idxStride = 4;
5303 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5304 vb = This->stateBlock->streamSource[0];
5305 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5306 if(vb) IWineD3DVertexBuffer_Release(vb);
5307 This->stateBlock->streamIsUP = TRUE;
5308 This->stateBlock->streamOffset[0] = 0;
5309 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5311 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5312 This->stateBlock->baseVertexIndex = 0;
5313 This->stateBlock->loadBaseVertexIndex = 0;
5314 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5318 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5320 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5321 This->stateBlock->streamSource[0] = NULL;
5322 This->stateBlock->streamStride[0] = 0;
5323 ib = This->stateBlock->pIndexData;
5324 if(ib) {
5325 IWineD3DIndexBuffer_Release(ib);
5326 This->stateBlock->pIndexData = NULL;
5328 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5329 * SetStreamSource to specify a vertex buffer
5332 return WINED3D_OK;
5335 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5338 /* Mark the state dirty until we have nicer tracking
5339 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5340 * that value.
5342 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5344 This->stateBlock->baseVertexIndex = 0;
5345 This->up_strided = DrawPrimStrideData;
5346 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5347 This->up_strided = NULL;
5348 return WINED3D_OK;
5351 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5353 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5355 /* Mark the state dirty until we have nicer tracking
5356 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5357 * that value.
5359 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5361 This->stateBlock->streamIsUP = TRUE;
5362 This->stateBlock->baseVertexIndex = 0;
5363 This->up_strided = DrawPrimStrideData;
5364 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5365 This->up_strided = NULL;
5366 return WINED3D_OK;
5369 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5370 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5371 * not callable by the app directly no parameter validation checks are needed here.
5373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5374 WINED3DLOCKED_BOX src;
5375 WINED3DLOCKED_BOX dst;
5376 HRESULT hr;
5377 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5379 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5380 * dirtification to improve loading performance.
5382 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5383 if(FAILED(hr)) return hr;
5384 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5385 if(FAILED(hr)) {
5386 IWineD3DVolume_UnlockBox(pSourceVolume);
5387 return hr;
5390 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5392 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5393 if(FAILED(hr)) {
5394 IWineD3DVolume_UnlockBox(pSourceVolume);
5395 } else {
5396 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5398 return hr;
5401 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5402 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5404 HRESULT hr = WINED3D_OK;
5405 WINED3DRESOURCETYPE sourceType;
5406 WINED3DRESOURCETYPE destinationType;
5407 int i ,levels;
5409 /* TODO: think about moving the code into IWineD3DBaseTexture */
5411 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5413 /* verify that the source and destination textures aren't NULL */
5414 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5415 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5416 This, pSourceTexture, pDestinationTexture);
5417 hr = WINED3DERR_INVALIDCALL;
5420 if (pSourceTexture == pDestinationTexture) {
5421 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5422 This, pSourceTexture, pDestinationTexture);
5423 hr = WINED3DERR_INVALIDCALL;
5425 /* Verify that the source and destination textures are the same type */
5426 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5427 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5429 if (sourceType != destinationType) {
5430 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5431 This);
5432 hr = WINED3DERR_INVALIDCALL;
5435 /* check that both textures have the identical numbers of levels */
5436 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5437 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5438 hr = WINED3DERR_INVALIDCALL;
5441 if (WINED3D_OK == hr) {
5443 /* Make sure that the destination texture is loaded */
5444 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5446 /* Update every surface level of the texture */
5447 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5449 switch (sourceType) {
5450 case WINED3DRTYPE_TEXTURE:
5452 IWineD3DSurface *srcSurface;
5453 IWineD3DSurface *destSurface;
5455 for (i = 0 ; i < levels ; ++i) {
5456 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5457 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5458 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5459 IWineD3DSurface_Release(srcSurface);
5460 IWineD3DSurface_Release(destSurface);
5461 if (WINED3D_OK != hr) {
5462 WARN("(%p) : Call to update surface failed\n", This);
5463 return hr;
5467 break;
5468 case WINED3DRTYPE_CUBETEXTURE:
5470 IWineD3DSurface *srcSurface;
5471 IWineD3DSurface *destSurface;
5472 WINED3DCUBEMAP_FACES faceType;
5474 for (i = 0 ; i < levels ; ++i) {
5475 /* Update each cube face */
5476 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5477 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5478 if (WINED3D_OK != hr) {
5479 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5480 } else {
5481 TRACE("Got srcSurface %p\n", srcSurface);
5483 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5484 if (WINED3D_OK != hr) {
5485 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5486 } else {
5487 TRACE("Got desrSurface %p\n", destSurface);
5489 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5490 IWineD3DSurface_Release(srcSurface);
5491 IWineD3DSurface_Release(destSurface);
5492 if (WINED3D_OK != hr) {
5493 WARN("(%p) : Call to update surface failed\n", This);
5494 return hr;
5499 break;
5501 case WINED3DRTYPE_VOLUMETEXTURE:
5503 IWineD3DVolume *srcVolume = NULL;
5504 IWineD3DVolume *destVolume = NULL;
5506 for (i = 0 ; i < levels ; ++i) {
5507 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5508 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5509 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5510 IWineD3DVolume_Release(srcVolume);
5511 IWineD3DVolume_Release(destVolume);
5512 if (WINED3D_OK != hr) {
5513 WARN("(%p) : Call to update volume failed\n", This);
5514 return hr;
5518 break;
5520 default:
5521 FIXME("(%p) : Unsupported source and destination type\n", This);
5522 hr = WINED3DERR_INVALIDCALL;
5526 return hr;
5529 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5530 IWineD3DSwapChain *swapChain;
5531 HRESULT hr;
5532 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5533 if(hr == WINED3D_OK) {
5534 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5535 IWineD3DSwapChain_Release(swapChain);
5537 return hr;
5540 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5542 /* return a sensible default */
5543 *pNumPasses = 1;
5544 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5545 FIXME("(%p) : stub\n", This);
5546 return WINED3D_OK;
5549 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5551 int i;
5553 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5554 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5555 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5556 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5561 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 int j;
5564 UINT NewSize;
5565 PALETTEENTRY **palettes;
5567 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5569 if (PaletteNumber >= MAX_PALETTES) {
5570 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5571 return WINED3DERR_INVALIDCALL;
5574 if (PaletteNumber >= This->NumberOfPalettes) {
5575 NewSize = This->NumberOfPalettes;
5576 do {
5577 NewSize *= 2;
5578 } while(PaletteNumber >= NewSize);
5579 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5580 if (!palettes) {
5581 ERR("Out of memory!\n");
5582 return E_OUTOFMEMORY;
5584 This->palettes = palettes;
5585 This->NumberOfPalettes = NewSize;
5588 if (!This->palettes[PaletteNumber]) {
5589 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5590 if (!This->palettes[PaletteNumber]) {
5591 ERR("Out of memory!\n");
5592 return E_OUTOFMEMORY;
5596 for (j = 0; j < 256; ++j) {
5597 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5598 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5599 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5600 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5602 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5603 TRACE("(%p) : returning\n", This);
5604 return WINED3D_OK;
5607 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5609 int j;
5610 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5611 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5612 /* What happens in such situation isn't documented; Native seems to silently abort
5613 on such conditions. Return Invalid Call. */
5614 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5615 return WINED3DERR_INVALIDCALL;
5617 for (j = 0; j < 256; ++j) {
5618 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5619 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5620 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5621 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5623 TRACE("(%p) : returning\n", This);
5624 return WINED3D_OK;
5627 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5630 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5631 (tested with reference rasterizer). Return Invalid Call. */
5632 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5633 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5634 return WINED3DERR_INVALIDCALL;
5636 /*TODO: stateblocks */
5637 if (This->currentPalette != PaletteNumber) {
5638 This->currentPalette = PaletteNumber;
5639 dirtify_p8_texture_samplers(This);
5641 TRACE("(%p) : returning\n", This);
5642 return WINED3D_OK;
5645 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 if (PaletteNumber == NULL) {
5648 WARN("(%p) : returning Invalid Call\n", This);
5649 return WINED3DERR_INVALIDCALL;
5651 /*TODO: stateblocks */
5652 *PaletteNumber = This->currentPalette;
5653 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5654 return WINED3D_OK;
5657 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 static BOOL showFixmes = TRUE;
5660 if (showFixmes) {
5661 FIXME("(%p) : stub\n", This);
5662 showFixmes = FALSE;
5665 This->softwareVertexProcessing = bSoftware;
5666 return WINED3D_OK;
5670 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5672 static BOOL showFixmes = TRUE;
5673 if (showFixmes) {
5674 FIXME("(%p) : stub\n", This);
5675 showFixmes = FALSE;
5677 return This->softwareVertexProcessing;
5681 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5683 IWineD3DSwapChain *swapChain;
5684 HRESULT hr;
5686 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5688 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5689 if(hr == WINED3D_OK){
5690 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5691 IWineD3DSwapChain_Release(swapChain);
5692 }else{
5693 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5695 return hr;
5699 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5701 static BOOL showfixmes = TRUE;
5702 if(nSegments != 0.0f) {
5703 if( showfixmes) {
5704 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5705 showfixmes = FALSE;
5708 return WINED3D_OK;
5711 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 static BOOL showfixmes = TRUE;
5714 if( showfixmes) {
5715 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5716 showfixmes = FALSE;
5718 return 0.0f;
5721 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5723 /** TODO: remove casts to IWineD3DSurfaceImpl
5724 * NOTE: move code to surface to accomplish this
5725 ****************************************/
5726 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5727 int srcWidth, srcHeight;
5728 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5729 WINED3DFORMAT destFormat, srcFormat;
5730 UINT destSize;
5731 int srcLeft, destLeft, destTop;
5732 WINED3DPOOL srcPool, destPool;
5733 int offset = 0;
5734 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5735 glDescriptor *glDescription = NULL;
5736 GLenum dummy;
5737 int bpp;
5738 CONVERT_TYPES convert = NO_CONVERSION;
5740 WINED3DSURFACE_DESC winedesc;
5742 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5743 memset(&winedesc, 0, sizeof(winedesc));
5744 winedesc.Width = &srcSurfaceWidth;
5745 winedesc.Height = &srcSurfaceHeight;
5746 winedesc.Pool = &srcPool;
5747 winedesc.Format = &srcFormat;
5749 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5751 winedesc.Width = &destSurfaceWidth;
5752 winedesc.Height = &destSurfaceHeight;
5753 winedesc.Pool = &destPool;
5754 winedesc.Format = &destFormat;
5755 winedesc.Size = &destSize;
5757 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5759 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5760 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5761 return WINED3DERR_INVALIDCALL;
5764 /* This call loads the opengl surface directly, instead of copying the surface to the
5765 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5766 * copy in sysmem and use regular surface loading.
5768 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5769 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5770 if(convert != NO_CONVERSION) {
5771 return IWineD3DSurface_BltFast(pDestinationSurface,
5772 pDestPoint ? pDestPoint->x : 0,
5773 pDestPoint ? pDestPoint->y : 0,
5774 pSourceSurface, (RECT *) pSourceRect, 0);
5777 if (destFormat == WINED3DFMT_UNKNOWN) {
5778 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5779 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5781 /* Get the update surface description */
5782 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5785 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5787 ENTER_GL();
5789 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5790 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5791 checkGLcall("glActiveTextureARB");
5794 /* Make sure the surface is loaded and up to date */
5795 IWineD3DSurface_PreLoad(pDestinationSurface);
5797 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5799 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5800 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5801 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5802 srcLeft = pSourceRect ? pSourceRect->left : 0;
5803 destLeft = pDestPoint ? pDestPoint->x : 0;
5804 destTop = pDestPoint ? pDestPoint->y : 0;
5807 /* This function doesn't support compressed textures
5808 the pitch is just bytesPerPixel * width */
5809 if(srcWidth != srcSurfaceWidth || srcLeft ){
5810 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5811 offset += srcLeft * pSrcSurface->bytesPerPixel;
5812 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5814 /* TODO DXT formats */
5816 if(pSourceRect != NULL && pSourceRect->top != 0){
5817 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5819 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5820 ,This
5821 ,glDescription->level
5822 ,destLeft
5823 ,destTop
5824 ,srcWidth
5825 ,srcHeight
5826 ,glDescription->glFormat
5827 ,glDescription->glType
5828 ,IWineD3DSurface_GetData(pSourceSurface)
5831 /* Sanity check */
5832 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5834 /* need to lock the surface to get the data */
5835 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5838 /* TODO: Cube and volume support */
5839 if(rowoffset != 0){
5840 /* not a whole row so we have to do it a line at a time */
5841 int j;
5843 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5844 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5846 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5848 glTexSubImage2D(glDescription->target
5849 ,glDescription->level
5850 ,destLeft
5852 ,srcWidth
5854 ,glDescription->glFormat
5855 ,glDescription->glType
5856 ,data /* could be quicker using */
5858 data += rowoffset;
5861 } else { /* Full width, so just write out the whole texture */
5863 if (WINED3DFMT_DXT1 == destFormat ||
5864 WINED3DFMT_DXT2 == destFormat ||
5865 WINED3DFMT_DXT3 == destFormat ||
5866 WINED3DFMT_DXT4 == destFormat ||
5867 WINED3DFMT_DXT5 == destFormat) {
5868 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5869 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5870 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5871 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5872 } if (destFormat != srcFormat) {
5873 FIXME("Updating mixed format compressed texture is not curretly support\n");
5874 } else {
5875 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5876 glDescription->level,
5877 glDescription->glFormatInternal,
5878 srcWidth,
5879 srcHeight,
5881 destSize,
5882 IWineD3DSurface_GetData(pSourceSurface));
5884 } else {
5885 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5889 } else {
5890 glTexSubImage2D(glDescription->target
5891 ,glDescription->level
5892 ,destLeft
5893 ,destTop
5894 ,srcWidth
5895 ,srcHeight
5896 ,glDescription->glFormat
5897 ,glDescription->glType
5898 ,IWineD3DSurface_GetData(pSourceSurface)
5902 checkGLcall("glTexSubImage2D");
5904 LEAVE_GL();
5906 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5909 return WINED3D_OK;
5912 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5914 struct WineD3DRectPatch *patch;
5915 unsigned int i;
5916 struct list *e;
5917 BOOL found;
5918 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5920 if(!(Handle || pRectPatchInfo)) {
5921 /* TODO: Write a test for the return value, thus the FIXME */
5922 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5923 return WINED3DERR_INVALIDCALL;
5926 if(Handle) {
5927 i = PATCHMAP_HASHFUNC(Handle);
5928 found = FALSE;
5929 LIST_FOR_EACH(e, &This->patches[i]) {
5930 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5931 if(patch->Handle == Handle) {
5932 found = TRUE;
5933 break;
5937 if(!found) {
5938 TRACE("Patch does not exist. Creating a new one\n");
5939 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5940 patch->Handle = Handle;
5941 list_add_head(&This->patches[i], &patch->entry);
5942 } else {
5943 TRACE("Found existing patch %p\n", patch);
5945 } else {
5946 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5947 * attributes we have to tesselate, read back, and draw. This needs a patch
5948 * management structure instance. Create one.
5950 * A possible improvement is to check if a vertex shader is used, and if not directly
5951 * draw the patch.
5953 FIXME("Drawing an uncached patch. This is slow\n");
5954 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5957 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5958 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5959 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5960 HRESULT hr;
5961 TRACE("Tesselation density or patch info changed, retesselating\n");
5963 if(pRectPatchInfo) {
5964 patch->RectPatchInfo = *pRectPatchInfo;
5966 patch->numSegs[0] = pNumSegs[0];
5967 patch->numSegs[1] = pNumSegs[1];
5968 patch->numSegs[2] = pNumSegs[2];
5969 patch->numSegs[3] = pNumSegs[3];
5971 hr = tesselate_rectpatch(This, patch);
5972 if(FAILED(hr)) {
5973 WARN("Patch tesselation failed\n");
5975 /* Do not release the handle to store the params of the patch */
5976 if(!Handle) {
5977 HeapFree(GetProcessHeap(), 0, patch);
5979 return hr;
5983 This->currentPatch = patch;
5984 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5985 This->currentPatch = NULL;
5987 /* Destroy uncached patches */
5988 if(!Handle) {
5989 HeapFree(GetProcessHeap(), 0, patch->mem);
5990 HeapFree(GetProcessHeap(), 0, patch);
5992 return WINED3D_OK;
5995 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5997 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5998 FIXME("(%p) : Stub\n", This);
5999 return WINED3D_OK;
6002 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6004 int i;
6005 struct WineD3DRectPatch *patch;
6006 struct list *e;
6007 TRACE("(%p) Handle(%d)\n", This, Handle);
6009 i = PATCHMAP_HASHFUNC(Handle);
6010 LIST_FOR_EACH(e, &This->patches[i]) {
6011 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6012 if(patch->Handle == Handle) {
6013 TRACE("Deleting patch %p\n", patch);
6014 list_remove(&patch->entry);
6015 HeapFree(GetProcessHeap(), 0, patch->mem);
6016 HeapFree(GetProcessHeap(), 0, patch);
6017 return WINED3D_OK;
6021 /* TODO: Write a test for the return value */
6022 FIXME("Attempt to destroy nonexistent patch\n");
6023 return WINED3DERR_INVALIDCALL;
6026 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6027 HRESULT hr;
6028 IWineD3DSwapChain *swapchain;
6030 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6031 if (SUCCEEDED(hr)) {
6032 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6033 return swapchain;
6036 return NULL;
6039 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6042 if (!*fbo) {
6043 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6044 checkGLcall("glGenFramebuffersEXT()");
6046 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6047 checkGLcall("glBindFramebuffer()");
6050 /* TODO: Handle stencil attachments */
6051 static void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6052 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6054 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6055 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6056 checkGLcall("glFramebufferRenderbufferEXT()");
6057 } else {
6058 IWineD3DBaseTextureImpl *texture_impl;
6059 GLenum texttarget, target;
6060 GLint old_binding = 0;
6062 texttarget = depth_stencil_impl->glDescription.target;
6063 if(texttarget == GL_TEXTURE_2D) {
6064 target = GL_TEXTURE_2D;
6065 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6066 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6067 target = GL_TEXTURE_RECTANGLE_ARB;
6068 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6069 } else {
6070 target = GL_TEXTURE_CUBE_MAP_ARB;
6071 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6074 IWineD3DSurface_PreLoad(depth_stencil);
6076 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6077 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6078 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6079 glBindTexture(target, old_binding);
6081 /* Update base texture states array */
6082 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6083 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6084 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6085 if (texture_impl->baseTexture.bindCount) {
6086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6089 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6092 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6093 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6094 checkGLcall("glFramebufferTexture2DEXT()");
6098 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6099 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6100 IWineD3DBaseTextureImpl *texture_impl;
6101 GLenum texttarget, target;
6102 GLint old_binding;
6104 texttarget = surface_impl->glDescription.target;
6105 if(texttarget == GL_TEXTURE_2D) {
6106 target = GL_TEXTURE_2D;
6107 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6108 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6109 target = GL_TEXTURE_RECTANGLE_ARB;
6110 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6111 } else {
6112 target = GL_TEXTURE_CUBE_MAP_ARB;
6113 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6116 IWineD3DSurface_PreLoad(surface);
6118 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6119 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6120 glBindTexture(target, old_binding);
6122 /* Update base texture states array */
6123 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6124 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6125 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6126 if (texture_impl->baseTexture.bindCount) {
6127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6130 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6133 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6134 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6136 checkGLcall("attach_surface_fbo");
6139 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6141 IWineD3DSwapChain *swapchain;
6143 swapchain = get_swapchain(surface);
6144 if (swapchain) {
6145 GLenum buffer;
6147 TRACE("Surface %p is onscreen\n", surface);
6149 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6150 buffer = surface_get_gl_buffer(surface, swapchain);
6151 glDrawBuffer(buffer);
6152 checkGLcall("glDrawBuffer()");
6153 } else {
6154 TRACE("Surface %p is offscreen\n", surface);
6155 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6156 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6159 if (rect) {
6160 glEnable(GL_SCISSOR_TEST);
6161 if(!swapchain) {
6162 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6163 } else {
6164 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6165 rect->x2 - rect->x1, rect->y2 - rect->y1);
6167 checkGLcall("glScissor");
6168 } else {
6169 glDisable(GL_SCISSOR_TEST);
6171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6173 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6176 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6177 glClear(GL_COLOR_BUFFER_BIT);
6178 checkGLcall("glClear");
6180 if (This->render_offscreen) {
6181 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6182 } else {
6183 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6184 checkGLcall("glBindFramebuffer()");
6187 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6188 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6189 glDrawBuffer(GL_BACK);
6190 checkGLcall("glDrawBuffer()");
6194 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6195 unsigned int r, g, b, a;
6196 DWORD ret;
6198 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6199 destfmt == WINED3DFMT_R8G8B8)
6200 return color;
6202 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6204 a = (color & 0xff000000) >> 24;
6205 r = (color & 0x00ff0000) >> 16;
6206 g = (color & 0x0000ff00) >> 8;
6207 b = (color & 0x000000ff) >> 0;
6209 switch(destfmt)
6211 case WINED3DFMT_R5G6B5:
6212 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6213 r = (r * 32) / 256;
6214 g = (g * 64) / 256;
6215 b = (b * 32) / 256;
6216 ret = r << 11;
6217 ret |= g << 5;
6218 ret |= b;
6219 TRACE("Returning %08x\n", ret);
6220 return ret;
6222 case WINED3DFMT_X1R5G5B5:
6223 case WINED3DFMT_A1R5G5B5:
6224 a = (a * 2) / 256;
6225 r = (r * 32) / 256;
6226 g = (g * 32) / 256;
6227 b = (b * 32) / 256;
6228 ret = a << 15;
6229 ret |= r << 10;
6230 ret |= g << 5;
6231 ret |= b << 0;
6232 TRACE("Returning %08x\n", ret);
6233 return ret;
6235 case WINED3DFMT_A8:
6236 TRACE("Returning %08x\n", a);
6237 return a;
6239 case WINED3DFMT_X4R4G4B4:
6240 case WINED3DFMT_A4R4G4B4:
6241 a = (a * 16) / 256;
6242 r = (r * 16) / 256;
6243 g = (g * 16) / 256;
6244 b = (b * 16) / 256;
6245 ret = a << 12;
6246 ret |= r << 8;
6247 ret |= g << 4;
6248 ret |= b << 0;
6249 TRACE("Returning %08x\n", ret);
6250 return ret;
6252 case WINED3DFMT_R3G3B2:
6253 r = (r * 8) / 256;
6254 g = (g * 8) / 256;
6255 b = (b * 4) / 256;
6256 ret = r << 5;
6257 ret |= g << 2;
6258 ret |= b << 0;
6259 TRACE("Returning %08x\n", ret);
6260 return ret;
6262 case WINED3DFMT_X8B8G8R8:
6263 case WINED3DFMT_A8B8G8R8:
6264 ret = a << 24;
6265 ret |= b << 16;
6266 ret |= g << 8;
6267 ret |= r << 0;
6268 TRACE("Returning %08x\n", ret);
6269 return ret;
6271 case WINED3DFMT_A2R10G10B10:
6272 a = (a * 4) / 256;
6273 r = (r * 1024) / 256;
6274 g = (g * 1024) / 256;
6275 b = (b * 1024) / 256;
6276 ret = a << 30;
6277 ret |= r << 20;
6278 ret |= g << 10;
6279 ret |= b << 0;
6280 TRACE("Returning %08x\n", ret);
6281 return ret;
6283 case WINED3DFMT_A2B10G10R10:
6284 a = (a * 4) / 256;
6285 r = (r * 1024) / 256;
6286 g = (g * 1024) / 256;
6287 b = (b * 1024) / 256;
6288 ret = a << 30;
6289 ret |= b << 20;
6290 ret |= g << 10;
6291 ret |= r << 0;
6292 TRACE("Returning %08x\n", ret);
6293 return ret;
6295 default:
6296 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6297 return 0;
6301 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6303 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6304 WINEDDBLTFX BltFx;
6305 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6307 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6308 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6309 return WINED3DERR_INVALIDCALL;
6312 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6313 ENTER_GL();
6314 color_fill_fbo(iface, pSurface, pRect, color);
6315 LEAVE_GL();
6316 return WINED3D_OK;
6317 } else {
6318 /* Just forward this to the DirectDraw blitting engine */
6319 memset(&BltFx, 0, sizeof(BltFx));
6320 BltFx.dwSize = sizeof(BltFx);
6321 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6322 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6326 /* rendertarget and depth stencil functions */
6327 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6330 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6331 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6332 return WINED3DERR_INVALIDCALL;
6335 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6336 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6337 /* Note inc ref on returned surface */
6338 if(*ppRenderTarget != NULL)
6339 IWineD3DSurface_AddRef(*ppRenderTarget);
6340 return WINED3D_OK;
6343 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6345 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6346 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6347 IWineD3DSwapChainImpl *Swapchain;
6348 HRESULT hr;
6350 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6352 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6353 if(hr != WINED3D_OK) {
6354 ERR("Can't get the swapchain\n");
6355 return hr;
6358 /* Make sure to release the swapchain */
6359 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6361 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6362 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6363 return WINED3DERR_INVALIDCALL;
6365 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6366 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6367 return WINED3DERR_INVALIDCALL;
6370 if(Swapchain->frontBuffer != Front) {
6371 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6373 if(Swapchain->frontBuffer)
6374 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6375 Swapchain->frontBuffer = Front;
6377 if(Swapchain->frontBuffer) {
6378 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6382 if(Back && !Swapchain->backBuffer) {
6383 /* We need memory for the back buffer array - only one back buffer this way */
6384 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6385 if(!Swapchain->backBuffer) {
6386 ERR("Out of memory\n");
6387 return E_OUTOFMEMORY;
6391 if(Swapchain->backBuffer[0] != Back) {
6392 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6394 /* What to do about the context here in the case of multithreading? Not sure.
6395 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6397 ENTER_GL();
6398 if(!Swapchain->backBuffer[0]) {
6399 /* GL was told to draw to the front buffer at creation,
6400 * undo that
6402 glDrawBuffer(GL_BACK);
6403 checkGLcall("glDrawBuffer(GL_BACK)");
6404 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6405 Swapchain->presentParms.BackBufferCount = 1;
6406 } else if (!Back) {
6407 /* That makes problems - disable for now */
6408 /* glDrawBuffer(GL_FRONT); */
6409 checkGLcall("glDrawBuffer(GL_FRONT)");
6410 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6411 Swapchain->presentParms.BackBufferCount = 0;
6413 LEAVE_GL();
6415 if(Swapchain->backBuffer[0])
6416 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6417 Swapchain->backBuffer[0] = Back;
6419 if(Swapchain->backBuffer[0]) {
6420 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6421 } else {
6422 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6423 Swapchain->backBuffer = NULL;
6428 return WINED3D_OK;
6431 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6433 *ppZStencilSurface = This->stencilBufferTarget;
6434 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6436 if(*ppZStencilSurface != NULL) {
6437 /* Note inc ref on returned surface */
6438 IWineD3DSurface_AddRef(*ppZStencilSurface);
6439 return WINED3D_OK;
6440 } else {
6441 return WINED3DERR_NOTFOUND;
6445 /* TODO: Handle stencil attachments */
6446 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6449 TRACE("Set depth stencil to %p\n", depth_stencil);
6451 if (depth_stencil) {
6452 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6453 } else {
6454 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6455 checkGLcall("glFramebufferTexture2DEXT()");
6459 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6462 TRACE("Set render target %u to %p\n", idx, render_target);
6464 if (render_target) {
6465 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6466 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6467 } else {
6468 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6469 checkGLcall("glFramebufferTexture2DEXT()");
6471 This->draw_buffers[idx] = GL_NONE;
6475 static void check_fbo_status(IWineD3DDevice *iface) {
6476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6477 GLenum status;
6479 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6480 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6481 TRACE("FBO complete\n");
6482 } else {
6483 IWineD3DSurfaceImpl *attachment;
6484 int i;
6485 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6487 /* Dump the FBO attachments */
6488 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6489 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6490 if (attachment) {
6491 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6492 attachment->pow2Width, attachment->pow2Height);
6495 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6496 if (attachment) {
6497 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6498 attachment->pow2Width, attachment->pow2Height);
6503 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6505 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6506 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6508 if (!ds_impl) return FALSE;
6510 if (ds_impl->current_renderbuffer) {
6511 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6512 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6515 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6516 rt_impl->pow2Height != ds_impl->pow2Height);
6519 void apply_fbo_state(IWineD3DDevice *iface) {
6520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6521 unsigned int i;
6523 if (This->render_offscreen) {
6524 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6526 /* Apply render targets */
6527 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6528 IWineD3DSurface *render_target = This->render_targets[i];
6529 if (This->fbo_color_attachments[i] != render_target) {
6530 set_render_target_fbo(iface, i, render_target);
6531 This->fbo_color_attachments[i] = render_target;
6535 /* Apply depth targets */
6536 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6537 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6538 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6540 if (This->stencilBufferTarget) {
6541 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6543 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6544 This->fbo_depth_attachment = This->stencilBufferTarget;
6547 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6548 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6549 checkGLcall("glDrawBuffers()");
6550 } else {
6551 glDrawBuffer(This->draw_buffers[0]);
6552 checkGLcall("glDrawBuffer()");
6554 } else {
6555 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6558 check_fbo_status(iface);
6561 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6562 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6564 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6565 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6566 GLenum gl_filter;
6568 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6569 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6570 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6571 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6573 switch (filter) {
6574 case WINED3DTEXF_LINEAR:
6575 gl_filter = GL_LINEAR;
6576 break;
6578 default:
6579 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6580 case WINED3DTEXF_NONE:
6581 case WINED3DTEXF_POINT:
6582 gl_filter = GL_NEAREST;
6583 break;
6586 /* Attach src surface to src fbo */
6587 src_swapchain = get_swapchain(src_surface);
6588 if (src_swapchain) {
6589 GLenum buffer;
6591 TRACE("Source surface %p is onscreen\n", src_surface);
6592 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6593 /* Make sure the drawable is up to date. In the offscreen case
6594 * attach_surface_fbo() implicitly takes care of this. */
6595 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6597 ENTER_GL();
6598 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6599 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6600 glReadBuffer(buffer);
6601 checkGLcall("glReadBuffer()");
6603 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6604 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6605 } else {
6606 TRACE("Source surface %p is offscreen\n", src_surface);
6607 ENTER_GL();
6608 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6609 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6610 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6611 checkGLcall("glReadBuffer()");
6613 LEAVE_GL();
6615 /* Attach dst surface to dst fbo */
6616 dst_swapchain = get_swapchain(dst_surface);
6617 if (dst_swapchain) {
6618 GLenum buffer;
6620 TRACE("Destination surface %p is onscreen\n", dst_surface);
6621 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6622 /* Make sure the drawable is up to date. In the offscreen case
6623 * attach_surface_fbo() implicitly takes care of this. */
6624 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6626 ENTER_GL();
6627 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6628 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6629 glDrawBuffer(buffer);
6630 checkGLcall("glDrawBuffer()");
6632 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6633 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6634 } else {
6635 TRACE("Destination surface %p is offscreen\n", dst_surface);
6637 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6638 if(!src_swapchain) {
6639 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6642 ENTER_GL();
6643 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6644 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6645 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6646 checkGLcall("glDrawBuffer()");
6648 glDisable(GL_SCISSOR_TEST);
6649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6651 if (flip) {
6652 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6653 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6654 checkGLcall("glBlitFramebuffer()");
6655 } else {
6656 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6657 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6658 checkGLcall("glBlitFramebuffer()");
6661 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6663 if (This->render_offscreen) {
6664 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6665 } else {
6666 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6667 checkGLcall("glBindFramebuffer()");
6670 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6671 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6672 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6673 glDrawBuffer(GL_BACK);
6674 checkGLcall("glDrawBuffer()");
6676 LEAVE_GL();
6679 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6681 WINED3DVIEWPORT viewport;
6683 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6685 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6686 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6687 This, RenderTargetIndex, GL_LIMITS(buffers));
6688 return WINED3DERR_INVALIDCALL;
6691 /* MSDN says that null disables the render target
6692 but a device must always be associated with a render target
6693 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6695 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6696 FIXME("Trying to set render target 0 to NULL\n");
6697 return WINED3DERR_INVALIDCALL;
6699 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6700 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);
6701 return WINED3DERR_INVALIDCALL;
6704 /* If we are trying to set what we already have, don't bother */
6705 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6706 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6707 return WINED3D_OK;
6709 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6710 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6711 This->render_targets[RenderTargetIndex] = pRenderTarget;
6713 /* Render target 0 is special */
6714 if(RenderTargetIndex == 0) {
6715 /* Finally, reset the viewport as the MSDN states. */
6716 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6717 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6718 viewport.X = 0;
6719 viewport.Y = 0;
6720 viewport.MaxZ = 1.0f;
6721 viewport.MinZ = 0.0f;
6722 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6723 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6724 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6728 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6729 * ctx properly.
6730 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6731 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6733 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6735 return WINED3D_OK;
6738 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6740 HRESULT hr = WINED3D_OK;
6741 IWineD3DSurface *tmp;
6743 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6745 if (pNewZStencil == This->stencilBufferTarget) {
6746 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6747 } else {
6748 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6749 * depending on the renter target implementation being used.
6750 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6751 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6752 * stencil buffer and incur an extra memory overhead
6753 ******************************************************/
6755 tmp = This->stencilBufferTarget;
6756 This->stencilBufferTarget = pNewZStencil;
6757 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6758 /* should we be calling the parent or the wined3d surface? */
6759 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6760 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6761 hr = WINED3D_OK;
6763 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6764 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6765 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6771 return hr;
6774 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6775 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6777 /* TODO: the use of Impl is deprecated. */
6778 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6779 WINED3DLOCKED_RECT lockedRect;
6781 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6783 /* some basic validation checks */
6784 if(This->cursorTexture) {
6785 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6786 ENTER_GL();
6787 glDeleteTextures(1, &This->cursorTexture);
6788 LEAVE_GL();
6789 This->cursorTexture = 0;
6792 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6793 This->haveHardwareCursor = TRUE;
6794 else
6795 This->haveHardwareCursor = FALSE;
6797 if(pCursorBitmap) {
6798 WINED3DLOCKED_RECT rect;
6800 /* MSDN: Cursor must be A8R8G8B8 */
6801 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6802 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6803 return WINED3DERR_INVALIDCALL;
6806 /* MSDN: Cursor must be smaller than the display mode */
6807 if(pSur->currentDesc.Width > This->ddraw_width ||
6808 pSur->currentDesc.Height > This->ddraw_height) {
6809 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);
6810 return WINED3DERR_INVALIDCALL;
6813 if (!This->haveHardwareCursor) {
6814 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6816 /* Do not store the surface's pointer because the application may
6817 * release it after setting the cursor image. Windows doesn't
6818 * addref the set surface, so we can't do this either without
6819 * creating circular refcount dependencies. Copy out the gl texture
6820 * instead.
6822 This->cursorWidth = pSur->currentDesc.Width;
6823 This->cursorHeight = pSur->currentDesc.Height;
6824 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6826 const GlPixelFormatDesc *glDesc;
6827 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6828 char *mem, *bits = (char *)rect.pBits;
6829 GLint intfmt = glDesc->glInternal;
6830 GLint format = glDesc->glFormat;
6831 GLint type = glDesc->glType;
6832 INT height = This->cursorHeight;
6833 INT width = This->cursorWidth;
6834 INT bpp = tableEntry->bpp;
6835 INT i;
6837 /* Reformat the texture memory (pitch and width can be
6838 * different) */
6839 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6840 for(i = 0; i < height; i++)
6841 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6842 IWineD3DSurface_UnlockRect(pCursorBitmap);
6843 ENTER_GL();
6845 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6846 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6847 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6850 /* Make sure that a proper texture unit is selected */
6851 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6852 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6853 checkGLcall("glActiveTextureARB");
6855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6856 /* Create a new cursor texture */
6857 glGenTextures(1, &This->cursorTexture);
6858 checkGLcall("glGenTextures");
6859 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6860 checkGLcall("glBindTexture");
6861 /* Copy the bitmap memory into the cursor texture */
6862 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6863 HeapFree(GetProcessHeap(), 0, mem);
6864 checkGLcall("glTexImage2D");
6866 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6867 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6868 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6871 LEAVE_GL();
6873 else
6875 FIXME("A cursor texture was not returned.\n");
6876 This->cursorTexture = 0;
6879 else
6881 /* Draw a hardware cursor */
6882 ICONINFO cursorInfo;
6883 HCURSOR cursor;
6884 /* Create and clear maskBits because it is not needed for
6885 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6886 * chunks. */
6887 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6888 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6889 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6890 WINED3DLOCK_NO_DIRTY_UPDATE |
6891 WINED3DLOCK_READONLY
6893 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6894 pSur->currentDesc.Height);
6896 cursorInfo.fIcon = FALSE;
6897 cursorInfo.xHotspot = XHotSpot;
6898 cursorInfo.yHotspot = YHotSpot;
6899 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6900 pSur->currentDesc.Height, 1,
6901 1, &maskBits);
6902 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6903 pSur->currentDesc.Height, 1,
6904 32, lockedRect.pBits);
6905 IWineD3DSurface_UnlockRect(pCursorBitmap);
6906 /* Create our cursor and clean up. */
6907 cursor = CreateIconIndirect(&cursorInfo);
6908 SetCursor(cursor);
6909 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6910 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6911 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6912 This->hardwareCursor = cursor;
6913 HeapFree(GetProcessHeap(), 0, maskBits);
6917 This->xHotSpot = XHotSpot;
6918 This->yHotSpot = YHotSpot;
6919 return WINED3D_OK;
6922 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6924 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6926 This->xScreenSpace = XScreenSpace;
6927 This->yScreenSpace = YScreenSpace;
6929 return;
6933 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6935 BOOL oldVisible = This->bCursorVisible;
6936 POINT pt;
6938 TRACE("(%p) : visible(%d)\n", This, bShow);
6941 * When ShowCursor is first called it should make the cursor appear at the OS's last
6942 * known cursor position. Because of this, some applications just repetitively call
6943 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6945 GetCursorPos(&pt);
6946 This->xScreenSpace = pt.x;
6947 This->yScreenSpace = pt.y;
6949 if (This->haveHardwareCursor) {
6950 This->bCursorVisible = bShow;
6951 if (bShow)
6952 SetCursor(This->hardwareCursor);
6953 else
6954 SetCursor(NULL);
6956 else
6958 if (This->cursorTexture)
6959 This->bCursorVisible = bShow;
6962 return oldVisible;
6965 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6967 IWineD3DResourceImpl *resource;
6968 TRACE("(%p) : state (%u)\n", This, This->state);
6970 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6971 switch (This->state) {
6972 case WINED3D_OK:
6973 return WINED3D_OK;
6974 case WINED3DERR_DEVICELOST:
6976 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6977 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6978 return WINED3DERR_DEVICENOTRESET;
6980 return WINED3DERR_DEVICELOST;
6982 case WINED3DERR_DRIVERINTERNALERROR:
6983 return WINED3DERR_DRIVERINTERNALERROR;
6986 /* Unknown state */
6987 return WINED3DERR_DRIVERINTERNALERROR;
6991 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6993 /** FIXME: Resource tracking needs to be done,
6994 * The closes we can do to this is set the priorities of all managed textures low
6995 * and then reset them.
6996 ***********************************************************/
6997 FIXME("(%p) : stub\n", This);
6998 return WINED3D_OK;
7001 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7002 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7004 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7005 if(surface->Flags & SFLAG_DIBSECTION) {
7006 /* Release the DC */
7007 SelectObject(surface->hDC, surface->dib.holdbitmap);
7008 DeleteDC(surface->hDC);
7009 /* Release the DIB section */
7010 DeleteObject(surface->dib.DIBsection);
7011 surface->dib.bitmap_data = NULL;
7012 surface->resource.allocatedMemory = NULL;
7013 surface->Flags &= ~SFLAG_DIBSECTION;
7015 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7016 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7017 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
7018 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7019 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7020 } else {
7021 surface->pow2Width = surface->pow2Height = 1;
7022 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7023 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7025 surface->glRect.left = 0;
7026 surface->glRect.top = 0;
7027 surface->glRect.right = surface->pow2Width;
7028 surface->glRect.bottom = surface->pow2Height;
7030 if(surface->glDescription.textureName) {
7031 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7032 ENTER_GL();
7033 glDeleteTextures(1, &surface->glDescription.textureName);
7034 LEAVE_GL();
7035 surface->glDescription.textureName = 0;
7036 surface->Flags &= ~SFLAG_CLIENT;
7038 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7039 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7040 surface->Flags |= SFLAG_NONPOW2;
7041 } else {
7042 surface->Flags &= ~SFLAG_NONPOW2;
7044 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7045 surface->resource.allocatedMemory = NULL;
7046 surface->resource.heapMemory = NULL;
7047 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7048 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7049 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7050 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7051 } else {
7052 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7056 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7057 TRACE("Unloading resource %p\n", resource);
7058 IWineD3DResource_UnLoad(resource);
7059 IWineD3DResource_Release(resource);
7060 return S_OK;
7063 static void reset_fbo_state(IWineD3DDevice *iface) {
7064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7065 unsigned int i;
7067 ENTER_GL();
7068 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7069 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7071 if (This->fbo) {
7072 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7073 This->fbo = 0;
7075 if (This->src_fbo) {
7076 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7077 This->src_fbo = 0;
7079 if (This->dst_fbo) {
7080 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7081 This->dst_fbo = 0;
7083 checkGLcall("Tear down FBOs\n");
7084 LEAVE_GL();
7086 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7087 This->fbo_color_attachments[i] = NULL;
7089 This->fbo_depth_attachment = NULL;
7092 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7093 UINT i, count;
7094 WINED3DDISPLAYMODE m;
7095 HRESULT hr;
7097 /* All Windowed modes are supported, as is leaving the current mode */
7098 if(pp->Windowed) return TRUE;
7099 if(!pp->BackBufferWidth) return TRUE;
7100 if(!pp->BackBufferHeight) return TRUE;
7102 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7103 for(i = 0; i < count; i++) {
7104 memset(&m, 0, sizeof(m));
7105 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7106 if(FAILED(hr)) {
7107 ERR("EnumAdapterModes failed\n");
7109 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7110 /* Mode found, it is supported */
7111 return TRUE;
7114 /* Mode not found -> not supported */
7115 return FALSE;
7118 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7120 IWineD3DSwapChainImpl *swapchain;
7121 HRESULT hr;
7122 BOOL DisplayModeChanged = FALSE;
7123 WINED3DDISPLAYMODE mode;
7124 IWineD3DBaseShaderImpl *shader;
7125 IWineD3DSurfaceImpl *target;
7126 UINT i;
7127 TRACE("(%p)\n", This);
7129 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7130 if(FAILED(hr)) {
7131 ERR("Failed to get the first implicit swapchain\n");
7132 return hr;
7135 if(!is_display_mode_supported(This, pPresentationParameters)) {
7136 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7137 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7138 pPresentationParameters->BackBufferHeight);
7139 return WINED3DERR_INVALIDCALL;
7142 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7143 * on an existing gl context, so there's no real need for recreation.
7145 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7147 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7149 TRACE("New params:\n");
7150 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7151 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7152 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7153 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7154 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7155 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7156 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7157 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7158 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7159 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7160 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7161 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7162 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7164 /* No special treatment of these parameters. Just store them */
7165 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7166 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7167 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7168 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7170 /* What to do about these? */
7171 if(pPresentationParameters->BackBufferCount != 0 &&
7172 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7173 ERR("Cannot change the back buffer count yet\n");
7175 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7176 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7177 ERR("Cannot change the back buffer format yet\n");
7179 if(pPresentationParameters->hDeviceWindow != NULL &&
7180 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7181 ERR("Cannot change the device window yet\n");
7183 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7184 ERR("What do do about a changed auto depth stencil parameter?\n");
7187 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7188 reset_fbo_state((IWineD3DDevice *) This);
7191 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7192 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7193 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7196 ENTER_GL();
7197 if(This->depth_blt_texture) {
7198 glDeleteTextures(1, &This->depth_blt_texture);
7199 This->depth_blt_texture = 0;
7201 This->shader_backend->shader_destroy_depth_blt(iface);
7202 This->shader_backend->shader_free_private(iface);
7204 for (i = 0; i < GL_LIMITS(textures); i++) {
7205 /* Textures are recreated below */
7206 glDeleteTextures(1, &This->dummyTextureName[i]);
7207 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7208 This->dummyTextureName[i] = 0;
7210 LEAVE_GL();
7212 while(This->numContexts) {
7213 DestroyContext(This, This->contexts[0]);
7215 This->activeContext = NULL;
7216 HeapFree(GetProcessHeap(), 0, swapchain->context);
7217 swapchain->context = NULL;
7218 swapchain->num_contexts = 0;
7220 if(pPresentationParameters->Windowed) {
7221 mode.Width = swapchain->orig_width;
7222 mode.Height = swapchain->orig_height;
7223 mode.RefreshRate = 0;
7224 mode.Format = swapchain->presentParms.BackBufferFormat;
7225 } else {
7226 mode.Width = pPresentationParameters->BackBufferWidth;
7227 mode.Height = pPresentationParameters->BackBufferHeight;
7228 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7229 mode.Format = swapchain->presentParms.BackBufferFormat;
7232 /* Should Width == 800 && Height == 0 set 800x600? */
7233 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7234 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7235 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7237 WINED3DVIEWPORT vp;
7238 int i;
7240 vp.X = 0;
7241 vp.Y = 0;
7242 vp.Width = pPresentationParameters->BackBufferWidth;
7243 vp.Height = pPresentationParameters->BackBufferHeight;
7244 vp.MinZ = 0;
7245 vp.MaxZ = 1;
7247 if(!pPresentationParameters->Windowed) {
7248 DisplayModeChanged = TRUE;
7250 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7251 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7253 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7254 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7255 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7257 if(This->auto_depth_stencil_buffer) {
7258 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7262 /* Now set the new viewport */
7263 IWineD3DDevice_SetViewport(iface, &vp);
7266 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7267 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7268 DisplayModeChanged) {
7270 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7271 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7272 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7273 } else if(!pPresentationParameters->Windowed) {
7274 DWORD style = This->style, exStyle = This->exStyle;
7275 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7276 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7277 * Reset to clear up their mess. Guild Wars also loses the device during that.
7279 This->style = 0;
7280 This->exStyle = 0;
7281 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7282 This->style = style;
7283 This->exStyle = exStyle;
7286 /* Recreate the primary swapchain's context */
7287 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7288 if(swapchain->backBuffer) {
7289 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7290 } else {
7291 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7293 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7294 &swapchain->presentParms);
7295 swapchain->num_contexts = 1;
7296 This->activeContext = swapchain->context[0];
7297 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7299 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7300 if(FAILED(hr)) {
7301 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7303 create_dummy_textures(This);
7306 hr = This->shader_backend->shader_alloc_private(iface);
7307 if(FAILED(hr)) {
7308 ERR("Failed to recreate shader private data\n");
7309 return hr;
7312 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7313 * first use
7315 return WINED3D_OK;
7318 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7320 /** FIXME: always true at the moment **/
7321 if(!bEnableDialogs) {
7322 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7324 return WINED3D_OK;
7328 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7330 TRACE("(%p) : pParameters %p\n", This, pParameters);
7332 *pParameters = This->createParms;
7333 return WINED3D_OK;
7336 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7337 IWineD3DSwapChain *swapchain;
7339 TRACE("Relaying to swapchain\n");
7341 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7342 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7343 IWineD3DSwapChain_Release(swapchain);
7345 return;
7348 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7349 IWineD3DSwapChain *swapchain;
7351 TRACE("Relaying to swapchain\n");
7353 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7354 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7355 IWineD3DSwapChain_Release(swapchain);
7357 return;
7361 /** ********************************************************
7362 * Notification functions
7363 ** ********************************************************/
7364 /** This function must be called in the release of a resource when ref == 0,
7365 * the contents of resource must still be correct,
7366 * any handles to other resource held by the caller must be closed
7367 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7368 *****************************************************/
7369 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7372 TRACE("(%p) : Adding Resource %p\n", This, resource);
7373 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7376 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7379 TRACE("(%p) : Removing resource %p\n", This, resource);
7381 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7385 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7387 int counter;
7389 TRACE("(%p) : resource %p\n", This, resource);
7390 switch(IWineD3DResource_GetType(resource)){
7391 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7392 case WINED3DRTYPE_SURFACE: {
7393 unsigned int i;
7395 /* Cleanup any FBO attachments if d3d is enabled */
7396 if(This->d3d_initialized) {
7397 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7398 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7400 TRACE("Last active render target destroyed\n");
7401 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7402 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7403 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7404 * and the lastActiveRenderTarget member shouldn't matter
7406 if(swapchain) {
7407 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7408 TRACE("Activating primary back buffer\n");
7409 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7410 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7411 /* Single buffering environment */
7412 TRACE("Activating primary front buffer\n");
7413 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7414 } else {
7415 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7416 /* Implicit render target destroyed, that means the device is being destroyed
7417 * whatever we set here, it shouldn't matter
7419 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7421 } else {
7422 /* May happen during ddraw uninitialization */
7423 TRACE("Render target set, but swapchain does not exist!\n");
7424 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7428 ENTER_GL();
7429 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7430 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7431 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7432 set_render_target_fbo(iface, i, NULL);
7433 This->fbo_color_attachments[i] = NULL;
7436 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7437 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7438 set_depth_stencil_fbo(iface, NULL);
7439 This->fbo_depth_attachment = NULL;
7441 LEAVE_GL();
7444 break;
7446 case WINED3DRTYPE_TEXTURE:
7447 case WINED3DRTYPE_CUBETEXTURE:
7448 case WINED3DRTYPE_VOLUMETEXTURE:
7449 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7450 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7451 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7452 This->stateBlock->textures[counter] = NULL;
7454 if (This->updateStateBlock != This->stateBlock ){
7455 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7456 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7457 This->updateStateBlock->textures[counter] = NULL;
7461 break;
7462 case WINED3DRTYPE_VOLUME:
7463 /* TODO: nothing really? */
7464 break;
7465 case WINED3DRTYPE_VERTEXBUFFER:
7466 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7468 int streamNumber;
7469 TRACE("Cleaning up stream pointers\n");
7471 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7472 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7473 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7475 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7476 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7477 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7478 This->updateStateBlock->streamSource[streamNumber] = 0;
7479 /* Set changed flag? */
7482 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) */
7483 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7484 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7485 This->stateBlock->streamSource[streamNumber] = 0;
7488 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7489 else { /* This shouldn't happen */
7490 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7492 #endif
7496 break;
7497 case WINED3DRTYPE_INDEXBUFFER:
7498 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7499 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7500 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7501 This->updateStateBlock->pIndexData = NULL;
7504 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7505 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7506 This->stateBlock->pIndexData = NULL;
7510 break;
7511 default:
7512 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7513 break;
7517 /* Remove the resource from the resourceStore */
7518 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7520 TRACE("Resource released\n");
7524 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7526 IWineD3DResourceImpl *resource, *cursor;
7527 HRESULT ret;
7528 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7530 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7531 TRACE("enumerating resource %p\n", resource);
7532 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7533 ret = pCallback((IWineD3DResource *) resource, pData);
7534 if(ret == S_FALSE) {
7535 TRACE("Canceling enumeration\n");
7536 break;
7539 return WINED3D_OK;
7542 /**********************************************************
7543 * IWineD3DDevice VTbl follows
7544 **********************************************************/
7546 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7548 /*** IUnknown methods ***/
7549 IWineD3DDeviceImpl_QueryInterface,
7550 IWineD3DDeviceImpl_AddRef,
7551 IWineD3DDeviceImpl_Release,
7552 /*** IWineD3DDevice methods ***/
7553 IWineD3DDeviceImpl_GetParent,
7554 /*** Creation methods**/
7555 IWineD3DDeviceImpl_CreateVertexBuffer,
7556 IWineD3DDeviceImpl_CreateIndexBuffer,
7557 IWineD3DDeviceImpl_CreateStateBlock,
7558 IWineD3DDeviceImpl_CreateSurface,
7559 IWineD3DDeviceImpl_CreateTexture,
7560 IWineD3DDeviceImpl_CreateVolumeTexture,
7561 IWineD3DDeviceImpl_CreateVolume,
7562 IWineD3DDeviceImpl_CreateCubeTexture,
7563 IWineD3DDeviceImpl_CreateQuery,
7564 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7565 IWineD3DDeviceImpl_CreateVertexDeclaration,
7566 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7567 IWineD3DDeviceImpl_CreateVertexShader,
7568 IWineD3DDeviceImpl_CreatePixelShader,
7569 IWineD3DDeviceImpl_CreatePalette,
7570 /*** Odd functions **/
7571 IWineD3DDeviceImpl_Init3D,
7572 IWineD3DDeviceImpl_Uninit3D,
7573 IWineD3DDeviceImpl_SetFullscreen,
7574 IWineD3DDeviceImpl_SetMultithreaded,
7575 IWineD3DDeviceImpl_EvictManagedResources,
7576 IWineD3DDeviceImpl_GetAvailableTextureMem,
7577 IWineD3DDeviceImpl_GetBackBuffer,
7578 IWineD3DDeviceImpl_GetCreationParameters,
7579 IWineD3DDeviceImpl_GetDeviceCaps,
7580 IWineD3DDeviceImpl_GetDirect3D,
7581 IWineD3DDeviceImpl_GetDisplayMode,
7582 IWineD3DDeviceImpl_SetDisplayMode,
7583 IWineD3DDeviceImpl_GetHWND,
7584 IWineD3DDeviceImpl_SetHWND,
7585 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7586 IWineD3DDeviceImpl_GetRasterStatus,
7587 IWineD3DDeviceImpl_GetSwapChain,
7588 IWineD3DDeviceImpl_Reset,
7589 IWineD3DDeviceImpl_SetDialogBoxMode,
7590 IWineD3DDeviceImpl_SetCursorProperties,
7591 IWineD3DDeviceImpl_SetCursorPosition,
7592 IWineD3DDeviceImpl_ShowCursor,
7593 IWineD3DDeviceImpl_TestCooperativeLevel,
7594 /*** Getters and setters **/
7595 IWineD3DDeviceImpl_SetClipPlane,
7596 IWineD3DDeviceImpl_GetClipPlane,
7597 IWineD3DDeviceImpl_SetClipStatus,
7598 IWineD3DDeviceImpl_GetClipStatus,
7599 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7600 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7601 IWineD3DDeviceImpl_SetDepthStencilSurface,
7602 IWineD3DDeviceImpl_GetDepthStencilSurface,
7603 IWineD3DDeviceImpl_SetFVF,
7604 IWineD3DDeviceImpl_GetFVF,
7605 IWineD3DDeviceImpl_SetGammaRamp,
7606 IWineD3DDeviceImpl_GetGammaRamp,
7607 IWineD3DDeviceImpl_SetIndices,
7608 IWineD3DDeviceImpl_GetIndices,
7609 IWineD3DDeviceImpl_SetBaseVertexIndex,
7610 IWineD3DDeviceImpl_GetBaseVertexIndex,
7611 IWineD3DDeviceImpl_SetLight,
7612 IWineD3DDeviceImpl_GetLight,
7613 IWineD3DDeviceImpl_SetLightEnable,
7614 IWineD3DDeviceImpl_GetLightEnable,
7615 IWineD3DDeviceImpl_SetMaterial,
7616 IWineD3DDeviceImpl_GetMaterial,
7617 IWineD3DDeviceImpl_SetNPatchMode,
7618 IWineD3DDeviceImpl_GetNPatchMode,
7619 IWineD3DDeviceImpl_SetPaletteEntries,
7620 IWineD3DDeviceImpl_GetPaletteEntries,
7621 IWineD3DDeviceImpl_SetPixelShader,
7622 IWineD3DDeviceImpl_GetPixelShader,
7623 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7624 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7625 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7626 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7627 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7628 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7629 IWineD3DDeviceImpl_SetRenderState,
7630 IWineD3DDeviceImpl_GetRenderState,
7631 IWineD3DDeviceImpl_SetRenderTarget,
7632 IWineD3DDeviceImpl_GetRenderTarget,
7633 IWineD3DDeviceImpl_SetFrontBackBuffers,
7634 IWineD3DDeviceImpl_SetSamplerState,
7635 IWineD3DDeviceImpl_GetSamplerState,
7636 IWineD3DDeviceImpl_SetScissorRect,
7637 IWineD3DDeviceImpl_GetScissorRect,
7638 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7639 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7640 IWineD3DDeviceImpl_SetStreamSource,
7641 IWineD3DDeviceImpl_GetStreamSource,
7642 IWineD3DDeviceImpl_SetStreamSourceFreq,
7643 IWineD3DDeviceImpl_GetStreamSourceFreq,
7644 IWineD3DDeviceImpl_SetTexture,
7645 IWineD3DDeviceImpl_GetTexture,
7646 IWineD3DDeviceImpl_SetTextureStageState,
7647 IWineD3DDeviceImpl_GetTextureStageState,
7648 IWineD3DDeviceImpl_SetTransform,
7649 IWineD3DDeviceImpl_GetTransform,
7650 IWineD3DDeviceImpl_SetVertexDeclaration,
7651 IWineD3DDeviceImpl_GetVertexDeclaration,
7652 IWineD3DDeviceImpl_SetVertexShader,
7653 IWineD3DDeviceImpl_GetVertexShader,
7654 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7655 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7656 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7657 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7658 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7659 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7660 IWineD3DDeviceImpl_SetViewport,
7661 IWineD3DDeviceImpl_GetViewport,
7662 IWineD3DDeviceImpl_MultiplyTransform,
7663 IWineD3DDeviceImpl_ValidateDevice,
7664 IWineD3DDeviceImpl_ProcessVertices,
7665 /*** State block ***/
7666 IWineD3DDeviceImpl_BeginStateBlock,
7667 IWineD3DDeviceImpl_EndStateBlock,
7668 /*** Scene management ***/
7669 IWineD3DDeviceImpl_BeginScene,
7670 IWineD3DDeviceImpl_EndScene,
7671 IWineD3DDeviceImpl_Present,
7672 IWineD3DDeviceImpl_Clear,
7673 /*** Drawing ***/
7674 IWineD3DDeviceImpl_DrawPrimitive,
7675 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7676 IWineD3DDeviceImpl_DrawPrimitiveUP,
7677 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7678 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7679 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7680 IWineD3DDeviceImpl_DrawRectPatch,
7681 IWineD3DDeviceImpl_DrawTriPatch,
7682 IWineD3DDeviceImpl_DeletePatch,
7683 IWineD3DDeviceImpl_ColorFill,
7684 IWineD3DDeviceImpl_UpdateTexture,
7685 IWineD3DDeviceImpl_UpdateSurface,
7686 IWineD3DDeviceImpl_GetFrontBufferData,
7687 /*** object tracking ***/
7688 IWineD3DDeviceImpl_ResourceReleased,
7689 IWineD3DDeviceImpl_EnumResources
7692 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7694 /*** IUnknown methods ***/
7695 IWineD3DDeviceImpl_QueryInterface,
7696 IWineD3DDeviceImpl_AddRef,
7697 IWineD3DDeviceImpl_Release,
7698 /*** IWineD3DDevice methods ***/
7699 IWineD3DDeviceImpl_GetParent,
7700 /*** Creation methods**/
7701 IWineD3DDeviceImpl_CreateVertexBuffer,
7702 IWineD3DDeviceImpl_CreateIndexBuffer,
7703 IWineD3DDeviceImpl_CreateStateBlock,
7704 IWineD3DDeviceImpl_CreateSurface,
7705 IWineD3DDeviceImpl_CreateTexture,
7706 IWineD3DDeviceImpl_CreateVolumeTexture,
7707 IWineD3DDeviceImpl_CreateVolume,
7708 IWineD3DDeviceImpl_CreateCubeTexture,
7709 IWineD3DDeviceImpl_CreateQuery,
7710 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7711 IWineD3DDeviceImpl_CreateVertexDeclaration,
7712 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7713 IWineD3DDeviceImpl_CreateVertexShader,
7714 IWineD3DDeviceImpl_CreatePixelShader,
7715 IWineD3DDeviceImpl_CreatePalette,
7716 /*** Odd functions **/
7717 IWineD3DDeviceImpl_Init3D,
7718 IWineD3DDeviceImpl_Uninit3D,
7719 IWineD3DDeviceImpl_SetFullscreen,
7720 IWineD3DDeviceImpl_SetMultithreaded,
7721 IWineD3DDeviceImpl_EvictManagedResources,
7722 IWineD3DDeviceImpl_GetAvailableTextureMem,
7723 IWineD3DDeviceImpl_GetBackBuffer,
7724 IWineD3DDeviceImpl_GetCreationParameters,
7725 IWineD3DDeviceImpl_GetDeviceCaps,
7726 IWineD3DDeviceImpl_GetDirect3D,
7727 IWineD3DDeviceImpl_GetDisplayMode,
7728 IWineD3DDeviceImpl_SetDisplayMode,
7729 IWineD3DDeviceImpl_GetHWND,
7730 IWineD3DDeviceImpl_SetHWND,
7731 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7732 IWineD3DDeviceImpl_GetRasterStatus,
7733 IWineD3DDeviceImpl_GetSwapChain,
7734 IWineD3DDeviceImpl_Reset,
7735 IWineD3DDeviceImpl_SetDialogBoxMode,
7736 IWineD3DDeviceImpl_SetCursorProperties,
7737 IWineD3DDeviceImpl_SetCursorPosition,
7738 IWineD3DDeviceImpl_ShowCursor,
7739 IWineD3DDeviceImpl_TestCooperativeLevel,
7740 /*** Getters and setters **/
7741 IWineD3DDeviceImpl_SetClipPlane,
7742 IWineD3DDeviceImpl_GetClipPlane,
7743 IWineD3DDeviceImpl_SetClipStatus,
7744 IWineD3DDeviceImpl_GetClipStatus,
7745 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7746 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7747 IWineD3DDeviceImpl_SetDepthStencilSurface,
7748 IWineD3DDeviceImpl_GetDepthStencilSurface,
7749 IWineD3DDeviceImpl_SetFVF,
7750 IWineD3DDeviceImpl_GetFVF,
7751 IWineD3DDeviceImpl_SetGammaRamp,
7752 IWineD3DDeviceImpl_GetGammaRamp,
7753 IWineD3DDeviceImpl_SetIndices,
7754 IWineD3DDeviceImpl_GetIndices,
7755 IWineD3DDeviceImpl_SetBaseVertexIndex,
7756 IWineD3DDeviceImpl_GetBaseVertexIndex,
7757 IWineD3DDeviceImpl_SetLight,
7758 IWineD3DDeviceImpl_GetLight,
7759 IWineD3DDeviceImpl_SetLightEnable,
7760 IWineD3DDeviceImpl_GetLightEnable,
7761 IWineD3DDeviceImpl_SetMaterial,
7762 IWineD3DDeviceImpl_GetMaterial,
7763 IWineD3DDeviceImpl_SetNPatchMode,
7764 IWineD3DDeviceImpl_GetNPatchMode,
7765 IWineD3DDeviceImpl_SetPaletteEntries,
7766 IWineD3DDeviceImpl_GetPaletteEntries,
7767 IWineD3DDeviceImpl_SetPixelShader,
7768 IWineD3DDeviceImpl_GetPixelShader,
7769 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7770 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7771 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7772 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7773 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7774 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7775 IWineD3DDeviceImpl_SetRenderState,
7776 IWineD3DDeviceImpl_GetRenderState,
7777 IWineD3DDeviceImpl_SetRenderTarget,
7778 IWineD3DDeviceImpl_GetRenderTarget,
7779 IWineD3DDeviceImpl_SetFrontBackBuffers,
7780 IWineD3DDeviceImpl_SetSamplerState,
7781 IWineD3DDeviceImpl_GetSamplerState,
7782 IWineD3DDeviceImpl_SetScissorRect,
7783 IWineD3DDeviceImpl_GetScissorRect,
7784 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7785 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7786 IWineD3DDeviceImpl_SetStreamSource,
7787 IWineD3DDeviceImpl_GetStreamSource,
7788 IWineD3DDeviceImpl_SetStreamSourceFreq,
7789 IWineD3DDeviceImpl_GetStreamSourceFreq,
7790 IWineD3DDeviceImpl_SetTexture,
7791 IWineD3DDeviceImpl_GetTexture,
7792 IWineD3DDeviceImpl_SetTextureStageState,
7793 IWineD3DDeviceImpl_GetTextureStageState,
7794 IWineD3DDeviceImpl_SetTransform,
7795 IWineD3DDeviceImpl_GetTransform,
7796 IWineD3DDeviceImpl_SetVertexDeclaration,
7797 IWineD3DDeviceImpl_GetVertexDeclaration,
7798 IWineD3DDeviceImpl_SetVertexShader,
7799 IWineD3DDeviceImpl_GetVertexShader,
7800 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7801 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7802 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7803 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7804 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7805 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7806 IWineD3DDeviceImpl_SetViewport,
7807 IWineD3DDeviceImpl_GetViewport,
7808 IWineD3DDeviceImpl_MultiplyTransform,
7809 IWineD3DDeviceImpl_ValidateDevice,
7810 IWineD3DDeviceImpl_ProcessVertices,
7811 /*** State block ***/
7812 IWineD3DDeviceImpl_BeginStateBlock,
7813 IWineD3DDeviceImpl_EndStateBlock,
7814 /*** Scene management ***/
7815 IWineD3DDeviceImpl_BeginScene,
7816 IWineD3DDeviceImpl_EndScene,
7817 IWineD3DDeviceImpl_Present,
7818 IWineD3DDeviceImpl_Clear,
7819 /*** Drawing ***/
7820 IWineD3DDeviceImpl_DrawPrimitive,
7821 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7822 IWineD3DDeviceImpl_DrawPrimitiveUP,
7823 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7824 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7825 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7826 IWineD3DDeviceImpl_DrawRectPatch,
7827 IWineD3DDeviceImpl_DrawTriPatch,
7828 IWineD3DDeviceImpl_DeletePatch,
7829 IWineD3DDeviceImpl_ColorFill,
7830 IWineD3DDeviceImpl_UpdateTexture,
7831 IWineD3DDeviceImpl_UpdateSurface,
7832 IWineD3DDeviceImpl_GetFrontBufferData,
7833 /*** object tracking ***/
7834 IWineD3DDeviceImpl_ResourceReleased,
7835 IWineD3DDeviceImpl_EnumResources
7838 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7839 WINED3DRS_ALPHABLENDENABLE ,
7840 WINED3DRS_ALPHAFUNC ,
7841 WINED3DRS_ALPHAREF ,
7842 WINED3DRS_ALPHATESTENABLE ,
7843 WINED3DRS_BLENDOP ,
7844 WINED3DRS_COLORWRITEENABLE ,
7845 WINED3DRS_DESTBLEND ,
7846 WINED3DRS_DITHERENABLE ,
7847 WINED3DRS_FILLMODE ,
7848 WINED3DRS_FOGDENSITY ,
7849 WINED3DRS_FOGEND ,
7850 WINED3DRS_FOGSTART ,
7851 WINED3DRS_LASTPIXEL ,
7852 WINED3DRS_SHADEMODE ,
7853 WINED3DRS_SRCBLEND ,
7854 WINED3DRS_STENCILENABLE ,
7855 WINED3DRS_STENCILFAIL ,
7856 WINED3DRS_STENCILFUNC ,
7857 WINED3DRS_STENCILMASK ,
7858 WINED3DRS_STENCILPASS ,
7859 WINED3DRS_STENCILREF ,
7860 WINED3DRS_STENCILWRITEMASK ,
7861 WINED3DRS_STENCILZFAIL ,
7862 WINED3DRS_TEXTUREFACTOR ,
7863 WINED3DRS_WRAP0 ,
7864 WINED3DRS_WRAP1 ,
7865 WINED3DRS_WRAP2 ,
7866 WINED3DRS_WRAP3 ,
7867 WINED3DRS_WRAP4 ,
7868 WINED3DRS_WRAP5 ,
7869 WINED3DRS_WRAP6 ,
7870 WINED3DRS_WRAP7 ,
7871 WINED3DRS_ZENABLE ,
7872 WINED3DRS_ZFUNC ,
7873 WINED3DRS_ZWRITEENABLE
7876 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7877 WINED3DTSS_ADDRESSW ,
7878 WINED3DTSS_ALPHAARG0 ,
7879 WINED3DTSS_ALPHAARG1 ,
7880 WINED3DTSS_ALPHAARG2 ,
7881 WINED3DTSS_ALPHAOP ,
7882 WINED3DTSS_BUMPENVLOFFSET ,
7883 WINED3DTSS_BUMPENVLSCALE ,
7884 WINED3DTSS_BUMPENVMAT00 ,
7885 WINED3DTSS_BUMPENVMAT01 ,
7886 WINED3DTSS_BUMPENVMAT10 ,
7887 WINED3DTSS_BUMPENVMAT11 ,
7888 WINED3DTSS_COLORARG0 ,
7889 WINED3DTSS_COLORARG1 ,
7890 WINED3DTSS_COLORARG2 ,
7891 WINED3DTSS_COLOROP ,
7892 WINED3DTSS_RESULTARG ,
7893 WINED3DTSS_TEXCOORDINDEX ,
7894 WINED3DTSS_TEXTURETRANSFORMFLAGS
7897 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7898 WINED3DSAMP_ADDRESSU ,
7899 WINED3DSAMP_ADDRESSV ,
7900 WINED3DSAMP_ADDRESSW ,
7901 WINED3DSAMP_BORDERCOLOR ,
7902 WINED3DSAMP_MAGFILTER ,
7903 WINED3DSAMP_MINFILTER ,
7904 WINED3DSAMP_MIPFILTER ,
7905 WINED3DSAMP_MIPMAPLODBIAS ,
7906 WINED3DSAMP_MAXMIPLEVEL ,
7907 WINED3DSAMP_MAXANISOTROPY ,
7908 WINED3DSAMP_SRGBTEXTURE ,
7909 WINED3DSAMP_ELEMENTINDEX
7912 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7913 WINED3DRS_AMBIENT ,
7914 WINED3DRS_AMBIENTMATERIALSOURCE ,
7915 WINED3DRS_CLIPPING ,
7916 WINED3DRS_CLIPPLANEENABLE ,
7917 WINED3DRS_COLORVERTEX ,
7918 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7919 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7920 WINED3DRS_FOGDENSITY ,
7921 WINED3DRS_FOGEND ,
7922 WINED3DRS_FOGSTART ,
7923 WINED3DRS_FOGTABLEMODE ,
7924 WINED3DRS_FOGVERTEXMODE ,
7925 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7926 WINED3DRS_LIGHTING ,
7927 WINED3DRS_LOCALVIEWER ,
7928 WINED3DRS_MULTISAMPLEANTIALIAS ,
7929 WINED3DRS_MULTISAMPLEMASK ,
7930 WINED3DRS_NORMALIZENORMALS ,
7931 WINED3DRS_PATCHEDGESTYLE ,
7932 WINED3DRS_POINTSCALE_A ,
7933 WINED3DRS_POINTSCALE_B ,
7934 WINED3DRS_POINTSCALE_C ,
7935 WINED3DRS_POINTSCALEENABLE ,
7936 WINED3DRS_POINTSIZE ,
7937 WINED3DRS_POINTSIZE_MAX ,
7938 WINED3DRS_POINTSIZE_MIN ,
7939 WINED3DRS_POINTSPRITEENABLE ,
7940 WINED3DRS_RANGEFOGENABLE ,
7941 WINED3DRS_SPECULARMATERIALSOURCE ,
7942 WINED3DRS_TWEENFACTOR ,
7943 WINED3DRS_VERTEXBLEND ,
7944 WINED3DRS_CULLMODE ,
7945 WINED3DRS_FOGCOLOR
7948 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7949 WINED3DTSS_TEXCOORDINDEX ,
7950 WINED3DTSS_TEXTURETRANSFORMFLAGS
7953 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7954 WINED3DSAMP_DMAPOFFSET
7957 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7958 DWORD rep = This->shader_backend->StateTable[state].representative;
7959 DWORD idx;
7960 BYTE shift;
7961 UINT i;
7962 WineD3DContext *context;
7964 if(!rep) return;
7965 for(i = 0; i < This->numContexts; i++) {
7966 context = This->contexts[i];
7967 if(isStateDirty(context, rep)) continue;
7969 context->dirtyArray[context->numDirtyEntries++] = rep;
7970 idx = rep >> 5;
7971 shift = rep & 0x1f;
7972 context->isStateDirty[idx] |= (1 << shift);
7976 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7977 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7978 /* The drawable size of a pbuffer render target is the current pbuffer size
7980 *width = dev->pbufferWidth;
7981 *height = dev->pbufferHeight;
7984 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7985 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7987 *width = This->pow2Width;
7988 *height = This->pow2Height;
7991 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7992 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7993 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7994 * current context's drawable, which is the size of the back buffer of the swapchain
7995 * the active context belongs to. The back buffer of the swapchain is stored as the
7996 * surface the context belongs to.
7998 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7999 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;