wined3d: Make the state table a property of the shader backend.
[wine/multimedia.git] / dlls / wined3d / device.c
blobdea417c6f74351f972006e921dd46422199cff10
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-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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 This->shader_backend->shader_free_private(iface);
178 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
180 /* TODO: Clean up all the surfaces and textures! */
181 /* NOTE: You must release the parent if the object was created via a callback
182 ** ***************************/
184 if (!list_empty(&This->resources)) {
185 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
186 dumpResources(&This->resources);
189 if(This->contexts) ERR("Context array not freed!\n");
190 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
191 This->haveHardwareCursor = FALSE;
193 IWineD3D_Release(This->wineD3D);
194 This->wineD3D = NULL;
195 HeapFree(GetProcessHeap(), 0, This);
196 TRACE("Freed device %p\n", This);
197 This = NULL;
199 return refCount;
202 /**********************************************************
203 * IWineD3DDevice implementation follows
204 **********************************************************/
205 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
207 *pParent = This->parent;
208 IUnknown_AddRef(This->parent);
209 return WINED3D_OK;
212 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
213 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
214 IUnknown *parent) {
215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
216 IWineD3DVertexBufferImpl *object;
217 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
218 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
219 BOOL conv;
221 if(Size == 0) {
222 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
223 *ppVertexBuffer = NULL;
224 return WINED3DERR_INVALIDCALL;
225 } else if(Pool == WINED3DPOOL_SCRATCH) {
226 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
227 * anyway, SCRATCH vertex buffers aren't useable anywhere
229 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
230 *ppVertexBuffer = NULL;
231 return WINED3DERR_INVALIDCALL;
234 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
236 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);
237 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
239 object->fvf = FVF;
241 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
242 * drawStridedFast (half-life 2).
244 * Basically converting the vertices in the buffer is quite expensive, and observations
245 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
246 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
248 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
249 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
250 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
251 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
252 * dx7 apps.
253 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
254 * more. In this call we can convert dx7 buffers too.
256 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
257 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
258 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
259 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
260 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
261 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
262 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
263 } else if(dxVersion <= 7 && conv) {
264 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
265 } else {
266 object->Flags |= VBFLAG_CREATEVBO;
268 return WINED3D_OK;
271 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
272 GLenum error, glUsage;
273 TRACE("Creating VBO for Index Buffer %p\n", object);
275 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
276 * restored on the next draw
278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
280 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
281 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
282 ENTER_GL();
284 while(glGetError());
286 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
287 error = glGetError();
288 if(error != GL_NO_ERROR || object->vbo == 0) {
289 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
290 goto out;
293 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
294 error = glGetError();
295 if(error != GL_NO_ERROR) {
296 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
297 goto out;
300 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
301 * copy no readback will be needed
303 glUsage = GL_STATIC_DRAW_ARB;
304 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
305 error = glGetError();
306 if(error != GL_NO_ERROR) {
307 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
308 goto out;
310 LEAVE_GL();
311 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
312 return;
314 out:
315 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
316 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
317 LEAVE_GL();
318 object->vbo = 0;
321 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
322 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
323 HANDLE *sharedHandle, IUnknown *parent) {
324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
325 IWineD3DIndexBufferImpl *object;
326 TRACE("(%p) Creating index buffer\n", This);
328 /* Allocate the storage for the device */
329 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
331 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
332 CreateIndexBufferVBO(This, object);
335 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
336 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
337 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
339 return WINED3D_OK;
342 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
345 IWineD3DStateBlockImpl *object;
346 int i, j;
347 HRESULT temp_result;
349 D3DCREATEOBJECTINSTANCE(object, StateBlock)
350 object->blockType = Type;
352 for(i = 0; i < LIGHTMAP_SIZE; i++) {
353 list_init(&object->lightMap[i]);
356 /* Special case - Used during initialization to produce a placeholder stateblock
357 so other functions called can update a state block */
358 if (Type == WINED3DSBT_INIT) {
359 /* Don't bother increasing the reference count otherwise a device will never
360 be freed due to circular dependencies */
361 return WINED3D_OK;
364 temp_result = allocate_shader_constants(object);
365 if (WINED3D_OK != temp_result)
366 return temp_result;
368 /* Otherwise, might as well set the whole state block to the appropriate values */
369 if (This->stateBlock != NULL)
370 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
371 else
372 memset(object->streamFreq, 1, sizeof(object->streamFreq));
374 /* Reset the ref and type after kludging it */
375 object->wineD3DDevice = This;
376 object->ref = 1;
377 object->blockType = Type;
379 TRACE("Updating changed flags appropriate for type %d\n", Type);
381 if (Type == WINED3DSBT_ALL) {
383 TRACE("ALL => Pretend everything has changed\n");
384 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
386 /* Lights are not part of the changed / set structure */
387 for(j = 0; j < LIGHTMAP_SIZE; j++) {
388 struct list *e;
389 LIST_FOR_EACH(e, &object->lightMap[j]) {
390 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
391 light->changed = TRUE;
392 light->enabledChanged = TRUE;
395 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
396 object->contained_render_states[j - 1] = j;
398 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
399 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
400 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
401 object->contained_transform_states[j - 1] = j;
403 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
404 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
405 object->contained_vs_consts_f[j] = j;
407 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
408 for(j = 0; j < MAX_CONST_I; j++) {
409 object->contained_vs_consts_i[j] = j;
411 object->num_contained_vs_consts_i = MAX_CONST_I;
412 for(j = 0; j < MAX_CONST_B; j++) {
413 object->contained_vs_consts_b[j] = j;
415 object->num_contained_vs_consts_b = MAX_CONST_B;
416 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
417 object->contained_ps_consts_f[j] = j;
419 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
420 for(j = 0; j < MAX_CONST_I; j++) {
421 object->contained_ps_consts_i[j] = j;
423 object->num_contained_ps_consts_i = MAX_CONST_I;
424 for(j = 0; j < MAX_CONST_B; j++) {
425 object->contained_ps_consts_b[j] = j;
427 object->num_contained_ps_consts_b = MAX_CONST_B;
428 for(i = 0; i < MAX_TEXTURES; i++) {
429 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
430 object->contained_tss_states[object->num_contained_tss_states].stage = i;
431 object->contained_tss_states[object->num_contained_tss_states].state = j;
432 object->num_contained_tss_states++;
435 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
436 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
437 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
438 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
439 object->num_contained_sampler_states++;
443 for(i = 0; i < MAX_STREAMS; i++) {
444 if(object->streamSource[i]) {
445 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
448 if(object->pIndexData) {
449 IWineD3DIndexBuffer_AddRef(object->pIndexData);
451 if(object->vertexShader) {
452 IWineD3DVertexShader_AddRef(object->vertexShader);
454 if(object->pixelShader) {
455 IWineD3DPixelShader_AddRef(object->pixelShader);
458 } else if (Type == WINED3DSBT_PIXELSTATE) {
460 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
461 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
463 object->changed.pixelShader = TRUE;
465 /* Pixel Shader Constants */
466 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
467 object->contained_ps_consts_f[i] = i;
468 object->changed.pixelShaderConstantsF[i] = TRUE;
470 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
471 for (i = 0; i < MAX_CONST_B; ++i) {
472 object->contained_ps_consts_b[i] = i;
473 object->changed.pixelShaderConstantsB[i] = TRUE;
475 object->num_contained_ps_consts_b = MAX_CONST_B;
476 for (i = 0; i < MAX_CONST_I; ++i) {
477 object->contained_ps_consts_i[i] = i;
478 object->changed.pixelShaderConstantsI[i] = TRUE;
480 object->num_contained_ps_consts_i = MAX_CONST_I;
482 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
483 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
484 object->contained_render_states[i] = SavedPixelStates_R[i];
486 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
487 for (j = 0; j < MAX_TEXTURES; j++) {
488 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
489 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
490 object->contained_tss_states[object->num_contained_tss_states].stage = j;
491 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
492 object->num_contained_tss_states++;
495 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
496 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
497 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
498 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
499 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
500 object->num_contained_sampler_states++;
503 if(object->pixelShader) {
504 IWineD3DPixelShader_AddRef(object->pixelShader);
507 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
508 * on them. This makes releasing the buffer easier
510 for(i = 0; i < MAX_STREAMS; i++) {
511 object->streamSource[i] = NULL;
513 object->pIndexData = NULL;
514 object->vertexShader = NULL;
516 } else if (Type == WINED3DSBT_VERTEXSTATE) {
518 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
519 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
521 object->changed.vertexShader = TRUE;
523 /* Vertex Shader Constants */
524 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
525 object->changed.vertexShaderConstantsF[i] = TRUE;
526 object->contained_vs_consts_f[i] = i;
528 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
529 for (i = 0; i < MAX_CONST_B; ++i) {
530 object->changed.vertexShaderConstantsB[i] = TRUE;
531 object->contained_vs_consts_b[i] = i;
533 object->num_contained_vs_consts_b = MAX_CONST_B;
534 for (i = 0; i < MAX_CONST_I; ++i) {
535 object->changed.vertexShaderConstantsI[i] = TRUE;
536 object->contained_vs_consts_i[i] = i;
538 object->num_contained_vs_consts_i = MAX_CONST_I;
539 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
540 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
541 object->contained_render_states[i] = SavedVertexStates_R[i];
543 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
544 for (j = 0; j < MAX_TEXTURES; j++) {
545 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
546 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
547 object->contained_tss_states[object->num_contained_tss_states].stage = j;
548 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
549 object->num_contained_tss_states++;
552 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
553 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
554 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
555 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
556 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
557 object->num_contained_sampler_states++;
561 for(j = 0; j < LIGHTMAP_SIZE; j++) {
562 struct list *e;
563 LIST_FOR_EACH(e, &object->lightMap[j]) {
564 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
565 light->changed = TRUE;
566 light->enabledChanged = TRUE;
570 for(i = 0; i < MAX_STREAMS; i++) {
571 if(object->streamSource[i]) {
572 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
575 if(object->vertexShader) {
576 IWineD3DVertexShader_AddRef(object->vertexShader);
578 object->pIndexData = NULL;
579 object->pixelShader = NULL;
580 } else {
581 FIXME("Unrecognized state block type %d\n", Type);
584 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
585 return WINED3D_OK;
588 /* ************************************
589 MSDN:
590 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
592 Discard
593 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
595 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.
597 ******************************** */
599 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) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
602 unsigned int Size = 1;
603 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
604 TRACE("(%p) Create surface\n",This);
606 /** FIXME: Check ranges on the inputs are valid
607 * MSDN
608 * MultisampleQuality
609 * [in] Quality level. The valid range is between zero and one less than the level
610 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
611 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
612 * values of paired render targets, depth stencil surfaces, and the MultiSample type
613 * must all match.
614 *******************************/
618 * TODO: Discard MSDN
619 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
621 * If this flag is set, the contents of the depth stencil buffer will be
622 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
623 * with a different depth surface.
625 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
626 ***************************/
628 if(MultisampleQuality > 0) {
629 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
630 MultisampleQuality=0;
633 /** FIXME: Check that the format is supported
634 * by the device.
635 *******************************/
637 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
638 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
639 * space!
640 *********************************/
641 if (WINED3DFMT_UNKNOWN == Format) {
642 Size = 0;
643 } else if (Format == WINED3DFMT_DXT1) {
644 /* DXT1 is half byte per pixel */
645 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
647 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
648 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
649 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
650 } else {
651 /* The pitch is a multiple of 4 bytes */
652 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
653 Size *= Height;
656 /** Create and initialise the surface resource **/
657 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
658 /* "Standalone" surface */
659 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
661 object->currentDesc.Width = Width;
662 object->currentDesc.Height = Height;
663 object->currentDesc.MultiSampleType = MultiSample;
664 object->currentDesc.MultiSampleQuality = MultisampleQuality;
665 object->glDescription.level = Level;
667 /* Flags */
668 object->Flags = 0;
669 object->Flags |= Discard ? SFLAG_DISCARD : 0;
670 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
671 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
674 if (WINED3DFMT_UNKNOWN != Format) {
675 object->bytesPerPixel = tableEntry->bpp;
676 } else {
677 object->bytesPerPixel = 0;
680 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
682 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
684 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
685 * this function is too deep to need to care about things like this.
686 * Levels need to be checked too, and possibly Type since they all affect what can be done.
687 * ****************************************/
688 switch(Pool) {
689 case WINED3DPOOL_SCRATCH:
690 if(!Lockable)
691 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
692 "which are mutually exclusive, setting lockable to TRUE\n");
693 Lockable = TRUE;
694 break;
695 case WINED3DPOOL_SYSTEMMEM:
696 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
697 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
698 case WINED3DPOOL_MANAGED:
699 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
700 "Usage of DYNAMIC which are mutually exclusive, not doing "
701 "anything just telling you.\n");
702 break;
703 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
704 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
705 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
706 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
707 break;
708 default:
709 FIXME("(%p) Unknown pool %d\n", This, Pool);
710 break;
713 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
714 FIXME("Trying to create a render target that isn't in the default pool\n");
717 /* mark the texture as dirty so that it gets loaded first time around*/
718 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
719 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
720 This, Width, Height, Format, debug_d3dformat(Format),
721 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
723 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
724 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
725 This->ddraw_primary = (IWineD3DSurface *) object;
727 /* Look at the implementation and set the correct Vtable */
728 switch(Impl) {
729 case SURFACE_OPENGL:
730 /* Check if a 3D adapter is available when creating gl surfaces */
731 if(!This->adapter) {
732 ERR("OpenGL surfaces are not available without opengl\n");
733 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
734 HeapFree(GetProcessHeap(), 0, object);
735 return WINED3DERR_NOTAVAILABLE;
737 break;
739 case SURFACE_GDI:
740 object->lpVtbl = &IWineGDISurface_Vtbl;
741 break;
743 default:
744 /* To be sure to catch this */
745 ERR("Unknown requested surface implementation %d!\n", Impl);
746 IWineD3DSurface_Release((IWineD3DSurface *) object);
747 return WINED3DERR_INVALIDCALL;
750 list_init(&object->renderbuffers);
752 /* Call the private setup routine */
753 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
758 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
759 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
760 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
763 IWineD3DTextureImpl *object;
764 unsigned int i;
765 UINT tmpW;
766 UINT tmpH;
767 HRESULT hr;
768 unsigned int pow2Width;
769 unsigned int pow2Height;
770 const GlPixelFormatDesc *glDesc;
771 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
774 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
775 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
776 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
778 /* TODO: It should only be possible to create textures for formats
779 that are reported as supported */
780 if (WINED3DFMT_UNKNOWN >= Format) {
781 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
782 return WINED3DERR_INVALIDCALL;
785 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
786 D3DINITIALIZEBASETEXTURE(object->baseTexture);
787 object->width = Width;
788 object->height = Height;
790 /** Non-power2 support **/
791 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
792 pow2Width = Width;
793 pow2Height = Height;
794 } else {
795 /* Find the nearest pow2 match */
796 pow2Width = pow2Height = 1;
797 while (pow2Width < Width) pow2Width <<= 1;
798 while (pow2Height < Height) pow2Height <<= 1;
800 if(pow2Width != Width || pow2Height != Height) {
801 if(Levels > 1) {
802 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
803 HeapFree(GetProcessHeap(), 0, object);
804 *ppTexture = NULL;
805 return WINED3DERR_INVALIDCALL;
806 } else {
807 Levels = 1;
812 /** FIXME: add support for real non-power-two if it's provided by the video card **/
813 /* Precalculated scaling for 'faked' non power of two texture coords.
814 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
815 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
816 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
818 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
819 (Width != pow2Width || Height != pow2Height) &&
820 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
822 object->baseTexture.pow2Matrix[0] = (float)Width;
823 object->baseTexture.pow2Matrix[5] = (float)Height;
824 object->baseTexture.pow2Matrix[10] = 1.0;
825 object->baseTexture.pow2Matrix[15] = 1.0;
826 object->target = GL_TEXTURE_RECTANGLE_ARB;
827 } else {
828 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
829 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
830 object->baseTexture.pow2Matrix[10] = 1.0;
831 object->baseTexture.pow2Matrix[15] = 1.0;
832 object->target = GL_TEXTURE_2D;
834 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
836 /* Calculate levels for mip mapping */
837 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
838 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
839 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
840 return WINED3DERR_INVALIDCALL;
842 if(Levels > 1) {
843 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
844 return WINED3DERR_INVALIDCALL;
846 object->baseTexture.levels = 1;
847 } else if (Levels == 0) {
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
850 tmpW = Width;
851 tmpH = Height;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
861 tmpW = Width;
862 tmpH = Height;
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
869 /* clean up */
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
873 *ppTexture = NULL;
874 return hr;
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
883 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
885 TRACE("(%p) : Created texture %p\n", This, object);
886 return WINED3D_OK;
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
890 UINT Width, UINT Height, UINT Depth,
891 UINT Levels, DWORD Usage,
892 WINED3DFORMAT Format, WINED3DPOOL Pool,
893 IWineD3DVolumeTexture **ppVolumeTexture,
894 HANDLE *pSharedHandle, IUnknown *parent,
895 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DVolumeTextureImpl *object;
899 unsigned int i;
900 UINT tmpW;
901 UINT tmpH;
902 UINT tmpD;
903 const GlPixelFormatDesc *glDesc;
905 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
907 /* TODO: It should only be possible to create textures for formats
908 that are reported as supported */
909 if (WINED3DFMT_UNKNOWN >= Format) {
910 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
911 return WINED3DERR_INVALIDCALL;
913 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
914 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
915 return WINED3DERR_INVALIDCALL;
918 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
919 D3DINITIALIZEBASETEXTURE(object->baseTexture);
921 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object->width = Width;
925 object->height = Height;
926 object->depth = Depth;
928 /* Is NP2 support for volumes needed? */
929 object->baseTexture.pow2Matrix[ 0] = 1.0;
930 object->baseTexture.pow2Matrix[ 5] = 1.0;
931 object->baseTexture.pow2Matrix[10] = 1.0;
932 object->baseTexture.pow2Matrix[15] = 1.0;
934 /* Calculate levels for mip mapping */
935 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
936 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
937 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
938 return WINED3DERR_INVALIDCALL;
940 if(Levels > 1) {
941 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
942 return WINED3DERR_INVALIDCALL;
944 Levels = 1;
945 } else if (Levels == 0) {
946 object->baseTexture.levels++;
947 tmpW = Width;
948 tmpH = Height;
949 tmpD = Depth;
950 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
951 tmpW = max(1, tmpW >> 1);
952 tmpH = max(1, tmpH >> 1);
953 tmpD = max(1, tmpD >> 1);
954 object->baseTexture.levels++;
956 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
959 /* Generate all the surfaces */
960 tmpW = Width;
961 tmpH = Height;
962 tmpD = Depth;
964 for (i = 0; i < object->baseTexture.levels; i++)
966 HRESULT hr;
967 /* Create the volume */
968 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
969 &object->volumes[i], pSharedHandle);
971 if(FAILED(hr)) {
972 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
973 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
974 *ppVolumeTexture = NULL;
975 return hr;
978 /* Set its container to this object */
979 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
981 /* calculate the next mipmap level */
982 tmpW = max(1, tmpW >> 1);
983 tmpH = max(1, tmpH >> 1);
984 tmpD = max(1, tmpD >> 1);
986 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
988 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
989 TRACE("(%p) : Created volume texture %p\n", This, object);
990 return WINED3D_OK;
993 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
994 UINT Width, UINT Height, UINT Depth,
995 DWORD Usage,
996 WINED3DFORMAT Format, WINED3DPOOL Pool,
997 IWineD3DVolume** ppVolume,
998 HANDLE* pSharedHandle, IUnknown *parent) {
1000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1001 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1002 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1004 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1005 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1006 return WINED3DERR_INVALIDCALL;
1009 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1011 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1012 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1014 object->currentDesc.Width = Width;
1015 object->currentDesc.Height = Height;
1016 object->currentDesc.Depth = Depth;
1017 object->bytesPerPixel = formatDesc->bpp;
1019 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1020 object->lockable = TRUE;
1021 object->locked = FALSE;
1022 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1023 object->dirty = TRUE;
1025 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1028 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1029 UINT Levels, DWORD Usage,
1030 WINED3DFORMAT Format, WINED3DPOOL Pool,
1031 IWineD3DCubeTexture **ppCubeTexture,
1032 HANDLE *pSharedHandle, IUnknown *parent,
1033 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1036 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1037 unsigned int i, j;
1038 UINT tmpW;
1039 HRESULT hr;
1040 unsigned int pow2EdgeLength = EdgeLength;
1041 const GlPixelFormatDesc *glDesc;
1042 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1044 /* TODO: It should only be possible to create textures for formats
1045 that are reported as supported */
1046 if (WINED3DFMT_UNKNOWN >= Format) {
1047 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1048 return WINED3DERR_INVALIDCALL;
1051 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1052 WARN("(%p) : Tried to create not supported cube texture\n", This);
1053 return WINED3DERR_INVALIDCALL;
1056 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1057 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1059 TRACE("(%p) Create Cube Texture\n", This);
1061 /** Non-power2 support **/
1063 /* Find the nearest pow2 match */
1064 pow2EdgeLength = 1;
1065 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1067 object->edgeLength = EdgeLength;
1068 /* TODO: support for native non-power 2 */
1069 /* Precalculated scaling for 'faked' non power of two texture coords */
1070 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1071 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1072 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1073 object->baseTexture.pow2Matrix[15] = 1.0;
1075 /* Calculate levels for mip mapping */
1076 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1077 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1078 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1079 HeapFree(GetProcessHeap(), 0, object);
1080 *ppCubeTexture = NULL;
1082 return WINED3DERR_INVALIDCALL;
1084 if(Levels > 1) {
1085 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1086 HeapFree(GetProcessHeap(), 0, object);
1087 *ppCubeTexture = NULL;
1089 return WINED3DERR_INVALIDCALL;
1091 Levels = 1;
1092 } else if (Levels == 0) {
1093 object->baseTexture.levels++;
1094 tmpW = EdgeLength;
1095 while (tmpW > 1) {
1096 tmpW = max(1, tmpW >> 1);
1097 object->baseTexture.levels++;
1099 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1102 /* Generate all the surfaces */
1103 tmpW = EdgeLength;
1104 for (i = 0; i < object->baseTexture.levels; i++) {
1106 /* Create the 6 faces */
1107 for (j = 0; j < 6; j++) {
1109 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1110 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1112 if(hr!= WINED3D_OK) {
1113 /* clean up */
1114 int k;
1115 int l;
1116 for (l = 0; l < j; l++) {
1117 IWineD3DSurface_Release(object->surfaces[l][i]);
1119 for (k = 0; k < i; k++) {
1120 for (l = 0; l < 6; l++) {
1121 IWineD3DSurface_Release(object->surfaces[l][k]);
1125 FIXME("(%p) Failed to create surface\n",object);
1126 HeapFree(GetProcessHeap(),0,object);
1127 *ppCubeTexture = NULL;
1128 return hr;
1130 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1131 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1133 tmpW = max(1, tmpW >> 1);
1135 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1137 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1138 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1139 return WINED3D_OK;
1142 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1144 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1145 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1146 const IWineD3DQueryVtbl *vtable;
1148 /* Just a check to see if we support this type of query */
1149 switch(Type) {
1150 case WINED3DQUERYTYPE_OCCLUSION:
1151 TRACE("(%p) occlusion query\n", This);
1152 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1153 hr = WINED3D_OK;
1154 else
1155 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1157 vtable = &IWineD3DOcclusionQuery_Vtbl;
1158 break;
1160 case WINED3DQUERYTYPE_EVENT:
1161 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1162 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1163 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1165 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1167 vtable = &IWineD3DEventQuery_Vtbl;
1168 hr = WINED3D_OK;
1169 break;
1171 case WINED3DQUERYTYPE_VCACHE:
1172 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1173 case WINED3DQUERYTYPE_VERTEXSTATS:
1174 case WINED3DQUERYTYPE_TIMESTAMP:
1175 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1176 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1177 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1178 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1179 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1180 case WINED3DQUERYTYPE_PIXELTIMINGS:
1181 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1182 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1183 default:
1184 /* Use the base Query vtable until we have a special one for each query */
1185 vtable = &IWineD3DQuery_Vtbl;
1186 FIXME("(%p) Unhandled query type %d\n", This, Type);
1188 if(NULL == ppQuery || hr != WINED3D_OK) {
1189 return hr;
1192 D3DCREATEOBJECTINSTANCE(object, Query)
1193 object->lpVtbl = vtable;
1194 object->type = Type;
1195 object->state = QUERY_CREATED;
1196 /* allocated the 'extended' data based on the type of query requested */
1197 switch(Type){
1198 case WINED3DQUERYTYPE_OCCLUSION:
1199 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1200 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1202 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1203 TRACE("(%p) Allocating data for an occlusion query\n", This);
1204 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1205 break;
1207 case WINED3DQUERYTYPE_EVENT:
1208 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1209 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1211 if(GL_SUPPORT(APPLE_FENCE)) {
1212 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1213 checkGLcall("glGenFencesAPPLE");
1214 } else if(GL_SUPPORT(NV_FENCE)) {
1215 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1216 checkGLcall("glGenFencesNV");
1218 break;
1220 case WINED3DQUERYTYPE_VCACHE:
1221 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1222 case WINED3DQUERYTYPE_VERTEXSTATS:
1223 case WINED3DQUERYTYPE_TIMESTAMP:
1224 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1225 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1226 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1227 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1228 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1229 case WINED3DQUERYTYPE_PIXELTIMINGS:
1230 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1231 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1232 default:
1233 object->extendedData = 0;
1234 FIXME("(%p) Unhandled query type %d\n",This , Type);
1236 TRACE("(%p) : Created Query %p\n", This, object);
1237 return WINED3D_OK;
1240 /*****************************************************************************
1241 * IWineD3DDeviceImpl_SetupFullscreenWindow
1243 * Helper function that modifies a HWND's Style and ExStyle for proper
1244 * fullscreen use.
1246 * Params:
1247 * iface: Pointer to the IWineD3DDevice interface
1248 * window: Window to setup
1250 *****************************************************************************/
1251 static LONG fullscreen_style(LONG orig_style) {
1252 LONG style = orig_style;
1253 style &= ~WS_CAPTION;
1254 style &= ~WS_THICKFRAME;
1256 /* Make sure the window is managed, otherwise we won't get keyboard input */
1257 style |= WS_POPUP | WS_SYSMENU;
1259 return style;
1262 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1263 LONG exStyle = orig_exStyle;
1265 /* Filter out window decorations */
1266 exStyle &= ~WS_EX_WINDOWEDGE;
1267 exStyle &= ~WS_EX_CLIENTEDGE;
1269 return exStyle;
1272 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1275 LONG style, exStyle;
1276 /* Don't do anything if an original style is stored.
1277 * That shouldn't happen
1279 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1280 if (This->style || This->exStyle) {
1281 ERR("(%p): Want to change the window parameters of HWND %p, but "
1282 "another style is stored for restoration afterwards\n", This, window);
1285 /* Get the parameters and save them */
1286 style = GetWindowLongW(window, GWL_STYLE);
1287 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1288 This->style = style;
1289 This->exStyle = exStyle;
1291 style = fullscreen_style(style);
1292 exStyle = fullscreen_exStyle(exStyle);
1294 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1295 This->style, This->exStyle, style, exStyle);
1297 SetWindowLongW(window, GWL_STYLE, style);
1298 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1300 /* Inform the window about the update. */
1301 SetWindowPos(window, HWND_TOP, 0, 0,
1302 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1303 ShowWindow(window, SW_NORMAL);
1306 /*****************************************************************************
1307 * IWineD3DDeviceImpl_RestoreWindow
1309 * Helper function that restores a windows' properties when taking it out
1310 * of fullscreen mode
1312 * Params:
1313 * iface: Pointer to the IWineD3DDevice interface
1314 * window: Window to setup
1316 *****************************************************************************/
1317 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1319 LONG style, exStyle;
1321 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1322 * switch, do nothing
1324 if (!This->style && !This->exStyle) return;
1326 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1327 This, window, This->style, This->exStyle);
1329 style = GetWindowLongW(window, GWL_STYLE);
1330 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1332 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1333 * Some applications change it before calling Reset() when switching between windowed and
1334 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1336 if(style == fullscreen_style(This->style) &&
1337 exStyle == fullscreen_style(This->exStyle)) {
1338 SetWindowLongW(window, GWL_STYLE, This->style);
1339 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1342 /* Delete the old values */
1343 This->style = 0;
1344 This->exStyle = 0;
1346 /* Inform the window about the update */
1347 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1348 0, 0, 0, 0, /* Pos, Size, ignored */
1349 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1352 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1353 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1354 IUnknown* parent,
1355 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1356 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1359 HDC hDc;
1360 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1361 HRESULT hr = WINED3D_OK;
1362 IUnknown *bufferParent;
1363 BOOL displaymode_set = FALSE;
1364 WINED3DDISPLAYMODE Mode;
1365 const StaticPixelFormatDesc *formatDesc;
1367 TRACE("(%p) : Created Additional Swap Chain\n", This);
1369 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1370 * does a device hold a reference to a swap chain giving them a lifetime of the device
1371 * or does the swap chain notify the device of its destruction.
1372 *******************************/
1374 /* Check the params */
1375 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1376 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1377 return WINED3DERR_INVALIDCALL;
1378 } else if (pPresentationParameters->BackBufferCount > 1) {
1379 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");
1382 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1384 /*********************
1385 * Lookup the window Handle and the relating X window handle
1386 ********************/
1388 /* Setup hwnd we are using, plus which display this equates to */
1389 object->win_handle = pPresentationParameters->hDeviceWindow;
1390 if (!object->win_handle) {
1391 object->win_handle = This->createParms.hFocusWindow;
1393 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1395 hDc = GetDC(object->win_handle);
1396 TRACE("Using hDc %p\n", hDc);
1398 if (NULL == hDc) {
1399 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1400 return WINED3DERR_NOTAVAILABLE;
1403 /* Get info on the current display setup */
1404 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1405 object->orig_width = Mode.Width;
1406 object->orig_height = Mode.Height;
1407 object->orig_fmt = Mode.Format;
1408 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1410 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1411 * then the corresponding dimension of the client area of the hDeviceWindow
1412 * (or the focus window, if hDeviceWindow is NULL) is taken.
1413 **********************/
1415 if (pPresentationParameters->Windowed &&
1416 ((pPresentationParameters->BackBufferWidth == 0) ||
1417 (pPresentationParameters->BackBufferHeight == 0) ||
1418 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1420 RECT Rect;
1421 GetClientRect(object->win_handle, &Rect);
1423 if (pPresentationParameters->BackBufferWidth == 0) {
1424 pPresentationParameters->BackBufferWidth = Rect.right;
1425 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1427 if (pPresentationParameters->BackBufferHeight == 0) {
1428 pPresentationParameters->BackBufferHeight = Rect.bottom;
1429 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1431 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1432 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1433 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1437 /* Put the correct figures in the presentation parameters */
1438 TRACE("Copying across presentation parameters\n");
1439 object->presentParms = *pPresentationParameters;
1441 TRACE("calling rendertarget CB\n");
1442 hr = D3DCB_CreateRenderTarget(This->parent,
1443 parent,
1444 object->presentParms.BackBufferWidth,
1445 object->presentParms.BackBufferHeight,
1446 object->presentParms.BackBufferFormat,
1447 object->presentParms.MultiSampleType,
1448 object->presentParms.MultiSampleQuality,
1449 TRUE /* Lockable */,
1450 &object->frontBuffer,
1451 NULL /* pShared (always null)*/);
1452 if (object->frontBuffer != NULL) {
1453 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1454 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1455 } else {
1456 ERR("Failed to create the front buffer\n");
1457 goto error;
1460 /*********************
1461 * Windowed / Fullscreen
1462 *******************/
1465 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1466 * so we should really check to see if there is a fullscreen swapchain already
1467 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1468 **************************************/
1470 if (!pPresentationParameters->Windowed) {
1471 WINED3DDISPLAYMODE mode;
1474 /* Change the display settings */
1475 mode.Width = pPresentationParameters->BackBufferWidth;
1476 mode.Height = pPresentationParameters->BackBufferHeight;
1477 mode.Format = pPresentationParameters->BackBufferFormat;
1478 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1480 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1481 displaymode_set = TRUE;
1482 IWineD3DDevice_SetFullscreen(iface, TRUE);
1486 * Create an opengl context for the display visual
1487 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1488 * use different properties after that point in time. FIXME: How to handle when requested format
1489 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1490 * it chooses is identical to the one already being used!
1491 **********************************/
1492 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1494 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1495 if(!object->context)
1496 return E_OUTOFMEMORY;
1497 object->num_contexts = 1;
1499 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1500 if (!object->context[0]) {
1501 ERR("Failed to create a new context\n");
1502 hr = WINED3DERR_NOTAVAILABLE;
1503 goto error;
1504 } else {
1505 TRACE("Context created (HWND=%p, glContext=%p)\n",
1506 object->win_handle, object->context[0]->glCtx);
1509 /*********************
1510 * Create the back, front and stencil buffers
1511 *******************/
1512 if(object->presentParms.BackBufferCount > 0) {
1513 int i;
1515 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1516 if(!object->backBuffer) {
1517 ERR("Out of memory\n");
1518 hr = E_OUTOFMEMORY;
1519 goto error;
1522 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1523 TRACE("calling rendertarget CB\n");
1524 hr = D3DCB_CreateRenderTarget(This->parent,
1525 parent,
1526 object->presentParms.BackBufferWidth,
1527 object->presentParms.BackBufferHeight,
1528 object->presentParms.BackBufferFormat,
1529 object->presentParms.MultiSampleType,
1530 object->presentParms.MultiSampleQuality,
1531 TRUE /* Lockable */,
1532 &object->backBuffer[i],
1533 NULL /* pShared (always null)*/);
1534 if(hr == WINED3D_OK && object->backBuffer[i]) {
1535 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1536 } else {
1537 ERR("Cannot create new back buffer\n");
1538 goto error;
1540 ENTER_GL();
1541 glDrawBuffer(GL_BACK);
1542 checkGLcall("glDrawBuffer(GL_BACK)");
1543 LEAVE_GL();
1545 } else {
1546 object->backBuffer = NULL;
1548 /* Single buffering - draw to front buffer */
1549 ENTER_GL();
1550 glDrawBuffer(GL_FRONT);
1551 checkGLcall("glDrawBuffer(GL_FRONT)");
1552 LEAVE_GL();
1555 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1556 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1557 TRACE("Creating depth stencil buffer\n");
1558 if (This->auto_depth_stencil_buffer == NULL ) {
1559 hr = D3DCB_CreateDepthStencil(This->parent,
1560 parent,
1561 object->presentParms.BackBufferWidth,
1562 object->presentParms.BackBufferHeight,
1563 object->presentParms.AutoDepthStencilFormat,
1564 object->presentParms.MultiSampleType,
1565 object->presentParms.MultiSampleQuality,
1566 FALSE /* FIXME: Discard */,
1567 &This->auto_depth_stencil_buffer,
1568 NULL /* pShared (always null)*/ );
1569 if (This->auto_depth_stencil_buffer != NULL)
1570 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1573 /** TODO: A check on width, height and multisample types
1574 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1575 ****************************/
1576 object->wantsDepthStencilBuffer = TRUE;
1577 } else {
1578 object->wantsDepthStencilBuffer = FALSE;
1581 TRACE("Created swapchain %p\n", object);
1582 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1583 return WINED3D_OK;
1585 error:
1586 if (displaymode_set) {
1587 DEVMODEW devmode;
1588 RECT clip_rc;
1590 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1591 ClipCursor(NULL);
1593 /* Change the display settings */
1594 memset(&devmode, 0, sizeof(devmode));
1595 devmode.dmSize = sizeof(devmode);
1596 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1597 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1598 devmode.dmPelsWidth = object->orig_width;
1599 devmode.dmPelsHeight = object->orig_height;
1600 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1603 if (object->backBuffer) {
1604 int i;
1605 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1606 if(object->backBuffer[i]) {
1607 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1608 IUnknown_Release(bufferParent); /* once for the get parent */
1609 if (IUnknown_Release(bufferParent) > 0) {
1610 FIXME("(%p) Something's still holding the back buffer\n",This);
1614 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1615 object->backBuffer = NULL;
1617 if(object->context[0])
1618 DestroyContext(This, object->context[0]);
1619 if(object->frontBuffer) {
1620 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1621 IUnknown_Release(bufferParent); /* once for the get parent */
1622 if (IUnknown_Release(bufferParent) > 0) {
1623 FIXME("(%p) Something's still holding the front buffer\n",This);
1626 HeapFree(GetProcessHeap(), 0, object);
1627 return hr;
1630 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1631 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1633 TRACE("(%p)\n", This);
1635 return This->NumberOfSwapChains;
1638 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1642 if(iSwapChain < This->NumberOfSwapChains) {
1643 *pSwapChain = This->swapchains[iSwapChain];
1644 IWineD3DSwapChain_AddRef(*pSwapChain);
1645 TRACE("(%p) returning %p\n", This, *pSwapChain);
1646 return WINED3D_OK;
1647 } else {
1648 TRACE("Swapchain out of range\n");
1649 *pSwapChain = NULL;
1650 return WINED3DERR_INVALIDCALL;
1654 /*****
1655 * Vertex Declaration
1656 *****/
1657 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1658 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1660 IWineD3DVertexDeclarationImpl *object = NULL;
1661 HRESULT hr = WINED3D_OK;
1663 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1664 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1666 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1668 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1669 if(FAILED(hr)) {
1670 *ppVertexDeclaration = NULL;
1671 HeapFree(GetProcessHeap(), 0, object);
1674 return hr;
1677 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1678 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1680 unsigned int idx, idx2;
1681 unsigned int offset;
1682 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1683 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1684 BOOL has_blend_idx = has_blend &&
1685 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1686 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1687 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1688 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1689 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1690 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1691 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1693 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1694 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1696 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1697 WINED3DVERTEXELEMENT *elements = NULL;
1699 unsigned int size;
1700 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1701 if (has_blend_idx) num_blends--;
1703 /* Compute declaration size */
1704 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1705 has_psize + has_diffuse + has_specular + num_textures + 1;
1707 /* convert the declaration */
1708 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1709 if (!elements)
1710 return 0;
1712 elements[size-1] = end_element;
1713 idx = 0;
1714 if (has_pos) {
1715 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1716 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1717 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1719 else {
1720 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1721 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1723 elements[idx].UsageIndex = 0;
1724 idx++;
1726 if (has_blend && (num_blends > 0)) {
1727 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1728 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1729 else
1730 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1731 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1732 elements[idx].UsageIndex = 0;
1733 idx++;
1735 if (has_blend_idx) {
1736 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1737 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1738 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1739 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1740 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1741 else
1742 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1743 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1744 elements[idx].UsageIndex = 0;
1745 idx++;
1747 if (has_normal) {
1748 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1749 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1750 elements[idx].UsageIndex = 0;
1751 idx++;
1753 if (has_psize) {
1754 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1755 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1756 elements[idx].UsageIndex = 0;
1757 idx++;
1759 if (has_diffuse) {
1760 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1761 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1762 elements[idx].UsageIndex = 0;
1763 idx++;
1765 if (has_specular) {
1766 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1767 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1768 elements[idx].UsageIndex = 1;
1769 idx++;
1771 for (idx2 = 0; idx2 < num_textures; idx2++) {
1772 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1773 switch (numcoords) {
1774 case WINED3DFVF_TEXTUREFORMAT1:
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1776 break;
1777 case WINED3DFVF_TEXTUREFORMAT2:
1778 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1779 break;
1780 case WINED3DFVF_TEXTUREFORMAT3:
1781 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1782 break;
1783 case WINED3DFVF_TEXTUREFORMAT4:
1784 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1785 break;
1787 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1788 elements[idx].UsageIndex = idx2;
1789 idx++;
1792 /* Now compute offsets, and initialize the rest of the fields */
1793 for (idx = 0, offset = 0; idx < size-1; idx++) {
1794 elements[idx].Stream = 0;
1795 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1796 elements[idx].Offset = offset;
1797 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1800 *ppVertexElements = elements;
1801 return size;
1804 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1805 WINED3DVERTEXELEMENT* elements = NULL;
1806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1807 unsigned int size;
1808 DWORD hr;
1810 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1811 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1813 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1814 HeapFree(GetProcessHeap(), 0, elements);
1815 if (hr != S_OK) return hr;
1817 return WINED3D_OK;
1820 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1822 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1823 HRESULT hr = WINED3D_OK;
1824 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1825 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1827 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1829 if (vertex_declaration) {
1830 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1833 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1835 if (WINED3D_OK != hr) {
1836 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1837 IWineD3DVertexShader_Release(*ppVertexShader);
1838 return WINED3DERR_INVALIDCALL;
1840 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1842 return WINED3D_OK;
1845 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1847 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1848 HRESULT hr = WINED3D_OK;
1850 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1851 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1852 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1853 if (WINED3D_OK == hr) {
1854 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1855 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1856 } else {
1857 WARN("(%p) : Failed to create pixel shader\n", This);
1860 return hr;
1863 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1865 IWineD3DPaletteImpl *object;
1866 HRESULT hr;
1867 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1869 /* Create the new object */
1870 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1871 if(!object) {
1872 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1873 return E_OUTOFMEMORY;
1876 object->lpVtbl = &IWineD3DPalette_Vtbl;
1877 object->ref = 1;
1878 object->Flags = Flags;
1879 object->parent = Parent;
1880 object->wineD3DDevice = This;
1881 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1883 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1885 if(!object->hpal) {
1886 HeapFree( GetProcessHeap(), 0, object);
1887 return E_OUTOFMEMORY;
1890 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1891 if(FAILED(hr)) {
1892 IWineD3DPalette_Release((IWineD3DPalette *) object);
1893 return hr;
1896 *Palette = (IWineD3DPalette *) object;
1898 return WINED3D_OK;
1901 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1902 HBITMAP hbm;
1903 BITMAP bm;
1904 HRESULT hr;
1905 HDC dcb = NULL, dcs = NULL;
1906 WINEDDCOLORKEY colorkey;
1908 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1909 if(hbm)
1911 GetObjectA(hbm, sizeof(BITMAP), &bm);
1912 dcb = CreateCompatibleDC(NULL);
1913 if(!dcb) goto out;
1914 SelectObject(dcb, hbm);
1916 else
1918 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1919 * couldn't be loaded
1921 memset(&bm, 0, sizeof(bm));
1922 bm.bmWidth = 32;
1923 bm.bmHeight = 32;
1926 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1927 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1928 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1929 if(FAILED(hr)) {
1930 ERR("Wine logo requested, but failed to create surface\n");
1931 goto out;
1934 if(dcb) {
1935 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1936 if(FAILED(hr)) goto out;
1937 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1938 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1940 colorkey.dwColorSpaceLowValue = 0;
1941 colorkey.dwColorSpaceHighValue = 0;
1942 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1943 } else {
1944 /* Fill the surface with a white color to show that wined3d is there */
1945 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1948 out:
1949 if(dcb) {
1950 DeleteDC(dcb);
1952 if(hbm) {
1953 DeleteObject(hbm);
1955 return;
1958 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1959 unsigned int i;
1960 /* Under DirectX you can have texture stage operations even if no texture is
1961 bound, whereas opengl will only do texture operations when a valid texture is
1962 bound. We emulate this by creating dummy textures and binding them to each
1963 texture stage, but disable all stages by default. Hence if a stage is enabled
1964 then the default texture will kick in until replaced by a SetTexture call */
1965 ENTER_GL();
1967 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1968 /* The dummy texture does not have client storage backing */
1969 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1970 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1972 for (i = 0; i < GL_LIMITS(textures); i++) {
1973 GLubyte white = 255;
1975 /* Make appropriate texture active */
1976 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1977 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1978 checkGLcall("glActiveTextureARB");
1979 } else if (i > 0) {
1980 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1983 /* Generate an opengl texture name */
1984 glGenTextures(1, &This->dummyTextureName[i]);
1985 checkGLcall("glGenTextures");
1986 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1988 /* Generate a dummy 2d texture (not using 1d because they cause many
1989 * DRI drivers fall back to sw) */
1990 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
1991 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1992 checkGLcall("glBindTexture");
1994 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1995 checkGLcall("glTexImage2D");
1997 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1998 /* Reenable because if supported it is enabled by default */
1999 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2000 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2003 LEAVE_GL();
2006 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2007 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2008 IWineD3DSwapChainImpl *swapchain = NULL;
2009 HRESULT hr;
2010 DWORD state;
2012 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2013 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2015 /* TODO: Test if OpenGL is compiled in and loaded */
2017 TRACE("(%p) : Creating stateblock\n", This);
2018 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2019 hr = IWineD3DDevice_CreateStateBlock(iface,
2020 WINED3DSBT_INIT,
2021 (IWineD3DStateBlock **)&This->stateBlock,
2022 NULL);
2023 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2024 WARN("Failed to create stateblock\n");
2025 goto err_out;
2027 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2028 This->updateStateBlock = This->stateBlock;
2029 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2031 hr = allocate_shader_constants(This->updateStateBlock);
2032 if (WINED3D_OK != hr) {
2033 goto err_out;
2036 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2037 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2038 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2040 /* Initialize the texture unit mapping to a 1:1 mapping */
2041 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2042 if (state < GL_LIMITS(fragment_samplers)) {
2043 This->texUnitMap[state] = state;
2044 This->rev_tex_unit_map[state] = state;
2045 } else {
2046 This->texUnitMap[state] = -1;
2047 This->rev_tex_unit_map[state] = -1;
2051 /* Setup the implicit swapchain */
2052 TRACE("Creating implicit swapchain\n");
2053 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2054 if (FAILED(hr) || !swapchain) {
2055 WARN("Failed to create implicit swapchain\n");
2056 goto err_out;
2059 This->NumberOfSwapChains = 1;
2060 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2061 if(!This->swapchains) {
2062 ERR("Out of memory!\n");
2063 goto err_out;
2065 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2067 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2068 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2069 This->render_targets[0] = swapchain->backBuffer[0];
2070 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2072 else {
2073 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2074 This->render_targets[0] = swapchain->frontBuffer;
2075 This->lastActiveRenderTarget = swapchain->frontBuffer;
2077 IWineD3DSurface_AddRef(This->render_targets[0]);
2078 This->activeContext = swapchain->context[0];
2079 This->lastThread = GetCurrentThreadId();
2081 /* Depth Stencil support */
2082 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2083 if (NULL != This->stencilBufferTarget) {
2084 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2087 /* Set up some starting GL setup */
2088 ENTER_GL();
2090 /* Setup all the devices defaults */
2091 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2092 create_dummy_textures(This);
2093 #if 0
2094 IWineD3DImpl_CheckGraphicsMemory();
2095 #endif
2097 { /* Set a default viewport */
2098 WINED3DVIEWPORT vp;
2099 vp.X = 0;
2100 vp.Y = 0;
2101 vp.Width = pPresentationParameters->BackBufferWidth;
2102 vp.Height = pPresentationParameters->BackBufferHeight;
2103 vp.MinZ = 0.0f;
2104 vp.MaxZ = 1.0f;
2105 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2108 /* Initialize the current view state */
2109 This->view_ident = 1;
2110 This->contexts[0]->last_was_rhw = 0;
2111 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2112 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2114 switch(wined3d_settings.offscreen_rendering_mode) {
2115 case ORM_FBO:
2116 case ORM_PBUFFER:
2117 This->offscreenBuffer = GL_BACK;
2118 break;
2120 case ORM_BACKBUFFER:
2122 if(GL_LIMITS(aux_buffers) > 0) {
2123 TRACE("Using auxilliary buffer for offscreen rendering\n");
2124 This->offscreenBuffer = GL_AUX0;
2125 } else {
2126 TRACE("Using back buffer for offscreen rendering\n");
2127 This->offscreenBuffer = GL_BACK;
2132 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2133 LEAVE_GL();
2135 /* Clear the screen */
2136 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2137 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2138 0x00, 1.0, 0);
2140 This->d3d_initialized = TRUE;
2142 if(wined3d_settings.logo) {
2143 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2145 This->highest_dirty_ps_const = 0;
2146 This->highest_dirty_vs_const = 0;
2147 return WINED3D_OK;
2149 err_out:
2150 HeapFree(GetProcessHeap(), 0, This->render_targets);
2151 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2152 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2153 HeapFree(GetProcessHeap(), 0, This->swapchains);
2154 This->NumberOfSwapChains = 0;
2155 if(swapchain) {
2156 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2158 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2159 if(This->stateBlock) {
2160 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2161 This->stateBlock = NULL;
2163 return hr;
2166 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2168 int sampler;
2169 UINT i;
2170 TRACE("(%p)\n", This);
2172 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2174 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2175 * it was created. Thus make sure a context is active for the glDelete* calls
2177 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2179 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2181 TRACE("Deleting high order patches\n");
2182 for(i = 0; i < PATCHMAP_SIZE; i++) {
2183 struct list *e1, *e2;
2184 struct WineD3DRectPatch *patch;
2185 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2186 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2187 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2191 /* Delete the palette conversion shader if it is around */
2192 if(This->paletteConversionShader) {
2193 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2194 This->paletteConversionShader = 0;
2197 /* Delete the pbuffer context if there is any */
2198 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2200 /* Delete the mouse cursor texture */
2201 if(This->cursorTexture) {
2202 ENTER_GL();
2203 glDeleteTextures(1, &This->cursorTexture);
2204 LEAVE_GL();
2205 This->cursorTexture = 0;
2208 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2209 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2211 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2212 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2215 /* Release the update stateblock */
2216 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2217 if(This->updateStateBlock != This->stateBlock)
2218 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2220 This->updateStateBlock = NULL;
2222 { /* because were not doing proper internal refcounts releasing the primary state block
2223 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2224 to set this->stateBlock = NULL; first */
2225 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2226 This->stateBlock = NULL;
2228 /* Release the stateblock */
2229 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2230 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2234 /* Release the buffers (with sanity checks)*/
2235 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2236 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2237 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2238 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2240 This->stencilBufferTarget = NULL;
2242 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2243 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2244 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2246 TRACE("Setting rendertarget to NULL\n");
2247 This->render_targets[0] = NULL;
2249 if (This->auto_depth_stencil_buffer) {
2250 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2251 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2253 This->auto_depth_stencil_buffer = NULL;
2256 for(i=0; i < This->NumberOfSwapChains; i++) {
2257 TRACE("Releasing the implicit swapchain %d\n", i);
2258 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2259 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2263 HeapFree(GetProcessHeap(), 0, This->swapchains);
2264 This->swapchains = NULL;
2265 This->NumberOfSwapChains = 0;
2267 HeapFree(GetProcessHeap(), 0, This->render_targets);
2268 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2269 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2270 This->render_targets = NULL;
2271 This->fbo_color_attachments = NULL;
2272 This->draw_buffers = NULL;
2275 This->d3d_initialized = FALSE;
2276 return WINED3D_OK;
2279 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2281 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2283 /* Setup the window for fullscreen mode */
2284 if(fullscreen && !This->ddraw_fullscreen) {
2285 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2286 } else if(!fullscreen && This->ddraw_fullscreen) {
2287 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2290 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2291 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2292 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2293 * separately.
2295 This->ddraw_fullscreen = fullscreen;
2298 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2299 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2300 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2302 * There is no way to deactivate thread safety once it is enabled.
2304 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2307 /*For now just store the flag(needed in case of ddraw) */
2308 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2310 return;
2313 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2314 DEVMODEW devmode;
2315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2316 LONG ret;
2317 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2318 RECT clip_rc;
2320 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2322 /* Resize the screen even without a window:
2323 * The app could have unset it with SetCooperativeLevel, but not called
2324 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2325 * but we don't have any hwnd
2328 memset(&devmode, 0, sizeof(devmode));
2329 devmode.dmSize = sizeof(devmode);
2330 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2331 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2332 devmode.dmPelsWidth = pMode->Width;
2333 devmode.dmPelsHeight = pMode->Height;
2335 devmode.dmDisplayFrequency = pMode->RefreshRate;
2336 if (pMode->RefreshRate != 0) {
2337 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2340 /* Only change the mode if necessary */
2341 if( (This->ddraw_width == pMode->Width) &&
2342 (This->ddraw_height == pMode->Height) &&
2343 (This->ddraw_format == pMode->Format) &&
2344 (pMode->RefreshRate == 0) ) {
2345 return WINED3D_OK;
2348 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2349 if (ret != DISP_CHANGE_SUCCESSFUL) {
2350 if(devmode.dmDisplayFrequency != 0) {
2351 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2352 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2353 devmode.dmDisplayFrequency = 0;
2354 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2356 if(ret != DISP_CHANGE_SUCCESSFUL) {
2357 return WINED3DERR_NOTAVAILABLE;
2361 /* Store the new values */
2362 This->ddraw_width = pMode->Width;
2363 This->ddraw_height = pMode->Height;
2364 This->ddraw_format = pMode->Format;
2366 /* Only do this with a window of course, and only if we're fullscreened */
2367 if(This->ddraw_window && This->ddraw_fullscreen)
2368 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2370 /* And finally clip mouse to our screen */
2371 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2372 ClipCursor(&clip_rc);
2374 return WINED3D_OK;
2377 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2379 *ppD3D= This->wineD3D;
2380 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2381 IWineD3D_AddRef(*ppD3D);
2382 return WINED3D_OK;
2385 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2388 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2389 (This->adapter->TextureRam/(1024*1024)),
2390 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2391 /* return simulated texture memory left */
2392 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2397 /*****
2398 * Get / Set FVF
2399 *****/
2400 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2403 /* Update the current state block */
2404 This->updateStateBlock->changed.fvf = TRUE;
2406 if(This->updateStateBlock->fvf == fvf) {
2407 TRACE("Application is setting the old fvf over, nothing to do\n");
2408 return WINED3D_OK;
2411 This->updateStateBlock->fvf = fvf;
2412 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2413 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2414 return WINED3D_OK;
2418 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2420 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2421 *pfvf = This->stateBlock->fvf;
2422 return WINED3D_OK;
2425 /*****
2426 * Get / Set Stream Source
2427 *****/
2428 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2430 IWineD3DVertexBuffer *oldSrc;
2432 if (StreamNumber >= MAX_STREAMS) {
2433 WARN("Stream out of range %d\n", StreamNumber);
2434 return WINED3DERR_INVALIDCALL;
2435 } else if(OffsetInBytes & 0x3) {
2436 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2437 return WINED3DERR_INVALIDCALL;
2440 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2441 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2443 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2445 if(oldSrc == pStreamData &&
2446 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2447 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2448 TRACE("Application is setting the old values over, nothing to do\n");
2449 return WINED3D_OK;
2452 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2453 if (pStreamData) {
2454 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2455 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2458 /* Handle recording of state blocks */
2459 if (This->isRecordingState) {
2460 TRACE("Recording... not performing anything\n");
2461 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2462 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2463 return WINED3D_OK;
2466 /* Need to do a getParent and pass the references up */
2467 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2468 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2469 so for now, just count internally */
2470 if (pStreamData != NULL) {
2471 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2472 InterlockedIncrement(&vbImpl->bindCount);
2473 IWineD3DVertexBuffer_AddRef(pStreamData);
2475 if (oldSrc != NULL) {
2476 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2477 IWineD3DVertexBuffer_Release(oldSrc);
2480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2482 return WINED3D_OK;
2485 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2488 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2489 This->stateBlock->streamSource[StreamNumber],
2490 This->stateBlock->streamOffset[StreamNumber],
2491 This->stateBlock->streamStride[StreamNumber]);
2493 if (StreamNumber >= MAX_STREAMS) {
2494 WARN("Stream out of range %d\n", StreamNumber);
2495 return WINED3DERR_INVALIDCALL;
2497 *pStream = This->stateBlock->streamSource[StreamNumber];
2498 *pStride = This->stateBlock->streamStride[StreamNumber];
2499 if (pOffset) {
2500 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2503 if (*pStream != NULL) {
2504 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2506 return WINED3D_OK;
2509 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2512 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2514 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2515 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2517 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2518 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2520 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2521 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2525 return WINED3D_OK;
2528 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2531 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2532 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2534 TRACE("(%p) : returning %d\n", This, *Divider);
2536 return WINED3D_OK;
2539 /*****
2540 * Get / Set & Multiply Transform
2541 *****/
2542 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2545 /* Most of this routine, comments included copied from ddraw tree initially: */
2546 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2548 /* Handle recording of state blocks */
2549 if (This->isRecordingState) {
2550 TRACE("Recording... not performing anything\n");
2551 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2552 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2553 return WINED3D_OK;
2557 * If the new matrix is the same as the current one,
2558 * we cut off any further processing. this seems to be a reasonable
2559 * optimization because as was noticed, some apps (warcraft3 for example)
2560 * tend towards setting the same matrix repeatedly for some reason.
2562 * From here on we assume that the new matrix is different, wherever it matters.
2564 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2565 TRACE("The app is setting the same matrix over again\n");
2566 return WINED3D_OK;
2567 } else {
2568 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2572 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2573 where ViewMat = Camera space, WorldMat = world space.
2575 In OpenGL, camera and world space is combined into GL_MODELVIEW
2576 matrix. The Projection matrix stay projection matrix.
2579 /* Capture the times we can just ignore the change for now */
2580 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2581 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2582 /* Handled by the state manager */
2585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2586 return WINED3D_OK;
2589 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2592 *pMatrix = This->stateBlock->transforms[State];
2593 return WINED3D_OK;
2596 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2597 WINED3DMATRIX *mat = NULL;
2598 WINED3DMATRIX temp;
2600 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2601 * below means it will be recorded in a state block change, but it
2602 * works regardless where it is recorded.
2603 * If this is found to be wrong, change to StateBlock.
2605 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2606 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2608 if (State < HIGHEST_TRANSFORMSTATE)
2610 mat = &This->updateStateBlock->transforms[State];
2611 } else {
2612 FIXME("Unhandled transform state!!\n");
2615 multiply_matrix(&temp, mat, pMatrix);
2617 /* Apply change via set transform - will reapply to eg. lights this way */
2618 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2621 /*****
2622 * Get / Set Light
2623 *****/
2624 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2625 you can reference any indexes you want as long as that number max are enabled at any
2626 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2627 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2628 but when recording, just build a chain pretty much of commands to be replayed. */
2630 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2631 float rho;
2632 PLIGHTINFOEL *object = NULL;
2633 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2634 struct list *e;
2636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2637 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2639 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2640 * the gl driver.
2642 if(!pLight) {
2643 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2644 return WINED3DERR_INVALIDCALL;
2647 switch(pLight->Type) {
2648 case WINED3DLIGHT_POINT:
2649 case WINED3DLIGHT_SPOT:
2650 case WINED3DLIGHT_PARALLELPOINT:
2651 case WINED3DLIGHT_GLSPOT:
2652 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2653 * most wanted
2655 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2656 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2657 return WINED3DERR_INVALIDCALL;
2659 break;
2661 case WINED3DLIGHT_DIRECTIONAL:
2662 /* Ignores attenuation */
2663 break;
2665 default:
2666 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2667 return WINED3DERR_INVALIDCALL;
2670 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2671 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2672 if(object->OriginalIndex == Index) break;
2673 object = NULL;
2676 if(!object) {
2677 TRACE("Adding new light\n");
2678 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2679 if(!object) {
2680 ERR("Out of memory error when allocating a light\n");
2681 return E_OUTOFMEMORY;
2683 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2684 object->glIndex = -1;
2685 object->OriginalIndex = Index;
2686 object->changed = TRUE;
2689 /* Initialize the object */
2690 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,
2691 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2692 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2693 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2694 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2695 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2696 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2698 /* Save away the information */
2699 object->OriginalParms = *pLight;
2701 switch (pLight->Type) {
2702 case WINED3DLIGHT_POINT:
2703 /* Position */
2704 object->lightPosn[0] = pLight->Position.x;
2705 object->lightPosn[1] = pLight->Position.y;
2706 object->lightPosn[2] = pLight->Position.z;
2707 object->lightPosn[3] = 1.0f;
2708 object->cutoff = 180.0f;
2709 /* FIXME: Range */
2710 break;
2712 case WINED3DLIGHT_DIRECTIONAL:
2713 /* Direction */
2714 object->lightPosn[0] = -pLight->Direction.x;
2715 object->lightPosn[1] = -pLight->Direction.y;
2716 object->lightPosn[2] = -pLight->Direction.z;
2717 object->lightPosn[3] = 0.0;
2718 object->exponent = 0.0f;
2719 object->cutoff = 180.0f;
2720 break;
2722 case WINED3DLIGHT_SPOT:
2723 /* Position */
2724 object->lightPosn[0] = pLight->Position.x;
2725 object->lightPosn[1] = pLight->Position.y;
2726 object->lightPosn[2] = pLight->Position.z;
2727 object->lightPosn[3] = 1.0;
2729 /* Direction */
2730 object->lightDirn[0] = pLight->Direction.x;
2731 object->lightDirn[1] = pLight->Direction.y;
2732 object->lightDirn[2] = pLight->Direction.z;
2733 object->lightDirn[3] = 1.0;
2736 * opengl-ish and d3d-ish spot lights use too different models for the
2737 * light "intensity" as a function of the angle towards the main light direction,
2738 * so we only can approximate very roughly.
2739 * however spot lights are rather rarely used in games (if ever used at all).
2740 * furthermore if still used, probably nobody pays attention to such details.
2742 if (pLight->Falloff == 0) {
2743 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2744 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2745 * will always be 1.0 for both of them, and we don't have to care for the
2746 * rest of the rather complex calculation
2748 object->exponent = 0;
2749 } else {
2750 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2751 if (rho < 0.0001) rho = 0.0001f;
2752 object->exponent = -0.3/log(cos(rho/2));
2754 if (object->exponent > 128.0) {
2755 object->exponent = 128.0;
2757 object->cutoff = pLight->Phi*90/M_PI;
2759 /* FIXME: Range */
2760 break;
2762 default:
2763 FIXME("Unrecognized light type %d\n", pLight->Type);
2766 /* Update the live definitions if the light is currently assigned a glIndex */
2767 if (object->glIndex != -1 && !This->isRecordingState) {
2768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2770 return WINED3D_OK;
2773 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2774 PLIGHTINFOEL *lightInfo = NULL;
2775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2776 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2777 struct list *e;
2778 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2780 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2781 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2782 if(lightInfo->OriginalIndex == Index) break;
2783 lightInfo = NULL;
2786 if (lightInfo == NULL) {
2787 TRACE("Light information requested but light not defined\n");
2788 return WINED3DERR_INVALIDCALL;
2791 *pLight = lightInfo->OriginalParms;
2792 return WINED3D_OK;
2795 /*****
2796 * Get / Set Light Enable
2797 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2798 *****/
2799 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2800 PLIGHTINFOEL *lightInfo = NULL;
2801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2802 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2803 struct list *e;
2804 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2806 /* Tests show true = 128...not clear why */
2807 Enable = Enable? 128: 0;
2809 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2810 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2811 if(lightInfo->OriginalIndex == Index) break;
2812 lightInfo = NULL;
2814 TRACE("Found light: %p\n", lightInfo);
2816 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2817 if (lightInfo == NULL) {
2819 TRACE("Light enabled requested but light not defined, so defining one!\n");
2820 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2822 /* Search for it again! Should be fairly quick as near head of list */
2823 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2824 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2825 if(lightInfo->OriginalIndex == Index) break;
2826 lightInfo = NULL;
2828 if (lightInfo == NULL) {
2829 FIXME("Adding default lights has failed dismally\n");
2830 return WINED3DERR_INVALIDCALL;
2834 lightInfo->enabledChanged = TRUE;
2835 if(!Enable) {
2836 if(lightInfo->glIndex != -1) {
2837 if(!This->isRecordingState) {
2838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2841 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2842 lightInfo->glIndex = -1;
2843 } else {
2844 TRACE("Light already disabled, nothing to do\n");
2846 lightInfo->enabled = FALSE;
2847 } else {
2848 lightInfo->enabled = TRUE;
2849 if (lightInfo->glIndex != -1) {
2850 /* nop */
2851 TRACE("Nothing to do as light was enabled\n");
2852 } else {
2853 int i;
2854 /* Find a free gl light */
2855 for(i = 0; i < This->maxConcurrentLights; i++) {
2856 if(This->stateBlock->activeLights[i] == NULL) {
2857 This->stateBlock->activeLights[i] = lightInfo;
2858 lightInfo->glIndex = i;
2859 break;
2862 if(lightInfo->glIndex == -1) {
2863 /* Our tests show that Windows returns D3D_OK in this situation, even with
2864 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2865 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2866 * as well for those lights.
2868 * TODO: Test how this affects rendering
2870 FIXME("Too many concurrently active lights\n");
2871 return WINED3D_OK;
2874 /* i == lightInfo->glIndex */
2875 if(!This->isRecordingState) {
2876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2881 return WINED3D_OK;
2884 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2886 PLIGHTINFOEL *lightInfo = NULL;
2887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2888 struct list *e;
2889 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2890 TRACE("(%p) : for idx(%d)\n", This, Index);
2892 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2893 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2894 if(lightInfo->OriginalIndex == Index) break;
2895 lightInfo = NULL;
2898 if (lightInfo == NULL) {
2899 TRACE("Light enabled state requested but light not defined\n");
2900 return WINED3DERR_INVALIDCALL;
2902 /* true is 128 according to SetLightEnable */
2903 *pEnable = lightInfo->enabled ? 128 : 0;
2904 return WINED3D_OK;
2907 /*****
2908 * Get / Set Clip Planes
2909 *****/
2910 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2914 /* Validate Index */
2915 if (Index >= GL_LIMITS(clipplanes)) {
2916 TRACE("Application has requested clipplane this device doesn't support\n");
2917 return WINED3DERR_INVALIDCALL;
2920 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2922 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2923 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2924 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2925 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2926 TRACE("Application is setting old values over, nothing to do\n");
2927 return WINED3D_OK;
2930 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2931 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2932 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2933 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2935 /* Handle recording of state blocks */
2936 if (This->isRecordingState) {
2937 TRACE("Recording... not performing anything\n");
2938 return WINED3D_OK;
2941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2943 return WINED3D_OK;
2946 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2948 TRACE("(%p) : for idx %d\n", This, Index);
2950 /* Validate Index */
2951 if (Index >= GL_LIMITS(clipplanes)) {
2952 TRACE("Application has requested clipplane this device doesn't support\n");
2953 return WINED3DERR_INVALIDCALL;
2956 pPlane[0] = This->stateBlock->clipplane[Index][0];
2957 pPlane[1] = This->stateBlock->clipplane[Index][1];
2958 pPlane[2] = This->stateBlock->clipplane[Index][2];
2959 pPlane[3] = This->stateBlock->clipplane[Index][3];
2960 return WINED3D_OK;
2963 /*****
2964 * Get / Set Clip Plane Status
2965 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2966 *****/
2967 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2969 FIXME("(%p) : stub\n", This);
2970 if (NULL == pClipStatus) {
2971 return WINED3DERR_INVALIDCALL;
2973 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2974 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 FIXME("(%p) : stub\n", This);
2981 if (NULL == pClipStatus) {
2982 return WINED3DERR_INVALIDCALL;
2984 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2985 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2986 return WINED3D_OK;
2989 /*****
2990 * Get / Set Material
2991 *****/
2992 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 This->updateStateBlock->changed.material = TRUE;
2996 This->updateStateBlock->material = *pMaterial;
2998 /* Handle recording of state blocks */
2999 if (This->isRecordingState) {
3000 TRACE("Recording... not performing anything\n");
3001 return WINED3D_OK;
3004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3005 return WINED3D_OK;
3008 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 *pMaterial = This->updateStateBlock->material;
3011 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3012 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3013 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3014 pMaterial->Ambient.b, pMaterial->Ambient.a);
3015 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3016 pMaterial->Specular.b, pMaterial->Specular.a);
3017 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3018 pMaterial->Emissive.b, pMaterial->Emissive.a);
3019 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3021 return WINED3D_OK;
3024 /*****
3025 * Get / Set Indices
3026 *****/
3027 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3029 IWineD3DIndexBuffer *oldIdxs;
3031 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3032 oldIdxs = This->updateStateBlock->pIndexData;
3034 This->updateStateBlock->changed.indices = TRUE;
3035 This->updateStateBlock->pIndexData = pIndexData;
3037 /* Handle recording of state blocks */
3038 if (This->isRecordingState) {
3039 TRACE("Recording... not performing anything\n");
3040 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3041 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3042 return WINED3D_OK;
3045 if(oldIdxs != pIndexData) {
3046 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3047 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3048 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3050 return WINED3D_OK;
3053 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 *ppIndexData = This->stateBlock->pIndexData;
3058 /* up ref count on ppindexdata */
3059 if (*ppIndexData) {
3060 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3061 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3062 }else{
3063 TRACE("(%p) No index data set\n", This);
3065 TRACE("Returning %p\n", *ppIndexData);
3067 return WINED3D_OK;
3070 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3071 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3073 TRACE("(%p)->(%d)\n", This, BaseIndex);
3075 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3076 TRACE("Application is setting the old value over, nothing to do\n");
3077 return WINED3D_OK;
3080 This->updateStateBlock->baseVertexIndex = BaseIndex;
3082 if (This->isRecordingState) {
3083 TRACE("Recording... not performing anything\n");
3084 return WINED3D_OK;
3086 /* The base vertex index affects the stream sources */
3087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3088 return WINED3D_OK;
3091 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 TRACE("(%p) : base_index %p\n", This, base_index);
3095 *base_index = This->stateBlock->baseVertexIndex;
3097 TRACE("Returning %u\n", *base_index);
3099 return WINED3D_OK;
3102 /*****
3103 * Get / Set Viewports
3104 *****/
3105 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 TRACE("(%p)\n", This);
3109 This->updateStateBlock->changed.viewport = TRUE;
3110 This->updateStateBlock->viewport = *pViewport;
3112 /* Handle recording of state blocks */
3113 if (This->isRecordingState) {
3114 TRACE("Recording... not performing anything\n");
3115 return WINED3D_OK;
3118 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3119 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3122 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 TRACE("(%p)\n", This);
3129 *pViewport = This->stateBlock->viewport;
3130 return WINED3D_OK;
3133 /*****
3134 * Get / Set Render States
3135 * TODO: Verify against dx9 definitions
3136 *****/
3137 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3140 DWORD oldValue = This->stateBlock->renderState[State];
3142 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3144 This->updateStateBlock->changed.renderState[State] = TRUE;
3145 This->updateStateBlock->renderState[State] = Value;
3147 /* Handle recording of state blocks */
3148 if (This->isRecordingState) {
3149 TRACE("Recording... not performing anything\n");
3150 return WINED3D_OK;
3153 /* Compared here and not before the assignment to allow proper stateblock recording */
3154 if(Value == oldValue) {
3155 TRACE("Application is setting the old value over, nothing to do\n");
3156 } else {
3157 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3160 return WINED3D_OK;
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3165 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3166 *pValue = This->stateBlock->renderState[State];
3167 return WINED3D_OK;
3170 /*****
3171 * Get / Set Sampler States
3172 * TODO: Verify against dx9 definitions
3173 *****/
3175 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3177 DWORD oldValue;
3179 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3180 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3182 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3183 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3186 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3187 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3188 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3191 * SetSampler is designed to allow for more than the standard up to 8 textures
3192 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3193 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3195 * http://developer.nvidia.com/object/General_FAQ.html#t6
3197 * There are two new settings for GForce
3198 * the sampler one:
3199 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3200 * and the texture one:
3201 * GL_MAX_TEXTURE_COORDS_ARB.
3202 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3203 ******************/
3205 oldValue = This->stateBlock->samplerState[Sampler][Type];
3206 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3207 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3209 /* Handle recording of state blocks */
3210 if (This->isRecordingState) {
3211 TRACE("Recording... not performing anything\n");
3212 return WINED3D_OK;
3215 if(oldValue == Value) {
3216 TRACE("Application is setting the old value over, nothing to do\n");
3217 return WINED3D_OK;
3220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3222 return WINED3D_OK;
3225 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3229 This, Sampler, debug_d3dsamplerstate(Type), Type);
3231 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3232 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3235 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3236 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3237 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3239 *Value = This->stateBlock->samplerState[Sampler][Type];
3240 TRACE("(%p) : Returning %#x\n", This, *Value);
3242 return WINED3D_OK;
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3248 This->updateStateBlock->changed.scissorRect = TRUE;
3249 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3250 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3251 return WINED3D_OK;
3253 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3255 if(This->isRecordingState) {
3256 TRACE("Recording... not performing anything\n");
3257 return WINED3D_OK;
3260 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3262 return WINED3D_OK;
3265 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 *pRect = This->updateStateBlock->scissorRect;
3269 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3270 return WINED3D_OK;
3273 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3275 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3277 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3279 This->updateStateBlock->vertexDecl = pDecl;
3280 This->updateStateBlock->changed.vertexDecl = TRUE;
3282 if (This->isRecordingState) {
3283 TRACE("Recording... not performing anything\n");
3284 return WINED3D_OK;
3285 } else if(pDecl == oldDecl) {
3286 /* Checked after the assignment to allow proper stateblock recording */
3287 TRACE("Application is setting the old declaration over, nothing to do\n");
3288 return WINED3D_OK;
3291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3292 return WINED3D_OK;
3295 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3298 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3300 *ppDecl = This->stateBlock->vertexDecl;
3301 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3302 return WINED3D_OK;
3305 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3309 This->updateStateBlock->vertexShader = pShader;
3310 This->updateStateBlock->changed.vertexShader = TRUE;
3312 if (This->isRecordingState) {
3313 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3314 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3315 TRACE("Recording... not performing anything\n");
3316 return WINED3D_OK;
3317 } else if(oldShader == pShader) {
3318 /* Checked here to allow proper stateblock recording */
3319 TRACE("App is setting the old shader over, nothing to do\n");
3320 return WINED3D_OK;
3323 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3324 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3325 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3329 return WINED3D_OK;
3332 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3335 if (NULL == ppShader) {
3336 return WINED3DERR_INVALIDCALL;
3338 *ppShader = This->stateBlock->vertexShader;
3339 if( NULL != *ppShader)
3340 IWineD3DVertexShader_AddRef(*ppShader);
3342 TRACE("(%p) : returning %p\n", This, *ppShader);
3343 return WINED3D_OK;
3346 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3347 IWineD3DDevice *iface,
3348 UINT start,
3349 CONST BOOL *srcData,
3350 UINT count) {
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3353 int i, cnt = min(count, MAX_CONST_B - start);
3355 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3356 iface, srcData, start, count);
3358 if (srcData == NULL || cnt < 0)
3359 return WINED3DERR_INVALIDCALL;
3361 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3362 for (i = 0; i < cnt; i++)
3363 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3365 for (i = start; i < cnt + start; ++i) {
3366 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3371 return WINED3D_OK;
3374 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3375 IWineD3DDevice *iface,
3376 UINT start,
3377 BOOL *dstData,
3378 UINT count) {
3380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3381 int cnt = min(count, MAX_CONST_B - start);
3383 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3384 iface, dstData, start, count);
3386 if (dstData == NULL || cnt < 0)
3387 return WINED3DERR_INVALIDCALL;
3389 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3390 return WINED3D_OK;
3393 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3394 IWineD3DDevice *iface,
3395 UINT start,
3396 CONST int *srcData,
3397 UINT count) {
3399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 int i, cnt = min(count, MAX_CONST_I - start);
3402 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3403 iface, srcData, start, count);
3405 if (srcData == NULL || cnt < 0)
3406 return WINED3DERR_INVALIDCALL;
3408 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3409 for (i = 0; i < cnt; i++)
3410 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3411 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3413 for (i = start; i < cnt + start; ++i) {
3414 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3419 return WINED3D_OK;
3422 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3423 IWineD3DDevice *iface,
3424 UINT start,
3425 int *dstData,
3426 UINT count) {
3428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3429 int cnt = min(count, MAX_CONST_I - start);
3431 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3432 iface, dstData, start, count);
3434 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3435 return WINED3DERR_INVALIDCALL;
3437 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3438 return WINED3D_OK;
3441 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3442 IWineD3DDevice *iface,
3443 UINT start,
3444 CONST float *srcData,
3445 UINT count) {
3447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3448 int i;
3450 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3451 iface, srcData, start, count);
3453 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3454 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3455 return WINED3DERR_INVALIDCALL;
3457 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3458 if(TRACE_ON(d3d)) {
3459 for (i = 0; i < count; i++)
3460 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3461 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3464 for (i = start; i < count + start; ++i) {
3465 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3466 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3467 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3468 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3469 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3471 ptr->idx[ptr->count++] = i;
3472 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3476 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3478 return WINED3D_OK;
3481 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3482 IWineD3DDevice *iface,
3483 UINT start,
3484 CONST float *srcData,
3485 UINT count) {
3487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3488 int i;
3490 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3491 iface, srcData, start, count);
3493 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3494 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3495 return WINED3DERR_INVALIDCALL;
3497 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3498 if(TRACE_ON(d3d)) {
3499 for (i = 0; i < count; i++)
3500 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3501 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3504 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3505 * context. On a context switch the old context will be fully dirtified
3507 memset(This->activeContext->vshader_const_dirty + start, 1,
3508 sizeof(*This->activeContext->vshader_const_dirty) * count);
3509 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3513 return WINED3D_OK;
3516 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3517 IWineD3DDevice *iface,
3518 UINT start,
3519 float *dstData,
3520 UINT count) {
3522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3523 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3525 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3526 iface, dstData, start, count);
3528 if (dstData == NULL || cnt < 0)
3529 return WINED3DERR_INVALIDCALL;
3531 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3532 return WINED3D_OK;
3535 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3536 DWORD i;
3537 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3542 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3543 int i = This->rev_tex_unit_map[unit];
3544 int j = This->texUnitMap[stage];
3546 This->texUnitMap[stage] = unit;
3547 if (i != -1 && i != stage) {
3548 This->texUnitMap[i] = -1;
3551 This->rev_tex_unit_map[unit] = stage;
3552 if (j != -1 && j != unit) {
3553 This->rev_tex_unit_map[j] = -1;
3557 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3558 int i;
3560 for (i = 0; i < MAX_TEXTURES; ++i) {
3561 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3562 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3563 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3564 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3565 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3566 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3567 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3568 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3570 if (color_op == WINED3DTOP_DISABLE) {
3571 /* Not used, and disable higher stages */
3572 while (i < MAX_TEXTURES) {
3573 This->fixed_function_usage_map[i] = FALSE;
3574 ++i;
3576 break;
3579 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3580 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3581 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3582 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3583 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3584 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3585 This->fixed_function_usage_map[i] = TRUE;
3586 } else {
3587 This->fixed_function_usage_map[i] = FALSE;
3590 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3591 This->fixed_function_usage_map[i+1] = TRUE;
3596 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3597 int i, tex;
3599 device_update_fixed_function_usage_map(This);
3601 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3602 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3603 if (!This->fixed_function_usage_map[i]) continue;
3605 if (This->texUnitMap[i] != i) {
3606 device_map_stage(This, i, i);
3607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3608 markTextureStagesDirty(This, i);
3611 return;
3614 /* Now work out the mapping */
3615 tex = 0;
3616 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3617 if (!This->fixed_function_usage_map[i]) continue;
3619 if (This->texUnitMap[i] != tex) {
3620 device_map_stage(This, i, tex);
3621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3622 markTextureStagesDirty(This, i);
3625 ++tex;
3629 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3630 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3631 int i;
3633 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3634 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3635 device_map_stage(This, i, i);
3636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3637 if (i < MAX_TEXTURES) {
3638 markTextureStagesDirty(This, i);
3644 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3645 int current_mapping = This->rev_tex_unit_map[unit];
3647 if (current_mapping == -1) {
3648 /* Not currently used */
3649 return TRUE;
3652 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3653 /* Used by a fragment sampler */
3655 if (!pshader_sampler_tokens) {
3656 /* No pixel shader, check fixed function */
3657 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3660 /* Pixel shader, check the shader's sampler map */
3661 return !pshader_sampler_tokens[current_mapping];
3664 /* Used by a vertex sampler */
3665 return !vshader_sampler_tokens[current_mapping];
3668 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3669 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3670 DWORD *pshader_sampler_tokens = NULL;
3671 int start = GL_LIMITS(combined_samplers) - 1;
3672 int i;
3674 if (ps) {
3675 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3677 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3678 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3679 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3682 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3683 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3684 if (vshader_sampler_tokens[i]) {
3685 if (This->texUnitMap[vsampler_idx] != -1) {
3686 /* Already mapped somewhere */
3687 continue;
3690 while (start >= 0) {
3691 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3692 device_map_stage(This, vsampler_idx, start);
3693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3695 --start;
3696 break;
3699 --start;
3705 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3706 BOOL vs = use_vs(This);
3707 BOOL ps = use_ps(This);
3709 * Rules are:
3710 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3711 * that would be really messy and require shader recompilation
3712 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3713 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3715 if (ps) {
3716 device_map_psamplers(This);
3717 } else {
3718 device_map_fixed_function_samplers(This);
3721 if (vs) {
3722 device_map_vsamplers(This, ps);
3726 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3728 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3729 This->updateStateBlock->pixelShader = pShader;
3730 This->updateStateBlock->changed.pixelShader = TRUE;
3732 /* Handle recording of state blocks */
3733 if (This->isRecordingState) {
3734 TRACE("Recording... not performing anything\n");
3737 if (This->isRecordingState) {
3738 TRACE("Recording... not performing anything\n");
3739 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3740 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3741 return WINED3D_OK;
3744 if(pShader == oldShader) {
3745 TRACE("App is setting the old pixel shader over, nothing to do\n");
3746 return WINED3D_OK;
3749 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3750 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3752 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3753 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3755 return WINED3D_OK;
3758 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761 if (NULL == ppShader) {
3762 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3763 return WINED3DERR_INVALIDCALL;
3766 *ppShader = This->stateBlock->pixelShader;
3767 if (NULL != *ppShader) {
3768 IWineD3DPixelShader_AddRef(*ppShader);
3770 TRACE("(%p) : returning %p\n", This, *ppShader);
3771 return WINED3D_OK;
3774 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3775 IWineD3DDevice *iface,
3776 UINT start,
3777 CONST BOOL *srcData,
3778 UINT count) {
3780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3781 int i, cnt = min(count, MAX_CONST_B - start);
3783 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3784 iface, srcData, start, count);
3786 if (srcData == NULL || cnt < 0)
3787 return WINED3DERR_INVALIDCALL;
3789 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3790 for (i = 0; i < cnt; i++)
3791 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3793 for (i = start; i < cnt + start; ++i) {
3794 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3799 return WINED3D_OK;
3802 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3803 IWineD3DDevice *iface,
3804 UINT start,
3805 BOOL *dstData,
3806 UINT count) {
3808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3809 int cnt = min(count, MAX_CONST_B - start);
3811 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3812 iface, dstData, start, count);
3814 if (dstData == NULL || cnt < 0)
3815 return WINED3DERR_INVALIDCALL;
3817 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3818 return WINED3D_OK;
3821 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3822 IWineD3DDevice *iface,
3823 UINT start,
3824 CONST int *srcData,
3825 UINT count) {
3827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3828 int i, cnt = min(count, MAX_CONST_I - start);
3830 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3831 iface, srcData, start, count);
3833 if (srcData == NULL || cnt < 0)
3834 return WINED3DERR_INVALIDCALL;
3836 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3837 for (i = 0; i < cnt; i++)
3838 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3839 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3841 for (i = start; i < cnt + start; ++i) {
3842 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3847 return WINED3D_OK;
3850 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3851 IWineD3DDevice *iface,
3852 UINT start,
3853 int *dstData,
3854 UINT count) {
3856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3857 int cnt = min(count, MAX_CONST_I - start);
3859 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3860 iface, dstData, start, count);
3862 if (dstData == NULL || cnt < 0)
3863 return WINED3DERR_INVALIDCALL;
3865 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3866 return WINED3D_OK;
3869 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3870 IWineD3DDevice *iface,
3871 UINT start,
3872 CONST float *srcData,
3873 UINT count) {
3875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3876 int i;
3878 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3879 iface, srcData, start, count);
3881 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3882 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3883 return WINED3DERR_INVALIDCALL;
3885 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3886 if(TRACE_ON(d3d)) {
3887 for (i = 0; i < count; i++)
3888 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3889 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3892 for (i = start; i < count + start; ++i) {
3893 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3894 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3895 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3896 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3897 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3899 ptr->idx[ptr->count++] = i;
3900 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3904 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3906 return WINED3D_OK;
3909 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
3910 IWineD3DDevice *iface,
3911 UINT start,
3912 CONST float *srcData,
3913 UINT count) {
3915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3916 int i;
3918 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3919 iface, srcData, start, count);
3921 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3922 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3923 return WINED3DERR_INVALIDCALL;
3925 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3926 if(TRACE_ON(d3d)) {
3927 for (i = 0; i < count; i++)
3928 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3929 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3932 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3933 * context. On a context switch the old context will be fully dirtified
3935 memset(This->activeContext->pshader_const_dirty + start, 1,
3936 sizeof(*This->activeContext->pshader_const_dirty) * count);
3937 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
3939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3941 return WINED3D_OK;
3944 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3945 IWineD3DDevice *iface,
3946 UINT start,
3947 float *dstData,
3948 UINT count) {
3950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3951 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3953 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3954 iface, dstData, start, count);
3956 if (dstData == NULL || cnt < 0)
3957 return WINED3DERR_INVALIDCALL;
3959 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3960 return WINED3D_OK;
3963 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3964 static HRESULT
3965 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3966 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3967 unsigned int i;
3968 DWORD DestFVF = dest->fvf;
3969 WINED3DVIEWPORT vp;
3970 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3971 BOOL doClip;
3972 int numTextures;
3974 if (lpStrideData->u.s.normal.lpData) {
3975 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3978 if (lpStrideData->u.s.position.lpData == NULL) {
3979 ERR("Source has no position mask\n");
3980 return WINED3DERR_INVALIDCALL;
3983 /* We might access VBOs from this code, so hold the lock */
3984 ENTER_GL();
3986 if (dest->resource.allocatedMemory == NULL) {
3987 /* This may happen if we do direct locking into a vbo. Unlikely,
3988 * but theoretically possible(ddraw processvertices test)
3990 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3991 if(!dest->resource.allocatedMemory) {
3992 LEAVE_GL();
3993 ERR("Out of memory\n");
3994 return E_OUTOFMEMORY;
3996 if(dest->vbo) {
3997 void *src;
3998 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3999 checkGLcall("glBindBufferARB");
4000 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4001 if(src) {
4002 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4004 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4005 checkGLcall("glUnmapBufferARB");
4009 /* Get a pointer into the destination vbo(create one if none exists) and
4010 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4012 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4013 dest->Flags |= VBFLAG_CREATEVBO;
4014 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4017 if(dest->vbo) {
4018 unsigned char extrabytes = 0;
4019 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4020 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4021 * this may write 4 extra bytes beyond the area that should be written
4023 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4024 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4025 if(!dest_conv_addr) {
4026 ERR("Out of memory\n");
4027 /* Continue without storing converted vertices */
4029 dest_conv = dest_conv_addr;
4032 /* Should I clip?
4033 * a) WINED3DRS_CLIPPING is enabled
4034 * b) WINED3DVOP_CLIP is passed
4036 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4037 static BOOL warned = FALSE;
4039 * The clipping code is not quite correct. Some things need
4040 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4041 * so disable clipping for now.
4042 * (The graphics in Half-Life are broken, and my processvertices
4043 * test crashes with IDirect3DDevice3)
4044 doClip = TRUE;
4046 doClip = FALSE;
4047 if(!warned) {
4048 warned = TRUE;
4049 FIXME("Clipping is broken and disabled for now\n");
4051 } else doClip = FALSE;
4052 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4054 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4055 WINED3DTS_VIEW,
4056 &view_mat);
4057 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4058 WINED3DTS_PROJECTION,
4059 &proj_mat);
4060 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4061 WINED3DTS_WORLDMATRIX(0),
4062 &world_mat);
4064 TRACE("View mat:\n");
4065 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);
4066 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);
4067 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);
4068 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);
4070 TRACE("Proj mat:\n");
4071 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);
4072 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);
4073 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);
4074 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);
4076 TRACE("World mat:\n");
4077 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);
4078 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);
4079 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);
4080 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);
4082 /* Get the viewport */
4083 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4084 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4085 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4087 multiply_matrix(&mat,&view_mat,&world_mat);
4088 multiply_matrix(&mat,&proj_mat,&mat);
4090 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4092 for (i = 0; i < dwCount; i+= 1) {
4093 unsigned int tex_index;
4095 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4096 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4097 /* The position first */
4098 float *p =
4099 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4100 float x, y, z, rhw;
4101 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4103 /* Multiplication with world, view and projection matrix */
4104 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);
4105 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);
4106 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);
4107 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);
4109 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4111 /* WARNING: The following things are taken from d3d7 and were not yet checked
4112 * against d3d8 or d3d9!
4115 /* Clipping conditions: From msdn
4117 * A vertex is clipped if it does not match the following requirements
4118 * -rhw < x <= rhw
4119 * -rhw < y <= rhw
4120 * 0 < z <= rhw
4121 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4123 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4124 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4128 if( !doClip ||
4129 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4130 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4131 ( rhw > eps ) ) ) {
4133 /* "Normal" viewport transformation (not clipped)
4134 * 1) The values are divided by rhw
4135 * 2) The y axis is negative, so multiply it with -1
4136 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4137 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4138 * 4) Multiply x with Width/2 and add Width/2
4139 * 5) The same for the height
4140 * 6) Add the viewpoint X and Y to the 2D coordinates and
4141 * The minimum Z value to z
4142 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4144 * Well, basically it's simply a linear transformation into viewport
4145 * coordinates
4148 x /= rhw;
4149 y /= rhw;
4150 z /= rhw;
4152 y *= -1;
4154 x *= vp.Width / 2;
4155 y *= vp.Height / 2;
4156 z *= vp.MaxZ - vp.MinZ;
4158 x += vp.Width / 2 + vp.X;
4159 y += vp.Height / 2 + vp.Y;
4160 z += vp.MinZ;
4162 rhw = 1 / rhw;
4163 } else {
4164 /* That vertex got clipped
4165 * Contrary to OpenGL it is not dropped completely, it just
4166 * undergoes a different calculation.
4168 TRACE("Vertex got clipped\n");
4169 x += rhw;
4170 y += rhw;
4172 x /= 2;
4173 y /= 2;
4175 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4176 * outside of the main vertex buffer memory. That needs some more
4177 * investigation...
4181 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4184 ( (float *) dest_ptr)[0] = x;
4185 ( (float *) dest_ptr)[1] = y;
4186 ( (float *) dest_ptr)[2] = z;
4187 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4189 dest_ptr += 3 * sizeof(float);
4191 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4192 dest_ptr += sizeof(float);
4195 if(dest_conv) {
4196 float w = 1 / rhw;
4197 ( (float *) dest_conv)[0] = x * w;
4198 ( (float *) dest_conv)[1] = y * w;
4199 ( (float *) dest_conv)[2] = z * w;
4200 ( (float *) dest_conv)[3] = w;
4202 dest_conv += 3 * sizeof(float);
4204 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4205 dest_conv += sizeof(float);
4209 if (DestFVF & WINED3DFVF_PSIZE) {
4210 dest_ptr += sizeof(DWORD);
4211 if(dest_conv) dest_conv += sizeof(DWORD);
4213 if (DestFVF & WINED3DFVF_NORMAL) {
4214 float *normal =
4215 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4216 /* AFAIK this should go into the lighting information */
4217 FIXME("Didn't expect the destination to have a normal\n");
4218 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4219 if(dest_conv) {
4220 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4224 if (DestFVF & WINED3DFVF_DIFFUSE) {
4225 DWORD *color_d =
4226 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4227 if(!color_d) {
4228 static BOOL warned = FALSE;
4230 if(!warned) {
4231 ERR("No diffuse color in source, but destination has one\n");
4232 warned = TRUE;
4235 *( (DWORD *) dest_ptr) = 0xffffffff;
4236 dest_ptr += sizeof(DWORD);
4238 if(dest_conv) {
4239 *( (DWORD *) dest_conv) = 0xffffffff;
4240 dest_conv += sizeof(DWORD);
4243 else {
4244 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4245 if(dest_conv) {
4246 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4247 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4248 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4249 dest_conv += sizeof(DWORD);
4254 if (DestFVF & WINED3DFVF_SPECULAR) {
4255 /* What's the color value in the feedback buffer? */
4256 DWORD *color_s =
4257 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4258 if(!color_s) {
4259 static BOOL warned = FALSE;
4261 if(!warned) {
4262 ERR("No specular color in source, but destination has one\n");
4263 warned = TRUE;
4266 *( (DWORD *) dest_ptr) = 0xFF000000;
4267 dest_ptr += sizeof(DWORD);
4269 if(dest_conv) {
4270 *( (DWORD *) dest_conv) = 0xFF000000;
4271 dest_conv += sizeof(DWORD);
4274 else {
4275 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4276 if(dest_conv) {
4277 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4278 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4279 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4280 dest_conv += sizeof(DWORD);
4285 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4286 float *tex_coord =
4287 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4288 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4289 if(!tex_coord) {
4290 ERR("No source texture, but destination requests one\n");
4291 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4292 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4294 else {
4295 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4296 if(dest_conv) {
4297 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4303 if(dest_conv) {
4304 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4305 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4306 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4307 dwCount * get_flexible_vertex_size(DestFVF),
4308 dest_conv_addr));
4309 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4310 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4313 LEAVE_GL();
4315 return WINED3D_OK;
4317 #undef copy_and_next
4319 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4321 WineDirect3DVertexStridedData strided;
4322 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4323 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4325 if(pVertexDecl) {
4326 ERR("Output vertex declaration not implemented yet\n");
4329 /* Need any context to write to the vbo. */
4330 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4332 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4333 * control the streamIsUP flag, thus restore it afterwards.
4335 This->stateBlock->streamIsUP = FALSE;
4336 memset(&strided, 0, sizeof(strided));
4337 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4338 This->stateBlock->streamIsUP = streamWasUP;
4340 if(vbo || SrcStartIndex) {
4341 unsigned int i;
4342 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4343 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4345 * Also get the start index in, but only loop over all elements if there's something to add at all.
4347 #define FIXSRC(type) \
4348 if(strided.u.s.type.VBO) { \
4349 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4350 strided.u.s.type.VBO = 0; \
4351 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4352 ENTER_GL(); \
4353 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4354 vb->vbo = 0; \
4355 LEAVE_GL(); \
4357 if(strided.u.s.type.lpData) { \
4358 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4360 FIXSRC(position);
4361 FIXSRC(blendWeights);
4362 FIXSRC(blendMatrixIndices);
4363 FIXSRC(normal);
4364 FIXSRC(pSize);
4365 FIXSRC(diffuse);
4366 FIXSRC(specular);
4367 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4368 FIXSRC(texCoords[i]);
4370 FIXSRC(position2);
4371 FIXSRC(normal2);
4372 FIXSRC(tangent);
4373 FIXSRC(binormal);
4374 FIXSRC(tessFactor);
4375 FIXSRC(fog);
4376 FIXSRC(depth);
4377 FIXSRC(sample);
4378 #undef FIXSRC
4381 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4384 /*****
4385 * Get / Set Texture Stage States
4386 * TODO: Verify against dx9 definitions
4387 *****/
4388 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4390 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4392 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4394 if (Stage >= MAX_TEXTURES) {
4395 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4396 return WINED3D_OK;
4399 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4400 This->updateStateBlock->textureState[Stage][Type] = Value;
4402 if (This->isRecordingState) {
4403 TRACE("Recording... not performing anything\n");
4404 return WINED3D_OK;
4407 /* Checked after the assignments to allow proper stateblock recording */
4408 if(oldValue == Value) {
4409 TRACE("App is setting the old value over, nothing to do\n");
4410 return WINED3D_OK;
4413 if(Stage > This->stateBlock->lowest_disabled_stage &&
4414 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4415 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4416 * Changes in other states are important on disabled stages too
4418 return WINED3D_OK;
4421 if(Type == WINED3DTSS_COLOROP) {
4422 int i;
4424 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4425 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4426 * they have to be disabled
4428 * The current stage is dirtified below.
4430 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4431 TRACE("Additionally dirtifying stage %d\n", i);
4432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4434 This->stateBlock->lowest_disabled_stage = Stage;
4435 TRACE("New lowest disabled: %d\n", Stage);
4436 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4437 /* Previously disabled stage enabled. Stages above it may need enabling
4438 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4439 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4441 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4444 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4445 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4446 break;
4448 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4451 This->stateBlock->lowest_disabled_stage = i;
4452 TRACE("New lowest disabled: %d\n", i);
4454 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4455 /* TODO: Built a stage -> texture unit mapping for register combiners */
4459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4461 return WINED3D_OK;
4464 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4466 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4467 *pValue = This->updateStateBlock->textureState[Stage][Type];
4468 return WINED3D_OK;
4471 /*****
4472 * Get / Set Texture
4473 *****/
4474 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4476 IWineD3DBaseTexture *oldTexture;
4478 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4480 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4481 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4484 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4485 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4486 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4489 oldTexture = This->updateStateBlock->textures[Stage];
4491 if(pTexture != NULL) {
4492 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4494 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4495 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4496 return WINED3DERR_INVALIDCALL;
4498 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4501 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4502 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4504 This->updateStateBlock->changed.textures[Stage] = TRUE;
4505 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4506 This->updateStateBlock->textures[Stage] = pTexture;
4508 /* Handle recording of state blocks */
4509 if (This->isRecordingState) {
4510 TRACE("Recording... not performing anything\n");
4511 return WINED3D_OK;
4514 if(oldTexture == pTexture) {
4515 TRACE("App is setting the same texture again, nothing to do\n");
4516 return WINED3D_OK;
4519 /** NOTE: MSDN says that setTexture increases the reference count,
4520 * and that the application must set the texture back to null (or have a leaky application),
4521 * This means we should pass the refcount up to the parent
4522 *******************************/
4523 if (NULL != This->updateStateBlock->textures[Stage]) {
4524 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4525 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4527 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4528 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4529 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4530 * so the COLOROP and ALPHAOP have to be dirtified.
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4535 if(bindCount == 1) {
4536 new->baseTexture.sampler = Stage;
4538 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4542 if (NULL != oldTexture) {
4543 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4544 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4546 IWineD3DBaseTexture_Release(oldTexture);
4547 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4552 if(bindCount && old->baseTexture.sampler == Stage) {
4553 int i;
4554 /* Have to do a search for the other sampler(s) where the texture is bound to
4555 * Shouldn't happen as long as apps bind a texture only to one stage
4557 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4558 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4559 if(This->updateStateBlock->textures[i] == oldTexture) {
4560 old->baseTexture.sampler = i;
4561 break;
4567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4569 return WINED3D_OK;
4572 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4575 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4577 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4578 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4581 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4582 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4583 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4586 *ppTexture=This->stateBlock->textures[Stage];
4587 if (*ppTexture)
4588 IWineD3DBaseTexture_AddRef(*ppTexture);
4590 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4592 return WINED3D_OK;
4595 /*****
4596 * Get Back Buffer
4597 *****/
4598 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4599 IWineD3DSurface **ppBackBuffer) {
4600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4601 IWineD3DSwapChain *swapChain;
4602 HRESULT hr;
4604 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4606 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4607 if (hr == WINED3D_OK) {
4608 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4609 IWineD3DSwapChain_Release(swapChain);
4610 } else {
4611 *ppBackBuffer = NULL;
4613 return hr;
4616 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4618 WARN("(%p) : stub, calling idirect3d for now\n", This);
4619 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4622 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4624 IWineD3DSwapChain *swapChain;
4625 HRESULT hr;
4627 if(iSwapChain > 0) {
4628 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4629 if (hr == WINED3D_OK) {
4630 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4631 IWineD3DSwapChain_Release(swapChain);
4632 } else {
4633 FIXME("(%p) Error getting display mode\n", This);
4635 } else {
4636 /* Don't read the real display mode,
4637 but return the stored mode instead. X11 can't change the color
4638 depth, and some apps are pretty angry if they SetDisplayMode from
4639 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4641 Also don't relay to the swapchain because with ddraw it's possible
4642 that there isn't a swapchain at all */
4643 pMode->Width = This->ddraw_width;
4644 pMode->Height = This->ddraw_height;
4645 pMode->Format = This->ddraw_format;
4646 pMode->RefreshRate = 0;
4647 hr = WINED3D_OK;
4650 return hr;
4653 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 TRACE("(%p)->(%p)\n", This, hWnd);
4657 if(This->ddraw_fullscreen) {
4658 if(This->ddraw_window && This->ddraw_window != hWnd) {
4659 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4661 if(hWnd && This->ddraw_window != hWnd) {
4662 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4666 This->ddraw_window = hWnd;
4667 return WINED3D_OK;
4670 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 TRACE("(%p)->(%p)\n", This, hWnd);
4674 *hWnd = This->ddraw_window;
4675 return WINED3D_OK;
4678 /*****
4679 * Stateblock related functions
4680 *****/
4682 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4684 IWineD3DStateBlockImpl *object;
4685 HRESULT temp_result;
4686 int i;
4688 TRACE("(%p)\n", This);
4690 if (This->isRecordingState) {
4691 return WINED3DERR_INVALIDCALL;
4694 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4695 if (NULL == object ) {
4696 FIXME("(%p)Error allocating memory for stateblock\n", This);
4697 return E_OUTOFMEMORY;
4699 TRACE("(%p) created object %p\n", This, object);
4700 object->wineD3DDevice= This;
4701 /** FIXME: object->parent = parent; **/
4702 object->parent = NULL;
4703 object->blockType = WINED3DSBT_RECORDED;
4704 object->ref = 1;
4705 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4707 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4708 list_init(&object->lightMap[i]);
4711 temp_result = allocate_shader_constants(object);
4712 if (WINED3D_OK != temp_result)
4713 return temp_result;
4715 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4716 This->updateStateBlock = object;
4717 This->isRecordingState = TRUE;
4719 TRACE("(%p) recording stateblock %p\n",This , object);
4720 return WINED3D_OK;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 unsigned int i, j;
4726 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4728 if (!This->isRecordingState) {
4729 FIXME("(%p) not recording! returning error\n", This);
4730 *ppStateBlock = NULL;
4731 return WINED3DERR_INVALIDCALL;
4734 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4735 if(object->changed.renderState[i]) {
4736 object->contained_render_states[object->num_contained_render_states] = i;
4737 object->num_contained_render_states++;
4740 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4741 if(object->changed.transform[i]) {
4742 object->contained_transform_states[object->num_contained_transform_states] = i;
4743 object->num_contained_transform_states++;
4746 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4747 if(object->changed.vertexShaderConstantsF[i]) {
4748 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4749 object->num_contained_vs_consts_f++;
4752 for(i = 0; i < MAX_CONST_I; i++) {
4753 if(object->changed.vertexShaderConstantsI[i]) {
4754 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4755 object->num_contained_vs_consts_i++;
4758 for(i = 0; i < MAX_CONST_B; i++) {
4759 if(object->changed.vertexShaderConstantsB[i]) {
4760 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4761 object->num_contained_vs_consts_b++;
4764 for(i = 0; i < MAX_CONST_I; i++) {
4765 if(object->changed.pixelShaderConstantsI[i]) {
4766 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4767 object->num_contained_ps_consts_i++;
4770 for(i = 0; i < MAX_CONST_B; i++) {
4771 if(object->changed.pixelShaderConstantsB[i]) {
4772 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4773 object->num_contained_ps_consts_b++;
4776 for(i = 0; i < MAX_TEXTURES; i++) {
4777 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4778 if(object->changed.textureState[i][j]) {
4779 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4780 object->contained_tss_states[object->num_contained_tss_states].state = j;
4781 object->num_contained_tss_states++;
4785 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4786 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4787 if(object->changed.samplerState[i][j]) {
4788 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4789 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4790 object->num_contained_sampler_states++;
4795 *ppStateBlock = (IWineD3DStateBlock*) object;
4796 This->isRecordingState = FALSE;
4797 This->updateStateBlock = This->stateBlock;
4798 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4799 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4800 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4801 return WINED3D_OK;
4804 /*****
4805 * Scene related functions
4806 *****/
4807 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4808 /* At the moment we have no need for any functionality at the beginning
4809 of a scene */
4810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4811 TRACE("(%p)\n", This);
4813 if(This->inScene) {
4814 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4815 return WINED3DERR_INVALIDCALL;
4817 This->inScene = TRUE;
4818 return WINED3D_OK;
4821 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4823 TRACE("(%p)\n", This);
4825 if(!This->inScene) {
4826 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4827 return WINED3DERR_INVALIDCALL;
4830 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4831 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4832 ENTER_GL();
4833 glFlush();
4834 checkGLcall("glFlush");
4835 LEAVE_GL();
4837 This->inScene = FALSE;
4838 return WINED3D_OK;
4841 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4842 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4843 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4845 IWineD3DSwapChain *swapChain = NULL;
4846 int i;
4847 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4849 TRACE("(%p) Presenting the frame\n", This);
4851 for(i = 0 ; i < swapchains ; i ++) {
4853 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4854 TRACE("presentinng chain %d, %p\n", i, swapChain);
4855 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4856 IWineD3DSwapChain_Release(swapChain);
4859 return WINED3D_OK;
4862 /* Not called from the VTable (internal subroutine) */
4863 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4864 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4865 float Z, DWORD Stencil) {
4866 GLbitfield glMask = 0;
4867 unsigned int i;
4868 WINED3DRECT curRect;
4869 RECT vp_rect;
4870 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4871 UINT drawable_width, drawable_height;
4872 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4874 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4875 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4876 * for the cleared parts, and the untouched parts.
4878 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4879 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4880 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4881 * checking all this if the dest surface is in the drawable anyway.
4883 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4884 while(1) {
4885 if(vp->X != 0 || vp->Y != 0 ||
4886 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4887 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4888 break;
4890 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4891 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4892 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4893 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4894 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4895 break;
4897 if(Count > 0 && pRects && (
4898 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4899 pRects[0].x2 < target->currentDesc.Width ||
4900 pRects[0].y2 < target->currentDesc.Height)) {
4901 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4902 break;
4904 break;
4908 target->get_drawable_size(target, &drawable_width, &drawable_height);
4910 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4911 ENTER_GL();
4913 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4914 apply_fbo_state((IWineD3DDevice *) This);
4917 /* Only set the values up once, as they are not changing */
4918 if (Flags & WINED3DCLEAR_STENCIL) {
4919 glClearStencil(Stencil);
4920 checkGLcall("glClearStencil");
4921 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4922 glStencilMask(0xFFFFFFFF);
4925 if (Flags & WINED3DCLEAR_ZBUFFER) {
4926 glDepthMask(GL_TRUE);
4927 glClearDepth(Z);
4928 checkGLcall("glClearDepth");
4929 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4932 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4933 if(vp->X != 0 || vp->Y != 0 ||
4934 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4935 depth_copy((IWineD3DDevice *) This);
4937 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4938 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4939 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4940 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4941 depth_copy((IWineD3DDevice *) This);
4943 else if(Count > 0 && pRects && (
4944 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4945 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4946 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4947 depth_copy((IWineD3DDevice *) This);
4950 This->depth_copy_state = WINED3D_DCS_INITIAL;
4953 if (Flags & WINED3DCLEAR_TARGET) {
4954 TRACE("Clearing screen with glClear to color %x\n", Color);
4955 glClearColor(D3DCOLOR_R(Color),
4956 D3DCOLOR_G(Color),
4957 D3DCOLOR_B(Color),
4958 D3DCOLOR_A(Color));
4959 checkGLcall("glClearColor");
4961 /* Clear ALL colors! */
4962 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4963 glMask = glMask | GL_COLOR_BUFFER_BIT;
4966 vp_rect.left = vp->X;
4967 vp_rect.top = vp->Y;
4968 vp_rect.right = vp->X + vp->Width;
4969 vp_rect.bottom = vp->Y + vp->Height;
4970 if (!(Count > 0 && pRects)) {
4971 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4972 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4974 if(This->render_offscreen) {
4975 glScissor(vp_rect.left, vp_rect.top,
4976 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4977 } else {
4978 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4979 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4981 checkGLcall("glScissor");
4982 glClear(glMask);
4983 checkGLcall("glClear");
4984 } else {
4985 /* Now process each rect in turn */
4986 for (i = 0; i < Count; i++) {
4987 /* Note gl uses lower left, width/height */
4988 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4989 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4990 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4992 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4993 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4994 curRect.x1, (target->currentDesc.Height - curRect.y2),
4995 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4997 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4998 * The rectangle is not cleared, no error is returned, but further rectanlges are
4999 * still cleared if they are valid
5001 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5002 TRACE("Rectangle with negative dimensions, ignoring\n");
5003 continue;
5006 if(This->render_offscreen) {
5007 glScissor(curRect.x1, curRect.y1,
5008 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5009 } else {
5010 glScissor(curRect.x1, drawable_height - curRect.y2,
5011 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5013 checkGLcall("glScissor");
5015 glClear(glMask);
5016 checkGLcall("glClear");
5020 /* Restore the old values (why..?) */
5021 if (Flags & WINED3DCLEAR_STENCIL) {
5022 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5024 if (Flags & WINED3DCLEAR_TARGET) {
5025 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5026 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5027 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5028 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5029 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5031 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5032 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5034 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5035 /* TODO: Move the fbo logic into ModifyLocation() */
5036 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5037 target->Flags |= SFLAG_INTEXTURE;
5040 LEAVE_GL();
5042 return WINED3D_OK;
5045 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5046 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5048 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5050 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5051 Count, pRects, Flags, Color, Z, Stencil);
5053 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5054 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5055 /* TODO: What about depth stencil buffers without stencil bits? */
5056 return WINED3DERR_INVALIDCALL;
5059 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5062 /*****
5063 * Drawing functions
5064 *****/
5065 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5066 UINT PrimitiveCount) {
5068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5070 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5071 debug_d3dprimitivetype(PrimitiveType),
5072 StartVertex, PrimitiveCount);
5074 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5075 if(This->stateBlock->streamIsUP) {
5076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5077 This->stateBlock->streamIsUP = FALSE;
5080 if(This->stateBlock->loadBaseVertexIndex != 0) {
5081 This->stateBlock->loadBaseVertexIndex = 0;
5082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5084 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5085 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5086 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5087 return WINED3D_OK;
5090 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5091 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5092 WINED3DPRIMITIVETYPE PrimitiveType,
5093 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5096 UINT idxStride = 2;
5097 IWineD3DIndexBuffer *pIB;
5098 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5099 GLuint vbo;
5101 pIB = This->stateBlock->pIndexData;
5102 if (!pIB) {
5103 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5104 * without an index buffer set. (The first time at least...)
5105 * D3D8 simply dies, but I doubt it can do much harm to return
5106 * D3DERR_INVALIDCALL there as well. */
5107 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5108 return WINED3DERR_INVALIDCALL;
5111 if(This->stateBlock->streamIsUP) {
5112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5113 This->stateBlock->streamIsUP = FALSE;
5115 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5117 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5118 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5119 minIndex, NumVertices, startIndex, primCount);
5121 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5122 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5123 idxStride = 2;
5124 } else {
5125 idxStride = 4;
5128 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5129 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5133 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5134 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5136 return WINED3D_OK;
5139 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5140 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5141 UINT VertexStreamZeroStride) {
5142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5143 IWineD3DVertexBuffer *vb;
5145 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5146 debug_d3dprimitivetype(PrimitiveType),
5147 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5149 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5150 vb = This->stateBlock->streamSource[0];
5151 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5152 if(vb) IWineD3DVertexBuffer_Release(vb);
5153 This->stateBlock->streamOffset[0] = 0;
5154 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5155 This->stateBlock->streamIsUP = TRUE;
5156 This->stateBlock->loadBaseVertexIndex = 0;
5158 /* TODO: Only mark dirty if drawing from a different UP address */
5159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5161 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5162 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5164 /* MSDN specifies stream zero settings must be set to NULL */
5165 This->stateBlock->streamStride[0] = 0;
5166 This->stateBlock->streamSource[0] = NULL;
5168 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5169 * the new stream sources or use UP drawing again
5171 return WINED3D_OK;
5174 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5175 UINT MinVertexIndex, UINT NumVertices,
5176 UINT PrimitiveCount, CONST void* pIndexData,
5177 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5178 UINT VertexStreamZeroStride) {
5179 int idxStride;
5180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5181 IWineD3DVertexBuffer *vb;
5182 IWineD3DIndexBuffer *ib;
5184 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5185 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5186 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5187 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5189 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5190 idxStride = 2;
5191 } else {
5192 idxStride = 4;
5195 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5196 vb = This->stateBlock->streamSource[0];
5197 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5198 if(vb) IWineD3DVertexBuffer_Release(vb);
5199 This->stateBlock->streamIsUP = TRUE;
5200 This->stateBlock->streamOffset[0] = 0;
5201 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5203 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5204 This->stateBlock->baseVertexIndex = 0;
5205 This->stateBlock->loadBaseVertexIndex = 0;
5206 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5207 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5210 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5212 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5213 This->stateBlock->streamSource[0] = NULL;
5214 This->stateBlock->streamStride[0] = 0;
5215 ib = This->stateBlock->pIndexData;
5216 if(ib) {
5217 IWineD3DIndexBuffer_Release(ib);
5218 This->stateBlock->pIndexData = NULL;
5220 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5221 * SetStreamSource to specify a vertex buffer
5224 return WINED3D_OK;
5227 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5228 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5230 /* Mark the state dirty until we have nicer tracking
5231 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5232 * that value.
5234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5236 This->stateBlock->baseVertexIndex = 0;
5237 This->up_strided = DrawPrimStrideData;
5238 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5239 This->up_strided = NULL;
5240 return WINED3D_OK;
5243 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5245 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5247 /* Mark the state dirty until we have nicer tracking
5248 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5249 * that value.
5251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5253 This->stateBlock->streamIsUP = TRUE;
5254 This->stateBlock->baseVertexIndex = 0;
5255 This->up_strided = DrawPrimStrideData;
5256 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5257 This->up_strided = NULL;
5258 return WINED3D_OK;
5261 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5262 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5263 * not callable by the app directly no parameter validation checks are needed here.
5265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5266 WINED3DLOCKED_BOX src;
5267 WINED3DLOCKED_BOX dst;
5268 HRESULT hr;
5269 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5271 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5272 * dirtification to improve loading performance.
5274 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5275 if(FAILED(hr)) return hr;
5276 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5277 if(FAILED(hr)) {
5278 IWineD3DVolume_UnlockBox(pSourceVolume);
5279 return hr;
5282 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5284 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5285 if(FAILED(hr)) {
5286 IWineD3DVolume_UnlockBox(pSourceVolume);
5287 } else {
5288 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5290 return hr;
5293 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5294 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5296 HRESULT hr = WINED3D_OK;
5297 WINED3DRESOURCETYPE sourceType;
5298 WINED3DRESOURCETYPE destinationType;
5299 int i ,levels;
5301 /* TODO: think about moving the code into IWineD3DBaseTexture */
5303 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5305 /* verify that the source and destination textures aren't NULL */
5306 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5307 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5308 This, pSourceTexture, pDestinationTexture);
5309 hr = WINED3DERR_INVALIDCALL;
5312 if (pSourceTexture == pDestinationTexture) {
5313 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5314 This, pSourceTexture, pDestinationTexture);
5315 hr = WINED3DERR_INVALIDCALL;
5317 /* Verify that the source and destination textures are the same type */
5318 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5319 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5321 if (sourceType != destinationType) {
5322 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5323 This);
5324 hr = WINED3DERR_INVALIDCALL;
5327 /* check that both textures have the identical numbers of levels */
5328 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5329 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5330 hr = WINED3DERR_INVALIDCALL;
5333 if (WINED3D_OK == hr) {
5335 /* Make sure that the destination texture is loaded */
5336 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5338 /* Update every surface level of the texture */
5339 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5341 switch (sourceType) {
5342 case WINED3DRTYPE_TEXTURE:
5344 IWineD3DSurface *srcSurface;
5345 IWineD3DSurface *destSurface;
5347 for (i = 0 ; i < levels ; ++i) {
5348 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5349 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5350 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5351 IWineD3DSurface_Release(srcSurface);
5352 IWineD3DSurface_Release(destSurface);
5353 if (WINED3D_OK != hr) {
5354 WARN("(%p) : Call to update surface failed\n", This);
5355 return hr;
5359 break;
5360 case WINED3DRTYPE_CUBETEXTURE:
5362 IWineD3DSurface *srcSurface;
5363 IWineD3DSurface *destSurface;
5364 WINED3DCUBEMAP_FACES faceType;
5366 for (i = 0 ; i < levels ; ++i) {
5367 /* Update each cube face */
5368 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5369 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5370 if (WINED3D_OK != hr) {
5371 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5372 } else {
5373 TRACE("Got srcSurface %p\n", srcSurface);
5375 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5376 if (WINED3D_OK != hr) {
5377 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5378 } else {
5379 TRACE("Got desrSurface %p\n", destSurface);
5381 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5382 IWineD3DSurface_Release(srcSurface);
5383 IWineD3DSurface_Release(destSurface);
5384 if (WINED3D_OK != hr) {
5385 WARN("(%p) : Call to update surface failed\n", This);
5386 return hr;
5391 break;
5393 case WINED3DRTYPE_VOLUMETEXTURE:
5395 IWineD3DVolume *srcVolume = NULL;
5396 IWineD3DVolume *destVolume = NULL;
5398 for (i = 0 ; i < levels ; ++i) {
5399 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5400 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5401 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5402 IWineD3DVolume_Release(srcVolume);
5403 IWineD3DVolume_Release(destVolume);
5404 if (WINED3D_OK != hr) {
5405 WARN("(%p) : Call to update volume failed\n", This);
5406 return hr;
5410 break;
5412 default:
5413 FIXME("(%p) : Unsupported source and destination type\n", This);
5414 hr = WINED3DERR_INVALIDCALL;
5418 return hr;
5421 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5422 IWineD3DSwapChain *swapChain;
5423 HRESULT hr;
5424 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5425 if(hr == WINED3D_OK) {
5426 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5427 IWineD3DSwapChain_Release(swapChain);
5429 return hr;
5432 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5434 /* return a sensible default */
5435 *pNumPasses = 1;
5436 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5437 FIXME("(%p) : stub\n", This);
5438 return WINED3D_OK;
5441 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5443 int j;
5444 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5445 if (PaletteNumber >= MAX_PALETTES) {
5446 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5447 return WINED3DERR_INVALIDCALL;
5449 for (j = 0; j < 256; ++j) {
5450 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5451 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5452 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5453 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5455 TRACE("(%p) : returning\n", This);
5456 return WINED3D_OK;
5459 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5461 int j;
5462 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5463 if (PaletteNumber >= MAX_PALETTES) {
5464 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5465 return WINED3DERR_INVALIDCALL;
5467 for (j = 0; j < 256; ++j) {
5468 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5469 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5470 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5471 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5473 TRACE("(%p) : returning\n", This);
5474 return WINED3D_OK;
5477 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5479 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5480 if (PaletteNumber >= MAX_PALETTES) {
5481 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5482 return WINED3DERR_INVALIDCALL;
5484 /*TODO: stateblocks */
5485 This->currentPalette = PaletteNumber;
5486 TRACE("(%p) : returning\n", This);
5487 return WINED3D_OK;
5490 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5492 if (PaletteNumber == NULL) {
5493 WARN("(%p) : returning Invalid Call\n", This);
5494 return WINED3DERR_INVALIDCALL;
5496 /*TODO: stateblocks */
5497 *PaletteNumber = This->currentPalette;
5498 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5499 return WINED3D_OK;
5502 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5504 static BOOL showFixmes = TRUE;
5505 if (showFixmes) {
5506 FIXME("(%p) : stub\n", This);
5507 showFixmes = FALSE;
5510 This->softwareVertexProcessing = bSoftware;
5511 return WINED3D_OK;
5515 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5517 static BOOL showFixmes = TRUE;
5518 if (showFixmes) {
5519 FIXME("(%p) : stub\n", This);
5520 showFixmes = FALSE;
5522 return This->softwareVertexProcessing;
5526 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5528 IWineD3DSwapChain *swapChain;
5529 HRESULT hr;
5531 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5533 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5534 if(hr == WINED3D_OK){
5535 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5536 IWineD3DSwapChain_Release(swapChain);
5537 }else{
5538 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5540 return hr;
5544 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5546 static BOOL showfixmes = TRUE;
5547 if(nSegments != 0.0f) {
5548 if( showfixmes) {
5549 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5550 showfixmes = FALSE;
5553 return WINED3D_OK;
5556 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5558 static BOOL showfixmes = TRUE;
5559 if( showfixmes) {
5560 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5561 showfixmes = FALSE;
5563 return 0.0f;
5566 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5568 /** TODO: remove casts to IWineD3DSurfaceImpl
5569 * NOTE: move code to surface to accomplish this
5570 ****************************************/
5571 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5572 int srcWidth, srcHeight;
5573 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5574 WINED3DFORMAT destFormat, srcFormat;
5575 UINT destSize;
5576 int srcLeft, destLeft, destTop;
5577 WINED3DPOOL srcPool, destPool;
5578 int offset = 0;
5579 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5580 glDescriptor *glDescription = NULL;
5581 GLenum dummy;
5582 int bpp;
5583 CONVERT_TYPES convert = NO_CONVERSION;
5585 WINED3DSURFACE_DESC winedesc;
5587 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5588 memset(&winedesc, 0, sizeof(winedesc));
5589 winedesc.Width = &srcSurfaceWidth;
5590 winedesc.Height = &srcSurfaceHeight;
5591 winedesc.Pool = &srcPool;
5592 winedesc.Format = &srcFormat;
5594 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5596 winedesc.Width = &destSurfaceWidth;
5597 winedesc.Height = &destSurfaceHeight;
5598 winedesc.Pool = &destPool;
5599 winedesc.Format = &destFormat;
5600 winedesc.Size = &destSize;
5602 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5604 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5605 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5606 return WINED3DERR_INVALIDCALL;
5609 /* This call loads the opengl surface directly, instead of copying the surface to the
5610 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5611 * copy in sysmem and use regular surface loading.
5613 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5614 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5615 if(convert != NO_CONVERSION) {
5616 return IWineD3DSurface_BltFast(pDestinationSurface,
5617 pDestPoint ? pDestPoint->x : 0,
5618 pDestPoint ? pDestPoint->y : 0,
5619 pSourceSurface, (RECT *) pSourceRect, 0);
5622 if (destFormat == WINED3DFMT_UNKNOWN) {
5623 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5624 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5626 /* Get the update surface description */
5627 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5630 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5632 ENTER_GL();
5634 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5635 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5636 checkGLcall("glActiveTextureARB");
5639 /* Make sure the surface is loaded and up to date */
5640 IWineD3DSurface_PreLoad(pDestinationSurface);
5642 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5644 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5645 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5646 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5647 srcLeft = pSourceRect ? pSourceRect->left : 0;
5648 destLeft = pDestPoint ? pDestPoint->x : 0;
5649 destTop = pDestPoint ? pDestPoint->y : 0;
5652 /* This function doesn't support compressed textures
5653 the pitch is just bytesPerPixel * width */
5654 if(srcWidth != srcSurfaceWidth || srcLeft ){
5655 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5656 offset += srcLeft * pSrcSurface->bytesPerPixel;
5657 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5659 /* TODO DXT formats */
5661 if(pSourceRect != NULL && pSourceRect->top != 0){
5662 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5664 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5665 ,This
5666 ,glDescription->level
5667 ,destLeft
5668 ,destTop
5669 ,srcWidth
5670 ,srcHeight
5671 ,glDescription->glFormat
5672 ,glDescription->glType
5673 ,IWineD3DSurface_GetData(pSourceSurface)
5676 /* Sanity check */
5677 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5679 /* need to lock the surface to get the data */
5680 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5683 /* TODO: Cube and volume support */
5684 if(rowoffset != 0){
5685 /* not a whole row so we have to do it a line at a time */
5686 int j;
5688 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5689 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5691 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5693 glTexSubImage2D(glDescription->target
5694 ,glDescription->level
5695 ,destLeft
5697 ,srcWidth
5699 ,glDescription->glFormat
5700 ,glDescription->glType
5701 ,data /* could be quicker using */
5703 data += rowoffset;
5706 } else { /* Full width, so just write out the whole texture */
5708 if (WINED3DFMT_DXT1 == destFormat ||
5709 WINED3DFMT_DXT2 == destFormat ||
5710 WINED3DFMT_DXT3 == destFormat ||
5711 WINED3DFMT_DXT4 == destFormat ||
5712 WINED3DFMT_DXT5 == destFormat) {
5713 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5714 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5715 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5716 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5717 } if (destFormat != srcFormat) {
5718 FIXME("Updating mixed format compressed texture is not curretly support\n");
5719 } else {
5720 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5721 glDescription->level,
5722 glDescription->glFormatInternal,
5723 srcWidth,
5724 srcHeight,
5726 destSize,
5727 IWineD3DSurface_GetData(pSourceSurface));
5729 } else {
5730 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5734 } else {
5735 glTexSubImage2D(glDescription->target
5736 ,glDescription->level
5737 ,destLeft
5738 ,destTop
5739 ,srcWidth
5740 ,srcHeight
5741 ,glDescription->glFormat
5742 ,glDescription->glType
5743 ,IWineD3DSurface_GetData(pSourceSurface)
5747 checkGLcall("glTexSubImage2D");
5749 LEAVE_GL();
5751 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5754 return WINED3D_OK;
5757 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5759 struct WineD3DRectPatch *patch;
5760 unsigned int i;
5761 struct list *e;
5762 BOOL found;
5763 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5765 if(!(Handle || pRectPatchInfo)) {
5766 /* TODO: Write a test for the return value, thus the FIXME */
5767 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5768 return WINED3DERR_INVALIDCALL;
5771 if(Handle) {
5772 i = PATCHMAP_HASHFUNC(Handle);
5773 found = FALSE;
5774 LIST_FOR_EACH(e, &This->patches[i]) {
5775 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5776 if(patch->Handle == Handle) {
5777 found = TRUE;
5778 break;
5782 if(!found) {
5783 TRACE("Patch does not exist. Creating a new one\n");
5784 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5785 patch->Handle = Handle;
5786 list_add_head(&This->patches[i], &patch->entry);
5787 } else {
5788 TRACE("Found existing patch %p\n", patch);
5790 } else {
5791 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5792 * attributes we have to tesselate, read back, and draw. This needs a patch
5793 * management structure instance. Create one.
5795 * A possible improvement is to check if a vertex shader is used, and if not directly
5796 * draw the patch.
5798 FIXME("Drawing an uncached patch. This is slow\n");
5799 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5802 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5803 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5804 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5805 HRESULT hr;
5806 TRACE("Tesselation density or patch info changed, retesselating\n");
5808 if(pRectPatchInfo) {
5809 patch->RectPatchInfo = *pRectPatchInfo;
5811 patch->numSegs[0] = pNumSegs[0];
5812 patch->numSegs[1] = pNumSegs[1];
5813 patch->numSegs[2] = pNumSegs[2];
5814 patch->numSegs[3] = pNumSegs[3];
5816 hr = tesselate_rectpatch(This, patch);
5817 if(FAILED(hr)) {
5818 WARN("Patch tesselation failed\n");
5820 /* Do not release the handle to store the params of the patch */
5821 if(!Handle) {
5822 HeapFree(GetProcessHeap(), 0, patch);
5824 return hr;
5828 This->currentPatch = patch;
5829 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5830 This->currentPatch = NULL;
5832 /* Destroy uncached patches */
5833 if(!Handle) {
5834 HeapFree(GetProcessHeap(), 0, patch->mem);
5835 HeapFree(GetProcessHeap(), 0, patch);
5837 return WINED3D_OK;
5840 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5842 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5843 FIXME("(%p) : Stub\n", This);
5844 return WINED3D_OK;
5847 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5849 int i;
5850 struct WineD3DRectPatch *patch;
5851 struct list *e;
5852 TRACE("(%p) Handle(%d)\n", This, Handle);
5854 i = PATCHMAP_HASHFUNC(Handle);
5855 LIST_FOR_EACH(e, &This->patches[i]) {
5856 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5857 if(patch->Handle == Handle) {
5858 TRACE("Deleting patch %p\n", patch);
5859 list_remove(&patch->entry);
5860 HeapFree(GetProcessHeap(), 0, patch->mem);
5861 HeapFree(GetProcessHeap(), 0, patch);
5862 return WINED3D_OK;
5866 /* TODO: Write a test for the return value */
5867 FIXME("Attempt to destroy nonexistent patch\n");
5868 return WINED3DERR_INVALIDCALL;
5871 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5872 HRESULT hr;
5873 IWineD3DSwapChain *swapchain;
5875 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5876 if (SUCCEEDED(hr)) {
5877 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5878 return swapchain;
5881 return NULL;
5884 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5887 if (!*fbo) {
5888 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5889 checkGLcall("glGenFramebuffersEXT()");
5891 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5892 checkGLcall("glBindFramebuffer()");
5895 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5896 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5897 IWineD3DBaseTextureImpl *texture_impl;
5898 GLenum texttarget, target;
5899 GLint old_binding;
5901 texttarget = surface_impl->glDescription.target;
5902 if(texttarget == GL_TEXTURE_2D) {
5903 target = GL_TEXTURE_2D;
5904 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5905 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5906 target = GL_TEXTURE_RECTANGLE_ARB;
5907 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5908 } else {
5909 target = GL_TEXTURE_CUBE_MAP_ARB;
5910 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5913 IWineD3DSurface_PreLoad(surface);
5915 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5916 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5917 glBindTexture(target, old_binding);
5919 /* Update base texture states array */
5920 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5921 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5922 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5923 if (texture_impl->baseTexture.bindCount) {
5924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5927 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5930 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5931 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5933 checkGLcall("attach_surface_fbo");
5936 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5938 IWineD3DSwapChain *swapchain;
5940 swapchain = get_swapchain(surface);
5941 if (swapchain) {
5942 GLenum buffer;
5944 TRACE("Surface %p is onscreen\n", surface);
5946 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5947 buffer = surface_get_gl_buffer(surface, swapchain);
5948 glDrawBuffer(buffer);
5949 checkGLcall("glDrawBuffer()");
5950 } else {
5951 TRACE("Surface %p is offscreen\n", surface);
5952 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5953 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5956 if (rect) {
5957 glEnable(GL_SCISSOR_TEST);
5958 if(!swapchain) {
5959 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5960 } else {
5961 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5962 rect->x2 - rect->x1, rect->y2 - rect->y1);
5964 checkGLcall("glScissor");
5965 } else {
5966 glDisable(GL_SCISSOR_TEST);
5968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5970 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5973 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5974 glClear(GL_COLOR_BUFFER_BIT);
5975 checkGLcall("glClear");
5977 if (This->render_offscreen) {
5978 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5979 } else {
5980 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5981 checkGLcall("glBindFramebuffer()");
5984 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5985 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5986 glDrawBuffer(GL_BACK);
5987 checkGLcall("glDrawBuffer()");
5991 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5992 unsigned int r, g, b, a;
5993 DWORD ret;
5995 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5996 destfmt == WINED3DFMT_R8G8B8)
5997 return color;
5999 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6001 a = (color & 0xff000000) >> 24;
6002 r = (color & 0x00ff0000) >> 16;
6003 g = (color & 0x0000ff00) >> 8;
6004 b = (color & 0x000000ff) >> 0;
6006 switch(destfmt)
6008 case WINED3DFMT_R5G6B5:
6009 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6010 r = (r * 32) / 256;
6011 g = (g * 64) / 256;
6012 b = (b * 32) / 256;
6013 ret = r << 11;
6014 ret |= g << 5;
6015 ret |= b;
6016 TRACE("Returning %08x\n", ret);
6017 return ret;
6019 case WINED3DFMT_X1R5G5B5:
6020 case WINED3DFMT_A1R5G5B5:
6021 a = (a * 2) / 256;
6022 r = (r * 32) / 256;
6023 g = (g * 32) / 256;
6024 b = (b * 32) / 256;
6025 ret = a << 15;
6026 ret |= r << 10;
6027 ret |= g << 5;
6028 ret |= b << 0;
6029 TRACE("Returning %08x\n", ret);
6030 return ret;
6032 case WINED3DFMT_A8:
6033 TRACE("Returning %08x\n", a);
6034 return a;
6036 case WINED3DFMT_X4R4G4B4:
6037 case WINED3DFMT_A4R4G4B4:
6038 a = (a * 16) / 256;
6039 r = (r * 16) / 256;
6040 g = (g * 16) / 256;
6041 b = (b * 16) / 256;
6042 ret = a << 12;
6043 ret |= r << 8;
6044 ret |= g << 4;
6045 ret |= b << 0;
6046 TRACE("Returning %08x\n", ret);
6047 return ret;
6049 case WINED3DFMT_R3G3B2:
6050 r = (r * 8) / 256;
6051 g = (g * 8) / 256;
6052 b = (b * 4) / 256;
6053 ret = r << 5;
6054 ret |= g << 2;
6055 ret |= b << 0;
6056 TRACE("Returning %08x\n", ret);
6057 return ret;
6059 case WINED3DFMT_X8B8G8R8:
6060 case WINED3DFMT_A8B8G8R8:
6061 ret = a << 24;
6062 ret |= b << 16;
6063 ret |= g << 8;
6064 ret |= r << 0;
6065 TRACE("Returning %08x\n", ret);
6066 return ret;
6068 case WINED3DFMT_A2R10G10B10:
6069 a = (a * 4) / 256;
6070 r = (r * 1024) / 256;
6071 g = (g * 1024) / 256;
6072 b = (b * 1024) / 256;
6073 ret = a << 30;
6074 ret |= r << 20;
6075 ret |= g << 10;
6076 ret |= b << 0;
6077 TRACE("Returning %08x\n", ret);
6078 return ret;
6080 case WINED3DFMT_A2B10G10R10:
6081 a = (a * 4) / 256;
6082 r = (r * 1024) / 256;
6083 g = (g * 1024) / 256;
6084 b = (b * 1024) / 256;
6085 ret = a << 30;
6086 ret |= b << 20;
6087 ret |= g << 10;
6088 ret |= r << 0;
6089 TRACE("Returning %08x\n", ret);
6090 return ret;
6092 default:
6093 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6094 return 0;
6098 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6100 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6101 WINEDDBLTFX BltFx;
6102 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6104 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6105 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6106 return WINED3DERR_INVALIDCALL;
6109 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6110 color_fill_fbo(iface, pSurface, pRect, color);
6111 return WINED3D_OK;
6112 } else {
6113 /* Just forward this to the DirectDraw blitting engine */
6114 memset(&BltFx, 0, sizeof(BltFx));
6115 BltFx.dwSize = sizeof(BltFx);
6116 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6117 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6121 /* rendertarget and depth stencil functions */
6122 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6125 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6126 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6127 return WINED3DERR_INVALIDCALL;
6130 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6131 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6132 /* Note inc ref on returned surface */
6133 if(*ppRenderTarget != NULL)
6134 IWineD3DSurface_AddRef(*ppRenderTarget);
6135 return WINED3D_OK;
6138 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6140 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6141 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6142 IWineD3DSwapChainImpl *Swapchain;
6143 HRESULT hr;
6145 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6147 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6148 if(hr != WINED3D_OK) {
6149 ERR("Can't get the swapchain\n");
6150 return hr;
6153 /* Make sure to release the swapchain */
6154 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6156 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6157 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6158 return WINED3DERR_INVALIDCALL;
6160 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6161 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6162 return WINED3DERR_INVALIDCALL;
6165 if(Swapchain->frontBuffer != Front) {
6166 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6168 if(Swapchain->frontBuffer)
6169 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6170 Swapchain->frontBuffer = Front;
6172 if(Swapchain->frontBuffer) {
6173 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6177 if(Back && !Swapchain->backBuffer) {
6178 /* We need memory for the back buffer array - only one back buffer this way */
6179 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6180 if(!Swapchain->backBuffer) {
6181 ERR("Out of memory\n");
6182 return E_OUTOFMEMORY;
6186 if(Swapchain->backBuffer[0] != Back) {
6187 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6189 /* What to do about the context here in the case of multithreading? Not sure.
6190 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6192 ENTER_GL();
6193 if(!Swapchain->backBuffer[0]) {
6194 /* GL was told to draw to the front buffer at creation,
6195 * undo that
6197 glDrawBuffer(GL_BACK);
6198 checkGLcall("glDrawBuffer(GL_BACK)");
6199 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6200 Swapchain->presentParms.BackBufferCount = 1;
6201 } else if (!Back) {
6202 /* That makes problems - disable for now */
6203 /* glDrawBuffer(GL_FRONT); */
6204 checkGLcall("glDrawBuffer(GL_FRONT)");
6205 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6206 Swapchain->presentParms.BackBufferCount = 0;
6208 LEAVE_GL();
6210 if(Swapchain->backBuffer[0])
6211 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6212 Swapchain->backBuffer[0] = Back;
6214 if(Swapchain->backBuffer[0]) {
6215 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6216 } else {
6217 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6218 Swapchain->backBuffer = NULL;
6223 return WINED3D_OK;
6226 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6228 *ppZStencilSurface = This->stencilBufferTarget;
6229 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6231 if(*ppZStencilSurface != NULL) {
6232 /* Note inc ref on returned surface */
6233 IWineD3DSurface_AddRef(*ppZStencilSurface);
6234 return WINED3D_OK;
6235 } else {
6236 return WINED3DERR_NOTFOUND;
6240 /* TODO: Handle stencil attachments */
6241 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6243 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6245 TRACE("Set depth stencil to %p\n", depth_stencil);
6247 if (depth_stencil_impl) {
6248 if (depth_stencil_impl->current_renderbuffer) {
6249 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6250 checkGLcall("glFramebufferRenderbufferEXT()");
6251 } else {
6252 IWineD3DBaseTextureImpl *texture_impl;
6253 GLenum texttarget, target;
6254 GLint old_binding = 0;
6256 texttarget = depth_stencil_impl->glDescription.target;
6257 if(texttarget == GL_TEXTURE_2D) {
6258 target = GL_TEXTURE_2D;
6259 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6260 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6261 target = GL_TEXTURE_RECTANGLE_ARB;
6262 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6263 } else {
6264 target = GL_TEXTURE_CUBE_MAP_ARB;
6265 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6268 IWineD3DSurface_PreLoad(depth_stencil);
6270 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6271 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6272 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6273 glBindTexture(target, old_binding);
6275 /* Update base texture states array */
6276 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6277 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6278 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6279 if (texture_impl->baseTexture.bindCount) {
6280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6283 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6286 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6287 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6288 checkGLcall("glFramebufferTexture2DEXT()");
6290 } else {
6291 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6292 checkGLcall("glFramebufferTexture2DEXT()");
6296 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6298 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6300 TRACE("Set render target %u to %p\n", idx, render_target);
6302 if (rtimpl) {
6303 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6304 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6305 } else {
6306 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6307 checkGLcall("glFramebufferTexture2DEXT()");
6309 This->draw_buffers[idx] = GL_NONE;
6313 static void check_fbo_status(IWineD3DDevice *iface) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6315 GLenum status;
6317 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6318 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6319 TRACE("FBO complete\n");
6320 } else {
6321 IWineD3DSurfaceImpl *attachment;
6322 int i;
6323 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6325 /* Dump the FBO attachments */
6326 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6327 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6328 if (attachment) {
6329 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6330 attachment->pow2Width, attachment->pow2Height);
6333 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6334 if (attachment) {
6335 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6336 attachment->pow2Width, attachment->pow2Height);
6341 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6343 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6344 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6346 if (!ds_impl) return FALSE;
6348 if (ds_impl->current_renderbuffer) {
6349 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6350 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6353 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6354 rt_impl->pow2Height != ds_impl->pow2Height);
6357 void apply_fbo_state(IWineD3DDevice *iface) {
6358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6359 unsigned int i;
6361 if (This->render_offscreen) {
6362 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6364 /* Apply render targets */
6365 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6366 IWineD3DSurface *render_target = This->render_targets[i];
6367 if (This->fbo_color_attachments[i] != render_target) {
6368 set_render_target_fbo(iface, i, render_target);
6369 This->fbo_color_attachments[i] = render_target;
6373 /* Apply depth targets */
6374 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6375 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6376 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6378 if (This->stencilBufferTarget) {
6379 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6381 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6382 This->fbo_depth_attachment = This->stencilBufferTarget;
6385 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6386 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6387 checkGLcall("glDrawBuffers()");
6388 } else {
6389 glDrawBuffer(This->draw_buffers[0]);
6390 checkGLcall("glDrawBuffer()");
6392 } else {
6393 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6396 check_fbo_status(iface);
6399 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6400 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6402 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6403 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6404 GLenum gl_filter;
6406 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6407 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6408 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6409 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6411 switch (filter) {
6412 case WINED3DTEXF_LINEAR:
6413 gl_filter = GL_LINEAR;
6414 break;
6416 default:
6417 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6418 case WINED3DTEXF_NONE:
6419 case WINED3DTEXF_POINT:
6420 gl_filter = GL_NEAREST;
6421 break;
6424 /* Attach src surface to src fbo */
6425 src_swapchain = get_swapchain(src_surface);
6426 if (src_swapchain) {
6427 GLenum buffer;
6429 TRACE("Source surface %p is onscreen\n", src_surface);
6430 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6431 /* Make sure the drawable is up to date. In the offscreen case
6432 * attach_surface_fbo() implicitly takes care of this. */
6433 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6435 ENTER_GL();
6436 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6437 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6438 glReadBuffer(buffer);
6439 checkGLcall("glReadBuffer()");
6441 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6442 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6443 } else {
6444 TRACE("Source surface %p is offscreen\n", src_surface);
6445 ENTER_GL();
6446 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6447 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6448 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6449 checkGLcall("glReadBuffer()");
6451 LEAVE_GL();
6453 /* Attach dst surface to dst fbo */
6454 dst_swapchain = get_swapchain(dst_surface);
6455 if (dst_swapchain) {
6456 GLenum buffer;
6458 TRACE("Destination surface %p is onscreen\n", dst_surface);
6459 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6460 /* Make sure the drawable is up to date. In the offscreen case
6461 * attach_surface_fbo() implicitly takes care of this. */
6462 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6464 ENTER_GL();
6465 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6466 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6467 glDrawBuffer(buffer);
6468 checkGLcall("glDrawBuffer()");
6470 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6471 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6472 } else {
6473 TRACE("Destination surface %p is offscreen\n", dst_surface);
6475 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6476 if(!src_swapchain) {
6477 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6480 ENTER_GL();
6481 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6482 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6483 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6484 checkGLcall("glDrawBuffer()");
6486 glDisable(GL_SCISSOR_TEST);
6487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6489 if (flip) {
6490 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6491 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6492 checkGLcall("glBlitFramebuffer()");
6493 } else {
6494 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6495 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6496 checkGLcall("glBlitFramebuffer()");
6499 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6501 if (This->render_offscreen) {
6502 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6503 } else {
6504 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6505 checkGLcall("glBindFramebuffer()");
6508 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6509 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6510 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6511 glDrawBuffer(GL_BACK);
6512 checkGLcall("glDrawBuffer()");
6514 LEAVE_GL();
6517 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6519 WINED3DVIEWPORT viewport;
6521 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6523 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6524 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6525 This, RenderTargetIndex, GL_LIMITS(buffers));
6526 return WINED3DERR_INVALIDCALL;
6529 /* MSDN says that null disables the render target
6530 but a device must always be associated with a render target
6531 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6533 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6534 FIXME("Trying to set render target 0 to NULL\n");
6535 return WINED3DERR_INVALIDCALL;
6537 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6538 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);
6539 return WINED3DERR_INVALIDCALL;
6542 /* If we are trying to set what we already have, don't bother */
6543 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6544 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6545 return WINED3D_OK;
6547 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6548 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6549 This->render_targets[RenderTargetIndex] = pRenderTarget;
6551 /* Render target 0 is special */
6552 if(RenderTargetIndex == 0) {
6553 /* Finally, reset the viewport as the MSDN states. */
6554 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6555 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6556 viewport.X = 0;
6557 viewport.Y = 0;
6558 viewport.MaxZ = 1.0f;
6559 viewport.MinZ = 0.0f;
6560 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6561 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6562 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6566 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6567 * ctx properly.
6568 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6569 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6571 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6573 return WINED3D_OK;
6576 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6578 HRESULT hr = WINED3D_OK;
6579 IWineD3DSurface *tmp;
6581 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6583 if (pNewZStencil == This->stencilBufferTarget) {
6584 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6585 } else {
6586 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6587 * depending on the renter target implementation being used.
6588 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6589 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6590 * stencil buffer and incur an extra memory overhead
6591 ******************************************************/
6593 tmp = This->stencilBufferTarget;
6594 This->stencilBufferTarget = pNewZStencil;
6595 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6596 /* should we be calling the parent or the wined3d surface? */
6597 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6598 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6599 hr = WINED3D_OK;
6601 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6602 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6609 return hr;
6612 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6613 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6615 /* TODO: the use of Impl is deprecated. */
6616 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6617 WINED3DLOCKED_RECT lockedRect;
6619 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6621 /* some basic validation checks */
6622 if(This->cursorTexture) {
6623 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6624 ENTER_GL();
6625 glDeleteTextures(1, &This->cursorTexture);
6626 LEAVE_GL();
6627 This->cursorTexture = 0;
6630 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6631 This->haveHardwareCursor = TRUE;
6632 else
6633 This->haveHardwareCursor = FALSE;
6635 if(pCursorBitmap) {
6636 WINED3DLOCKED_RECT rect;
6638 /* MSDN: Cursor must be A8R8G8B8 */
6639 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6640 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6641 return WINED3DERR_INVALIDCALL;
6644 /* MSDN: Cursor must be smaller than the display mode */
6645 if(pSur->currentDesc.Width > This->ddraw_width ||
6646 pSur->currentDesc.Height > This->ddraw_height) {
6647 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);
6648 return WINED3DERR_INVALIDCALL;
6651 if (!This->haveHardwareCursor) {
6652 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6654 /* Do not store the surface's pointer because the application may
6655 * release it after setting the cursor image. Windows doesn't
6656 * addref the set surface, so we can't do this either without
6657 * creating circular refcount dependencies. Copy out the gl texture
6658 * instead.
6660 This->cursorWidth = pSur->currentDesc.Width;
6661 This->cursorHeight = pSur->currentDesc.Height;
6662 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6664 const GlPixelFormatDesc *glDesc;
6665 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6666 char *mem, *bits = (char *)rect.pBits;
6667 GLint intfmt = glDesc->glInternal;
6668 GLint format = glDesc->glFormat;
6669 GLint type = glDesc->glType;
6670 INT height = This->cursorHeight;
6671 INT width = This->cursorWidth;
6672 INT bpp = tableEntry->bpp;
6673 INT i;
6675 /* Reformat the texture memory (pitch and width can be
6676 * different) */
6677 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6678 for(i = 0; i < height; i++)
6679 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6680 IWineD3DSurface_UnlockRect(pCursorBitmap);
6681 ENTER_GL();
6683 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6684 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6685 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6688 /* Make sure that a proper texture unit is selected */
6689 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6690 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6691 checkGLcall("glActiveTextureARB");
6693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6694 /* Create a new cursor texture */
6695 glGenTextures(1, &This->cursorTexture);
6696 checkGLcall("glGenTextures");
6697 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6698 checkGLcall("glBindTexture");
6699 /* Copy the bitmap memory into the cursor texture */
6700 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6701 HeapFree(GetProcessHeap(), 0, mem);
6702 checkGLcall("glTexImage2D");
6704 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6705 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6706 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6709 LEAVE_GL();
6711 else
6713 FIXME("A cursor texture was not returned.\n");
6714 This->cursorTexture = 0;
6717 else
6719 /* Draw a hardware cursor */
6720 ICONINFO cursorInfo;
6721 HCURSOR cursor;
6722 /* Create and clear maskBits because it is not needed for
6723 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6724 * chunks. */
6725 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6726 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6727 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6728 WINED3DLOCK_NO_DIRTY_UPDATE |
6729 WINED3DLOCK_READONLY
6731 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6732 pSur->currentDesc.Height);
6734 cursorInfo.fIcon = FALSE;
6735 cursorInfo.xHotspot = XHotSpot;
6736 cursorInfo.yHotspot = YHotSpot;
6737 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6738 pSur->currentDesc.Height, 1,
6739 1, &maskBits);
6740 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6741 pSur->currentDesc.Height, 1,
6742 32, lockedRect.pBits);
6743 IWineD3DSurface_UnlockRect(pCursorBitmap);
6744 /* Create our cursor and clean up. */
6745 cursor = CreateIconIndirect(&cursorInfo);
6746 SetCursor(cursor);
6747 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6748 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6749 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6750 This->hardwareCursor = cursor;
6751 HeapFree(GetProcessHeap(), 0, maskBits);
6755 This->xHotSpot = XHotSpot;
6756 This->yHotSpot = YHotSpot;
6757 return WINED3D_OK;
6760 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6762 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6764 This->xScreenSpace = XScreenSpace;
6765 This->yScreenSpace = YScreenSpace;
6767 return;
6771 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6773 BOOL oldVisible = This->bCursorVisible;
6774 POINT pt;
6776 TRACE("(%p) : visible(%d)\n", This, bShow);
6779 * When ShowCursor is first called it should make the cursor appear at the OS's last
6780 * known cursor position. Because of this, some applications just repetitively call
6781 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6783 GetCursorPos(&pt);
6784 This->xScreenSpace = pt.x;
6785 This->yScreenSpace = pt.y;
6787 if (This->haveHardwareCursor) {
6788 This->bCursorVisible = bShow;
6789 if (bShow)
6790 SetCursor(This->hardwareCursor);
6791 else
6792 SetCursor(NULL);
6794 else
6796 if (This->cursorTexture)
6797 This->bCursorVisible = bShow;
6800 return oldVisible;
6803 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6805 IWineD3DResourceImpl *resource;
6806 TRACE("(%p) : state (%u)\n", This, This->state);
6808 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6809 switch (This->state) {
6810 case WINED3D_OK:
6811 return WINED3D_OK;
6812 case WINED3DERR_DEVICELOST:
6814 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6815 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6816 return WINED3DERR_DEVICENOTRESET;
6818 return WINED3DERR_DEVICELOST;
6820 case WINED3DERR_DRIVERINTERNALERROR:
6821 return WINED3DERR_DRIVERINTERNALERROR;
6824 /* Unknown state */
6825 return WINED3DERR_DRIVERINTERNALERROR;
6829 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6831 /** FIXME: Resource tracking needs to be done,
6832 * The closes we can do to this is set the priorities of all managed textures low
6833 * and then reset them.
6834 ***********************************************************/
6835 FIXME("(%p) : stub\n", This);
6836 return WINED3D_OK;
6839 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6840 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6842 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6843 if(surface->Flags & SFLAG_DIBSECTION) {
6844 /* Release the DC */
6845 SelectObject(surface->hDC, surface->dib.holdbitmap);
6846 DeleteDC(surface->hDC);
6847 /* Release the DIB section */
6848 DeleteObject(surface->dib.DIBsection);
6849 surface->dib.bitmap_data = NULL;
6850 surface->resource.allocatedMemory = NULL;
6851 surface->Flags &= ~SFLAG_DIBSECTION;
6853 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6854 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6855 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6856 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6857 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6858 } else {
6859 surface->pow2Width = surface->pow2Height = 1;
6860 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6861 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6863 surface->glRect.left = 0;
6864 surface->glRect.top = 0;
6865 surface->glRect.right = surface->pow2Width;
6866 surface->glRect.bottom = surface->pow2Height;
6868 if(surface->glDescription.textureName) {
6869 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6870 ENTER_GL();
6871 glDeleteTextures(1, &surface->glDescription.textureName);
6872 LEAVE_GL();
6873 surface->glDescription.textureName = 0;
6874 surface->Flags &= ~SFLAG_CLIENT;
6876 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6877 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6878 surface->Flags |= SFLAG_NONPOW2;
6879 } else {
6880 surface->Flags &= ~SFLAG_NONPOW2;
6882 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6883 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6886 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6887 TRACE("Unloading resource %p\n", resource);
6888 IWineD3DResource_UnLoad(resource);
6889 IWineD3DResource_Release(resource);
6890 return S_OK;
6893 static void reset_fbo_state(IWineD3DDevice *iface) {
6894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6895 unsigned int i;
6897 ENTER_GL();
6898 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6899 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
6901 if (This->fbo) {
6902 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
6903 This->fbo = 0;
6905 if (This->src_fbo) {
6906 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
6907 This->src_fbo = 0;
6909 if (This->dst_fbo) {
6910 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
6911 This->dst_fbo = 0;
6913 checkGLcall("Tear down fbos\n");
6914 LEAVE_GL();
6916 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6917 This->fbo_color_attachments[i] = NULL;
6919 This->fbo_depth_attachment = NULL;
6922 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6923 UINT i, count;
6924 WINED3DDISPLAYMODE m;
6925 HRESULT hr;
6927 /* All Windowed modes are supported, as is leaving the current mode */
6928 if(pp->Windowed) return TRUE;
6929 if(!pp->BackBufferWidth) return TRUE;
6930 if(!pp->BackBufferHeight) return TRUE;
6932 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6933 for(i = 0; i < count; i++) {
6934 memset(&m, 0, sizeof(m));
6935 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6936 if(FAILED(hr)) {
6937 ERR("EnumAdapterModes failed\n");
6939 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6940 /* Mode found, it is supported */
6941 return TRUE;
6944 /* Mode not found -> not supported */
6945 return FALSE;
6948 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6950 IWineD3DSwapChainImpl *swapchain;
6951 HRESULT hr;
6952 BOOL DisplayModeChanged = FALSE;
6953 WINED3DDISPLAYMODE mode;
6954 IWineD3DBaseShaderImpl *shader;
6955 IWineD3DSurfaceImpl *target;
6956 UINT i;
6957 TRACE("(%p)\n", This);
6959 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6960 if(FAILED(hr)) {
6961 ERR("Failed to get the first implicit swapchain\n");
6962 return hr;
6965 if(!is_display_mode_supported(This, pPresentationParameters)) {
6966 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6967 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6968 pPresentationParameters->BackBufferHeight);
6969 return WINED3DERR_INVALIDCALL;
6972 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6973 * on an existing gl context, so there's no real need for recreation.
6975 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6977 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6979 TRACE("New params:\n");
6980 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6981 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6982 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6983 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6984 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6985 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6986 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6987 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6988 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6989 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6990 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6991 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6992 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6994 /* No special treatment of these parameters. Just store them */
6995 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6996 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6997 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6998 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7000 /* What to do about these? */
7001 if(pPresentationParameters->BackBufferCount != 0 &&
7002 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7003 ERR("Cannot change the back buffer count yet\n");
7005 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7006 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7007 ERR("Cannot change the back buffer format yet\n");
7009 if(pPresentationParameters->hDeviceWindow != NULL &&
7010 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7011 ERR("Cannot change the device window yet\n");
7013 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7014 ERR("What do do about a changed auto depth stencil parameter?\n");
7017 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7018 reset_fbo_state((IWineD3DDevice *) This);
7021 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7022 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7023 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7026 ENTER_GL();
7027 if(This->depth_blt_texture) {
7028 glDeleteTextures(1, &This->depth_blt_texture);
7029 This->depth_blt_texture = 0;
7031 This->shader_backend->shader_destroy_depth_blt(iface);
7033 for (i = 0; i < GL_LIMITS(textures); i++) {
7034 /* Textures are recreated below */
7035 glDeleteTextures(1, &This->dummyTextureName[i]);
7036 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7037 This->dummyTextureName[i] = 0;
7039 LEAVE_GL();
7041 while(This->numContexts) {
7042 DestroyContext(This, This->contexts[0]);
7044 This->activeContext = NULL;
7045 HeapFree(GetProcessHeap(), 0, swapchain->context);
7046 swapchain->context = NULL;
7047 swapchain->num_contexts = 0;
7049 if(pPresentationParameters->Windowed) {
7050 mode.Width = swapchain->orig_width;
7051 mode.Height = swapchain->orig_height;
7052 mode.RefreshRate = 0;
7053 mode.Format = swapchain->presentParms.BackBufferFormat;
7054 } else {
7055 mode.Width = pPresentationParameters->BackBufferWidth;
7056 mode.Height = pPresentationParameters->BackBufferHeight;
7057 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7058 mode.Format = swapchain->presentParms.BackBufferFormat;
7061 /* Should Width == 800 && Height == 0 set 800x600? */
7062 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7063 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7064 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7066 WINED3DVIEWPORT vp;
7067 int i;
7069 vp.X = 0;
7070 vp.Y = 0;
7071 vp.Width = pPresentationParameters->BackBufferWidth;
7072 vp.Height = pPresentationParameters->BackBufferHeight;
7073 vp.MinZ = 0;
7074 vp.MaxZ = 1;
7076 if(!pPresentationParameters->Windowed) {
7077 DisplayModeChanged = TRUE;
7079 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7080 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7082 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7083 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7084 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7086 if(This->auto_depth_stencil_buffer) {
7087 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7091 /* Now set the new viewport */
7092 IWineD3DDevice_SetViewport(iface, &vp);
7095 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7096 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7097 DisplayModeChanged) {
7099 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7100 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7101 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7102 } else if(!pPresentationParameters->Windowed) {
7103 DWORD style = This->style, exStyle = This->exStyle;
7104 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7105 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7106 * Reset to clear up their mess. Guild Wars also loses the device during that.
7108 This->style = 0;
7109 This->exStyle = 0;
7110 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7111 This->style = style;
7112 This->exStyle = exStyle;
7115 /* Recreate the primary swapchain's context */
7116 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7117 if(swapchain->backBuffer) {
7118 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7119 } else {
7120 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7122 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7123 &swapchain->presentParms);
7124 swapchain->num_contexts = 1;
7125 This->activeContext = swapchain->context[0];
7127 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7128 if(FAILED(hr)) {
7129 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7131 create_dummy_textures(This);
7133 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7134 * first use
7137 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7138 return WINED3D_OK;
7141 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7143 /** FIXME: always true at the moment **/
7144 if(!bEnableDialogs) {
7145 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7147 return WINED3D_OK;
7151 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7153 TRACE("(%p) : pParameters %p\n", This, pParameters);
7155 *pParameters = This->createParms;
7156 return WINED3D_OK;
7159 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7160 IWineD3DSwapChain *swapchain;
7161 HRESULT hrc = WINED3D_OK;
7163 TRACE("Relaying to swapchain\n");
7165 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7166 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7167 IWineD3DSwapChain_Release(swapchain);
7169 return;
7172 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7173 IWineD3DSwapChain *swapchain;
7174 HRESULT hrc = WINED3D_OK;
7176 TRACE("Relaying to swapchain\n");
7178 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7179 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7180 IWineD3DSwapChain_Release(swapchain);
7182 return;
7186 /** ********************************************************
7187 * Notification functions
7188 ** ********************************************************/
7189 /** This function must be called in the release of a resource when ref == 0,
7190 * the contents of resource must still be correct,
7191 * any handles to other resource held by the caller must be closed
7192 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7193 *****************************************************/
7194 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7197 TRACE("(%p) : Adding Resource %p\n", This, resource);
7198 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7201 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7204 TRACE("(%p) : Removing resource %p\n", This, resource);
7206 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7210 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7212 int counter;
7214 TRACE("(%p) : resource %p\n", This, resource);
7215 switch(IWineD3DResource_GetType(resource)){
7216 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7217 case WINED3DRTYPE_SURFACE: {
7218 unsigned int i;
7220 /* Cleanup any FBO attachments if d3d is enabled */
7221 if(This->d3d_initialized) {
7222 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7223 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7225 TRACE("Last active render target destroyed\n");
7226 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7227 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7228 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7229 * and the lastActiveRenderTarget member shouldn't matter
7231 if(swapchain) {
7232 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7233 TRACE("Activating primary back buffer\n");
7234 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7235 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7236 /* Single buffering environment */
7237 TRACE("Activating primary front buffer\n");
7238 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7239 } else {
7240 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7241 /* Implicit render target destroyed, that means the device is being destroyed
7242 * whatever we set here, it shouldn't matter
7244 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7246 } else {
7247 /* May happen during ddraw uninitialization */
7248 TRACE("Render target set, but swapchain does not exist!\n");
7249 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7253 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7254 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7255 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7256 set_render_target_fbo(iface, i, NULL);
7257 This->fbo_color_attachments[i] = NULL;
7260 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7261 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7262 set_depth_stencil_fbo(iface, NULL);
7263 This->fbo_depth_attachment = NULL;
7267 break;
7269 case WINED3DRTYPE_TEXTURE:
7270 case WINED3DRTYPE_CUBETEXTURE:
7271 case WINED3DRTYPE_VOLUMETEXTURE:
7272 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7273 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7274 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7275 This->stateBlock->textures[counter] = NULL;
7277 if (This->updateStateBlock != This->stateBlock ){
7278 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7279 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7280 This->updateStateBlock->textures[counter] = NULL;
7284 break;
7285 case WINED3DRTYPE_VOLUME:
7286 /* TODO: nothing really? */
7287 break;
7288 case WINED3DRTYPE_VERTEXBUFFER:
7289 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7291 int streamNumber;
7292 TRACE("Cleaning up stream pointers\n");
7294 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7295 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7296 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7298 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7299 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7300 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7301 This->updateStateBlock->streamSource[streamNumber] = 0;
7302 /* Set changed flag? */
7305 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) */
7306 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7307 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7308 This->stateBlock->streamSource[streamNumber] = 0;
7311 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7312 else { /* This shouldn't happen */
7313 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7315 #endif
7319 break;
7320 case WINED3DRTYPE_INDEXBUFFER:
7321 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7322 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7323 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7324 This->updateStateBlock->pIndexData = NULL;
7327 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7328 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7329 This->stateBlock->pIndexData = NULL;
7333 break;
7334 default:
7335 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7336 break;
7340 /* Remove the resource from the resourceStore */
7341 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7343 TRACE("Resource released\n");
7347 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7349 IWineD3DResourceImpl *resource, *cursor;
7350 HRESULT ret;
7351 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7353 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7354 TRACE("enumerating resource %p\n", resource);
7355 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7356 ret = pCallback((IWineD3DResource *) resource, pData);
7357 if(ret == S_FALSE) {
7358 TRACE("Canceling enumeration\n");
7359 break;
7362 return WINED3D_OK;
7365 /**********************************************************
7366 * IWineD3DDevice VTbl follows
7367 **********************************************************/
7369 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7371 /*** IUnknown methods ***/
7372 IWineD3DDeviceImpl_QueryInterface,
7373 IWineD3DDeviceImpl_AddRef,
7374 IWineD3DDeviceImpl_Release,
7375 /*** IWineD3DDevice methods ***/
7376 IWineD3DDeviceImpl_GetParent,
7377 /*** Creation methods**/
7378 IWineD3DDeviceImpl_CreateVertexBuffer,
7379 IWineD3DDeviceImpl_CreateIndexBuffer,
7380 IWineD3DDeviceImpl_CreateStateBlock,
7381 IWineD3DDeviceImpl_CreateSurface,
7382 IWineD3DDeviceImpl_CreateTexture,
7383 IWineD3DDeviceImpl_CreateVolumeTexture,
7384 IWineD3DDeviceImpl_CreateVolume,
7385 IWineD3DDeviceImpl_CreateCubeTexture,
7386 IWineD3DDeviceImpl_CreateQuery,
7387 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7388 IWineD3DDeviceImpl_CreateVertexDeclaration,
7389 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7390 IWineD3DDeviceImpl_CreateVertexShader,
7391 IWineD3DDeviceImpl_CreatePixelShader,
7392 IWineD3DDeviceImpl_CreatePalette,
7393 /*** Odd functions **/
7394 IWineD3DDeviceImpl_Init3D,
7395 IWineD3DDeviceImpl_Uninit3D,
7396 IWineD3DDeviceImpl_SetFullscreen,
7397 IWineD3DDeviceImpl_SetMultithreaded,
7398 IWineD3DDeviceImpl_EvictManagedResources,
7399 IWineD3DDeviceImpl_GetAvailableTextureMem,
7400 IWineD3DDeviceImpl_GetBackBuffer,
7401 IWineD3DDeviceImpl_GetCreationParameters,
7402 IWineD3DDeviceImpl_GetDeviceCaps,
7403 IWineD3DDeviceImpl_GetDirect3D,
7404 IWineD3DDeviceImpl_GetDisplayMode,
7405 IWineD3DDeviceImpl_SetDisplayMode,
7406 IWineD3DDeviceImpl_GetHWND,
7407 IWineD3DDeviceImpl_SetHWND,
7408 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7409 IWineD3DDeviceImpl_GetRasterStatus,
7410 IWineD3DDeviceImpl_GetSwapChain,
7411 IWineD3DDeviceImpl_Reset,
7412 IWineD3DDeviceImpl_SetDialogBoxMode,
7413 IWineD3DDeviceImpl_SetCursorProperties,
7414 IWineD3DDeviceImpl_SetCursorPosition,
7415 IWineD3DDeviceImpl_ShowCursor,
7416 IWineD3DDeviceImpl_TestCooperativeLevel,
7417 /*** Getters and setters **/
7418 IWineD3DDeviceImpl_SetClipPlane,
7419 IWineD3DDeviceImpl_GetClipPlane,
7420 IWineD3DDeviceImpl_SetClipStatus,
7421 IWineD3DDeviceImpl_GetClipStatus,
7422 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7423 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7424 IWineD3DDeviceImpl_SetDepthStencilSurface,
7425 IWineD3DDeviceImpl_GetDepthStencilSurface,
7426 IWineD3DDeviceImpl_SetFVF,
7427 IWineD3DDeviceImpl_GetFVF,
7428 IWineD3DDeviceImpl_SetGammaRamp,
7429 IWineD3DDeviceImpl_GetGammaRamp,
7430 IWineD3DDeviceImpl_SetIndices,
7431 IWineD3DDeviceImpl_GetIndices,
7432 IWineD3DDeviceImpl_SetBaseVertexIndex,
7433 IWineD3DDeviceImpl_GetBaseVertexIndex,
7434 IWineD3DDeviceImpl_SetLight,
7435 IWineD3DDeviceImpl_GetLight,
7436 IWineD3DDeviceImpl_SetLightEnable,
7437 IWineD3DDeviceImpl_GetLightEnable,
7438 IWineD3DDeviceImpl_SetMaterial,
7439 IWineD3DDeviceImpl_GetMaterial,
7440 IWineD3DDeviceImpl_SetNPatchMode,
7441 IWineD3DDeviceImpl_GetNPatchMode,
7442 IWineD3DDeviceImpl_SetPaletteEntries,
7443 IWineD3DDeviceImpl_GetPaletteEntries,
7444 IWineD3DDeviceImpl_SetPixelShader,
7445 IWineD3DDeviceImpl_GetPixelShader,
7446 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7447 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7448 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7449 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7450 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7451 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7452 IWineD3DDeviceImpl_SetRenderState,
7453 IWineD3DDeviceImpl_GetRenderState,
7454 IWineD3DDeviceImpl_SetRenderTarget,
7455 IWineD3DDeviceImpl_GetRenderTarget,
7456 IWineD3DDeviceImpl_SetFrontBackBuffers,
7457 IWineD3DDeviceImpl_SetSamplerState,
7458 IWineD3DDeviceImpl_GetSamplerState,
7459 IWineD3DDeviceImpl_SetScissorRect,
7460 IWineD3DDeviceImpl_GetScissorRect,
7461 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7462 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7463 IWineD3DDeviceImpl_SetStreamSource,
7464 IWineD3DDeviceImpl_GetStreamSource,
7465 IWineD3DDeviceImpl_SetStreamSourceFreq,
7466 IWineD3DDeviceImpl_GetStreamSourceFreq,
7467 IWineD3DDeviceImpl_SetTexture,
7468 IWineD3DDeviceImpl_GetTexture,
7469 IWineD3DDeviceImpl_SetTextureStageState,
7470 IWineD3DDeviceImpl_GetTextureStageState,
7471 IWineD3DDeviceImpl_SetTransform,
7472 IWineD3DDeviceImpl_GetTransform,
7473 IWineD3DDeviceImpl_SetVertexDeclaration,
7474 IWineD3DDeviceImpl_GetVertexDeclaration,
7475 IWineD3DDeviceImpl_SetVertexShader,
7476 IWineD3DDeviceImpl_GetVertexShader,
7477 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7478 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7479 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7480 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7481 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7482 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7483 IWineD3DDeviceImpl_SetViewport,
7484 IWineD3DDeviceImpl_GetViewport,
7485 IWineD3DDeviceImpl_MultiplyTransform,
7486 IWineD3DDeviceImpl_ValidateDevice,
7487 IWineD3DDeviceImpl_ProcessVertices,
7488 /*** State block ***/
7489 IWineD3DDeviceImpl_BeginStateBlock,
7490 IWineD3DDeviceImpl_EndStateBlock,
7491 /*** Scene management ***/
7492 IWineD3DDeviceImpl_BeginScene,
7493 IWineD3DDeviceImpl_EndScene,
7494 IWineD3DDeviceImpl_Present,
7495 IWineD3DDeviceImpl_Clear,
7496 /*** Drawing ***/
7497 IWineD3DDeviceImpl_DrawPrimitive,
7498 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7499 IWineD3DDeviceImpl_DrawPrimitiveUP,
7500 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7501 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7502 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7503 IWineD3DDeviceImpl_DrawRectPatch,
7504 IWineD3DDeviceImpl_DrawTriPatch,
7505 IWineD3DDeviceImpl_DeletePatch,
7506 IWineD3DDeviceImpl_ColorFill,
7507 IWineD3DDeviceImpl_UpdateTexture,
7508 IWineD3DDeviceImpl_UpdateSurface,
7509 IWineD3DDeviceImpl_GetFrontBufferData,
7510 /*** object tracking ***/
7511 IWineD3DDeviceImpl_ResourceReleased,
7512 IWineD3DDeviceImpl_EnumResources
7515 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7517 /*** IUnknown methods ***/
7518 IWineD3DDeviceImpl_QueryInterface,
7519 IWineD3DDeviceImpl_AddRef,
7520 IWineD3DDeviceImpl_Release,
7521 /*** IWineD3DDevice methods ***/
7522 IWineD3DDeviceImpl_GetParent,
7523 /*** Creation methods**/
7524 IWineD3DDeviceImpl_CreateVertexBuffer,
7525 IWineD3DDeviceImpl_CreateIndexBuffer,
7526 IWineD3DDeviceImpl_CreateStateBlock,
7527 IWineD3DDeviceImpl_CreateSurface,
7528 IWineD3DDeviceImpl_CreateTexture,
7529 IWineD3DDeviceImpl_CreateVolumeTexture,
7530 IWineD3DDeviceImpl_CreateVolume,
7531 IWineD3DDeviceImpl_CreateCubeTexture,
7532 IWineD3DDeviceImpl_CreateQuery,
7533 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7534 IWineD3DDeviceImpl_CreateVertexDeclaration,
7535 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7536 IWineD3DDeviceImpl_CreateVertexShader,
7537 IWineD3DDeviceImpl_CreatePixelShader,
7538 IWineD3DDeviceImpl_CreatePalette,
7539 /*** Odd functions **/
7540 IWineD3DDeviceImpl_Init3D,
7541 IWineD3DDeviceImpl_Uninit3D,
7542 IWineD3DDeviceImpl_SetFullscreen,
7543 IWineD3DDeviceImpl_SetMultithreaded,
7544 IWineD3DDeviceImpl_EvictManagedResources,
7545 IWineD3DDeviceImpl_GetAvailableTextureMem,
7546 IWineD3DDeviceImpl_GetBackBuffer,
7547 IWineD3DDeviceImpl_GetCreationParameters,
7548 IWineD3DDeviceImpl_GetDeviceCaps,
7549 IWineD3DDeviceImpl_GetDirect3D,
7550 IWineD3DDeviceImpl_GetDisplayMode,
7551 IWineD3DDeviceImpl_SetDisplayMode,
7552 IWineD3DDeviceImpl_GetHWND,
7553 IWineD3DDeviceImpl_SetHWND,
7554 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7555 IWineD3DDeviceImpl_GetRasterStatus,
7556 IWineD3DDeviceImpl_GetSwapChain,
7557 IWineD3DDeviceImpl_Reset,
7558 IWineD3DDeviceImpl_SetDialogBoxMode,
7559 IWineD3DDeviceImpl_SetCursorProperties,
7560 IWineD3DDeviceImpl_SetCursorPosition,
7561 IWineD3DDeviceImpl_ShowCursor,
7562 IWineD3DDeviceImpl_TestCooperativeLevel,
7563 /*** Getters and setters **/
7564 IWineD3DDeviceImpl_SetClipPlane,
7565 IWineD3DDeviceImpl_GetClipPlane,
7566 IWineD3DDeviceImpl_SetClipStatus,
7567 IWineD3DDeviceImpl_GetClipStatus,
7568 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7569 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7570 IWineD3DDeviceImpl_SetDepthStencilSurface,
7571 IWineD3DDeviceImpl_GetDepthStencilSurface,
7572 IWineD3DDeviceImpl_SetFVF,
7573 IWineD3DDeviceImpl_GetFVF,
7574 IWineD3DDeviceImpl_SetGammaRamp,
7575 IWineD3DDeviceImpl_GetGammaRamp,
7576 IWineD3DDeviceImpl_SetIndices,
7577 IWineD3DDeviceImpl_GetIndices,
7578 IWineD3DDeviceImpl_SetBaseVertexIndex,
7579 IWineD3DDeviceImpl_GetBaseVertexIndex,
7580 IWineD3DDeviceImpl_SetLight,
7581 IWineD3DDeviceImpl_GetLight,
7582 IWineD3DDeviceImpl_SetLightEnable,
7583 IWineD3DDeviceImpl_GetLightEnable,
7584 IWineD3DDeviceImpl_SetMaterial,
7585 IWineD3DDeviceImpl_GetMaterial,
7586 IWineD3DDeviceImpl_SetNPatchMode,
7587 IWineD3DDeviceImpl_GetNPatchMode,
7588 IWineD3DDeviceImpl_SetPaletteEntries,
7589 IWineD3DDeviceImpl_GetPaletteEntries,
7590 IWineD3DDeviceImpl_SetPixelShader,
7591 IWineD3DDeviceImpl_GetPixelShader,
7592 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7593 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7594 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7595 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7596 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7597 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7598 IWineD3DDeviceImpl_SetRenderState,
7599 IWineD3DDeviceImpl_GetRenderState,
7600 IWineD3DDeviceImpl_SetRenderTarget,
7601 IWineD3DDeviceImpl_GetRenderTarget,
7602 IWineD3DDeviceImpl_SetFrontBackBuffers,
7603 IWineD3DDeviceImpl_SetSamplerState,
7604 IWineD3DDeviceImpl_GetSamplerState,
7605 IWineD3DDeviceImpl_SetScissorRect,
7606 IWineD3DDeviceImpl_GetScissorRect,
7607 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7608 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7609 IWineD3DDeviceImpl_SetStreamSource,
7610 IWineD3DDeviceImpl_GetStreamSource,
7611 IWineD3DDeviceImpl_SetStreamSourceFreq,
7612 IWineD3DDeviceImpl_GetStreamSourceFreq,
7613 IWineD3DDeviceImpl_SetTexture,
7614 IWineD3DDeviceImpl_GetTexture,
7615 IWineD3DDeviceImpl_SetTextureStageState,
7616 IWineD3DDeviceImpl_GetTextureStageState,
7617 IWineD3DDeviceImpl_SetTransform,
7618 IWineD3DDeviceImpl_GetTransform,
7619 IWineD3DDeviceImpl_SetVertexDeclaration,
7620 IWineD3DDeviceImpl_GetVertexDeclaration,
7621 IWineD3DDeviceImpl_SetVertexShader,
7622 IWineD3DDeviceImpl_GetVertexShader,
7623 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7624 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7625 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7626 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7627 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7628 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7629 IWineD3DDeviceImpl_SetViewport,
7630 IWineD3DDeviceImpl_GetViewport,
7631 IWineD3DDeviceImpl_MultiplyTransform,
7632 IWineD3DDeviceImpl_ValidateDevice,
7633 IWineD3DDeviceImpl_ProcessVertices,
7634 /*** State block ***/
7635 IWineD3DDeviceImpl_BeginStateBlock,
7636 IWineD3DDeviceImpl_EndStateBlock,
7637 /*** Scene management ***/
7638 IWineD3DDeviceImpl_BeginScene,
7639 IWineD3DDeviceImpl_EndScene,
7640 IWineD3DDeviceImpl_Present,
7641 IWineD3DDeviceImpl_Clear,
7642 /*** Drawing ***/
7643 IWineD3DDeviceImpl_DrawPrimitive,
7644 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7645 IWineD3DDeviceImpl_DrawPrimitiveUP,
7646 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7647 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7648 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7649 IWineD3DDeviceImpl_DrawRectPatch,
7650 IWineD3DDeviceImpl_DrawTriPatch,
7651 IWineD3DDeviceImpl_DeletePatch,
7652 IWineD3DDeviceImpl_ColorFill,
7653 IWineD3DDeviceImpl_UpdateTexture,
7654 IWineD3DDeviceImpl_UpdateSurface,
7655 IWineD3DDeviceImpl_GetFrontBufferData,
7656 /*** object tracking ***/
7657 IWineD3DDeviceImpl_ResourceReleased,
7658 IWineD3DDeviceImpl_EnumResources
7661 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7662 WINED3DRS_ALPHABLENDENABLE ,
7663 WINED3DRS_ALPHAFUNC ,
7664 WINED3DRS_ALPHAREF ,
7665 WINED3DRS_ALPHATESTENABLE ,
7666 WINED3DRS_BLENDOP ,
7667 WINED3DRS_COLORWRITEENABLE ,
7668 WINED3DRS_DESTBLEND ,
7669 WINED3DRS_DITHERENABLE ,
7670 WINED3DRS_FILLMODE ,
7671 WINED3DRS_FOGDENSITY ,
7672 WINED3DRS_FOGEND ,
7673 WINED3DRS_FOGSTART ,
7674 WINED3DRS_LASTPIXEL ,
7675 WINED3DRS_SHADEMODE ,
7676 WINED3DRS_SRCBLEND ,
7677 WINED3DRS_STENCILENABLE ,
7678 WINED3DRS_STENCILFAIL ,
7679 WINED3DRS_STENCILFUNC ,
7680 WINED3DRS_STENCILMASK ,
7681 WINED3DRS_STENCILPASS ,
7682 WINED3DRS_STENCILREF ,
7683 WINED3DRS_STENCILWRITEMASK ,
7684 WINED3DRS_STENCILZFAIL ,
7685 WINED3DRS_TEXTUREFACTOR ,
7686 WINED3DRS_WRAP0 ,
7687 WINED3DRS_WRAP1 ,
7688 WINED3DRS_WRAP2 ,
7689 WINED3DRS_WRAP3 ,
7690 WINED3DRS_WRAP4 ,
7691 WINED3DRS_WRAP5 ,
7692 WINED3DRS_WRAP6 ,
7693 WINED3DRS_WRAP7 ,
7694 WINED3DRS_ZENABLE ,
7695 WINED3DRS_ZFUNC ,
7696 WINED3DRS_ZWRITEENABLE
7699 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7700 WINED3DTSS_ADDRESSW ,
7701 WINED3DTSS_ALPHAARG0 ,
7702 WINED3DTSS_ALPHAARG1 ,
7703 WINED3DTSS_ALPHAARG2 ,
7704 WINED3DTSS_ALPHAOP ,
7705 WINED3DTSS_BUMPENVLOFFSET ,
7706 WINED3DTSS_BUMPENVLSCALE ,
7707 WINED3DTSS_BUMPENVMAT00 ,
7708 WINED3DTSS_BUMPENVMAT01 ,
7709 WINED3DTSS_BUMPENVMAT10 ,
7710 WINED3DTSS_BUMPENVMAT11 ,
7711 WINED3DTSS_COLORARG0 ,
7712 WINED3DTSS_COLORARG1 ,
7713 WINED3DTSS_COLORARG2 ,
7714 WINED3DTSS_COLOROP ,
7715 WINED3DTSS_RESULTARG ,
7716 WINED3DTSS_TEXCOORDINDEX ,
7717 WINED3DTSS_TEXTURETRANSFORMFLAGS
7720 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7721 WINED3DSAMP_ADDRESSU ,
7722 WINED3DSAMP_ADDRESSV ,
7723 WINED3DSAMP_ADDRESSW ,
7724 WINED3DSAMP_BORDERCOLOR ,
7725 WINED3DSAMP_MAGFILTER ,
7726 WINED3DSAMP_MINFILTER ,
7727 WINED3DSAMP_MIPFILTER ,
7728 WINED3DSAMP_MIPMAPLODBIAS ,
7729 WINED3DSAMP_MAXMIPLEVEL ,
7730 WINED3DSAMP_MAXANISOTROPY ,
7731 WINED3DSAMP_SRGBTEXTURE ,
7732 WINED3DSAMP_ELEMENTINDEX
7735 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7736 WINED3DRS_AMBIENT ,
7737 WINED3DRS_AMBIENTMATERIALSOURCE ,
7738 WINED3DRS_CLIPPING ,
7739 WINED3DRS_CLIPPLANEENABLE ,
7740 WINED3DRS_COLORVERTEX ,
7741 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7742 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7743 WINED3DRS_FOGDENSITY ,
7744 WINED3DRS_FOGEND ,
7745 WINED3DRS_FOGSTART ,
7746 WINED3DRS_FOGTABLEMODE ,
7747 WINED3DRS_FOGVERTEXMODE ,
7748 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7749 WINED3DRS_LIGHTING ,
7750 WINED3DRS_LOCALVIEWER ,
7751 WINED3DRS_MULTISAMPLEANTIALIAS ,
7752 WINED3DRS_MULTISAMPLEMASK ,
7753 WINED3DRS_NORMALIZENORMALS ,
7754 WINED3DRS_PATCHEDGESTYLE ,
7755 WINED3DRS_POINTSCALE_A ,
7756 WINED3DRS_POINTSCALE_B ,
7757 WINED3DRS_POINTSCALE_C ,
7758 WINED3DRS_POINTSCALEENABLE ,
7759 WINED3DRS_POINTSIZE ,
7760 WINED3DRS_POINTSIZE_MAX ,
7761 WINED3DRS_POINTSIZE_MIN ,
7762 WINED3DRS_POINTSPRITEENABLE ,
7763 WINED3DRS_RANGEFOGENABLE ,
7764 WINED3DRS_SPECULARMATERIALSOURCE ,
7765 WINED3DRS_TWEENFACTOR ,
7766 WINED3DRS_VERTEXBLEND ,
7767 WINED3DRS_CULLMODE ,
7768 WINED3DRS_FOGCOLOR
7771 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7772 WINED3DTSS_TEXCOORDINDEX ,
7773 WINED3DTSS_TEXTURETRANSFORMFLAGS
7776 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7777 WINED3DSAMP_DMAPOFFSET
7780 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7781 DWORD rep = This->shader_backend->StateTable[state].representative;
7782 DWORD idx;
7783 BYTE shift;
7784 UINT i;
7785 WineD3DContext *context;
7787 if(!rep) return;
7788 for(i = 0; i < This->numContexts; i++) {
7789 context = This->contexts[i];
7790 if(isStateDirty(context, rep)) continue;
7792 context->dirtyArray[context->numDirtyEntries++] = rep;
7793 idx = rep >> 5;
7794 shift = rep & 0x1f;
7795 context->isStateDirty[idx] |= (1 << shift);
7799 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7800 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7801 /* The drawable size of a pbuffer render target is the current pbuffer size
7803 *width = dev->pbufferWidth;
7804 *height = dev->pbufferHeight;
7807 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7808 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7810 *width = This->pow2Width;
7811 *height = This->pow2Height;
7814 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7815 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7816 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7817 * current context's drawable, which is the size of the back buffer of the swapchain
7818 * the active context belongs to. The back buffer of the swapchain is stored as the
7819 * surface the context belongs to.
7821 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7822 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;