wined3d: Render to the correct hwnd/hdc.
[wine.git] / dlls / wined3d / device.c
blob4f489cf4ef72559146484c8970bb8fc28ece9645
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->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.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 for(i = 0; i < MAX_STREAMS; i++) {
518 if(object->streamSource[i]) {
519 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
522 if(object->pIndexData) {
523 IWineD3DIndexBuffer_AddRef(object->pIndexData);
525 if(object->vertexShader) {
526 IWineD3DVertexShader_AddRef(object->vertexShader);
528 if(object->pixelShader) {
529 IWineD3DPixelShader_AddRef(object->pixelShader);
532 } else if (Type == WINED3DSBT_PIXELSTATE) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.pixelShader = TRUE;
539 /* Pixel Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541 object->contained_ps_consts_f[i] = i;
542 object->changed.pixelShaderConstantsF[i] = TRUE;
544 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545 for (i = 0; i < MAX_CONST_B; ++i) {
546 object->contained_ps_consts_b[i] = i;
547 object->changed.pixelShaderConstantsB[i] = TRUE;
549 object->num_contained_ps_consts_b = MAX_CONST_B;
550 for (i = 0; i < MAX_CONST_I; ++i) {
551 object->contained_ps_consts_i[i] = i;
552 object->changed.pixelShaderConstantsI[i] = TRUE;
554 object->num_contained_ps_consts_i = MAX_CONST_I;
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558 object->contained_render_states[i] = SavedPixelStates_R[i];
560 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561 for (j = 0; j < MAX_TEXTURES; j++) {
562 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566 object->num_contained_tss_states++;
569 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574 object->num_contained_sampler_states++;
577 if(object->pixelShader) {
578 IWineD3DPixelShader_AddRef(object->pixelShader);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i = 0; i < MAX_STREAMS; i++) {
585 object->streamSource[i] = NULL;
587 object->pIndexData = NULL;
588 object->vertexShader = NULL;
590 } else if (Type == WINED3DSBT_VERTEXSTATE) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
595 object->changed.vertexShader = TRUE;
597 /* Vertex Shader Constants */
598 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599 object->changed.vertexShaderConstantsF[i] = TRUE;
600 object->contained_vs_consts_f[i] = i;
602 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603 for (i = 0; i < MAX_CONST_B; ++i) {
604 object->changed.vertexShaderConstantsB[i] = TRUE;
605 object->contained_vs_consts_b[i] = i;
607 object->num_contained_vs_consts_b = MAX_CONST_B;
608 for (i = 0; i < MAX_CONST_I; ++i) {
609 object->changed.vertexShaderConstantsI[i] = TRUE;
610 object->contained_vs_consts_i[i] = i;
612 object->num_contained_vs_consts_i = MAX_CONST_I;
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 object->contained_render_states[i] = SavedVertexStates_R[i];
617 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618 for (j = 0; j < MAX_TEXTURES; j++) {
619 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623 object->num_contained_tss_states++;
626 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631 object->num_contained_sampler_states++;
635 for(j = 0; j < LIGHTMAP_SIZE; j++) {
636 struct list *e;
637 LIST_FOR_EACH(e, &object->lightMap[j]) {
638 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639 light->changed = TRUE;
640 light->enabledChanged = TRUE;
644 for(i = 0; i < MAX_STREAMS; i++) {
645 if(object->streamSource[i]) {
646 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
649 if(object->vertexShader) {
650 IWineD3DVertexShader_AddRef(object->vertexShader);
652 object->pIndexData = NULL;
653 object->pixelShader = NULL;
654 } else {
655 FIXME("Unrecognized state block type %d\n", Type);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
659 return WINED3D_OK;
662 /* ************************************
663 MSDN:
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
666 Discard
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
671 ******************************** */
673 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
675 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size = 1;
677 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678 TRACE("(%p) Create surface\n",This);
680 /** FIXME: Check ranges on the inputs are valid
681 * MSDN
682 * MultisampleQuality
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
687 * must all match.
688 *******************************/
692 * TODO: Discard MSDN
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality < 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality);
704 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
707 if(MultisampleQuality > 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709 MultisampleQuality=0;
712 /** FIXME: Check that the format is supported
713 * by the device.
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
718 * space!
719 *********************************/
720 if (WINED3DFMT_UNKNOWN == Format) {
721 Size = 0;
722 } else if (Format == WINED3DFMT_DXT1) {
723 /* DXT1 is half byte per pixel */
724 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
726 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
729 } else {
730 /* The pitch is a multiple of 4 bytes */
731 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
732 Size *= Height;
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
740 object->currentDesc.Width = Width;
741 object->currentDesc.Height = Height;
742 object->currentDesc.MultiSampleType = MultiSample;
743 object->currentDesc.MultiSampleQuality = MultisampleQuality;
744 object->glDescription.level = Level;
746 /* Flags */
747 object->Flags = 0;
748 object->Flags |= Discard ? SFLAG_DISCARD : 0;
749 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
753 if (WINED3DFMT_UNKNOWN != Format) {
754 object->bytesPerPixel = tableEntry->bpp;
755 } else {
756 object->bytesPerPixel = 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
767 switch(Pool) {
768 case WINED3DPOOL_SCRATCH:
769 if(!Lockable)
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
772 Lockable = TRUE;
773 break;
774 case WINED3DPOOL_SYSTEMMEM:
775 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED:
778 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
781 break;
782 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
786 break;
787 default:
788 FIXME("(%p) Unknown pool %d\n", This, Pool);
789 break;
792 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This, Width, Height, Format, debug_d3dformat(Format),
800 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804 This->ddraw_primary = (IWineD3DSurface *) object;
806 /* Look at the implementation and set the correct Vtable */
807 switch(Impl) {
808 case SURFACE_OPENGL:
809 /* Check if a 3D adapter is available when creating gl surfaces */
810 if(!This->adapter) {
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813 HeapFree(GetProcessHeap(), 0, object);
814 return WINED3DERR_NOTAVAILABLE;
816 break;
818 case SURFACE_GDI:
819 object->lpVtbl = &IWineGDISurface_Vtbl;
820 break;
822 default:
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl);
825 IWineD3DSurface_Release((IWineD3DSurface *) object);
826 return WINED3DERR_INVALIDCALL;
829 list_init(&object->renderbuffers);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842 IWineD3DTextureImpl *object;
843 unsigned int i;
844 UINT tmpW;
845 UINT tmpH;
846 HRESULT hr;
847 unsigned int pow2Width;
848 unsigned int pow2Height;
849 const GlPixelFormatDesc *glDesc;
850 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
853 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
854 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
855 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
857 /* TODO: It should only be possible to create textures for formats
858 that are reported as supported */
859 if (WINED3DFMT_UNKNOWN >= Format) {
860 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
861 return WINED3DERR_INVALIDCALL;
864 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
865 D3DINITIALIZEBASETEXTURE(object->baseTexture);
866 object->width = Width;
867 object->height = Height;
869 /** Non-power2 support **/
870 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
871 pow2Width = Width;
872 pow2Height = Height;
873 } else {
874 /* Find the nearest pow2 match */
875 pow2Width = pow2Height = 1;
876 while (pow2Width < Width) pow2Width <<= 1;
877 while (pow2Height < Height) pow2Height <<= 1;
880 /** FIXME: add support for real non-power-two if it's provided by the video card **/
881 /* Precalculated scaling for 'faked' non power of two texture coords */
882 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
883 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
884 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
886 /* Calculate levels for mip mapping */
887 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
888 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
889 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
890 return WINED3DERR_INVALIDCALL;
892 if(Levels > 1) {
893 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
894 return WINED3DERR_INVALIDCALL;
896 object->baseTexture.levels = 1;
897 } else if (Levels == 0) {
898 TRACE("calculating levels %d\n", object->baseTexture.levels);
899 object->baseTexture.levels++;
900 tmpW = Width;
901 tmpH = Height;
902 while (tmpW > 1 || tmpH > 1) {
903 tmpW = max(1, tmpW >> 1);
904 tmpH = max(1, tmpH >> 1);
905 object->baseTexture.levels++;
907 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
910 /* Generate all the surfaces */
911 tmpW = Width;
912 tmpH = Height;
913 for (i = 0; i < object->baseTexture.levels; i++)
915 /* use the callback to create the texture surface */
916 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
917 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
918 FIXME("Failed to create surface %p\n", object);
919 /* clean up */
920 object->surfaces[i] = NULL;
921 IWineD3DTexture_Release((IWineD3DTexture *)object);
923 *ppTexture = NULL;
924 return hr;
927 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
928 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
929 /* calculate the next mipmap level */
930 tmpW = max(1, tmpW >> 1);
931 tmpH = max(1, tmpH >> 1);
933 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
935 TRACE("(%p) : Created texture %p\n", This, object);
936 return WINED3D_OK;
939 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
940 UINT Width, UINT Height, UINT Depth,
941 UINT Levels, DWORD Usage,
942 WINED3DFORMAT Format, WINED3DPOOL Pool,
943 IWineD3DVolumeTexture **ppVolumeTexture,
944 HANDLE *pSharedHandle, IUnknown *parent,
945 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
948 IWineD3DVolumeTextureImpl *object;
949 unsigned int i;
950 UINT tmpW;
951 UINT tmpH;
952 UINT tmpD;
953 const GlPixelFormatDesc *glDesc;
954 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
956 /* TODO: It should only be possible to create textures for formats
957 that are reported as supported */
958 if (WINED3DFMT_UNKNOWN >= Format) {
959 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
960 return WINED3DERR_INVALIDCALL;
963 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
964 D3DINITIALIZEBASETEXTURE(object->baseTexture);
966 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
967 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
969 object->width = Width;
970 object->height = Height;
971 object->depth = Depth;
973 /* Calculate levels for mip mapping */
974 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
975 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
976 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
977 return WINED3DERR_INVALIDCALL;
979 if(Levels > 1) {
980 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
981 return WINED3DERR_INVALIDCALL;
983 Levels = 1;
984 } else if (Levels == 0) {
985 object->baseTexture.levels++;
986 tmpW = Width;
987 tmpH = Height;
988 tmpD = Depth;
989 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
990 tmpW = max(1, tmpW >> 1);
991 tmpH = max(1, tmpH >> 1);
992 tmpD = max(1, tmpD >> 1);
993 object->baseTexture.levels++;
995 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
998 /* Generate all the surfaces */
999 tmpW = Width;
1000 tmpH = Height;
1001 tmpD = Depth;
1003 for (i = 0; i < object->baseTexture.levels; i++)
1005 HRESULT hr;
1006 /* Create the volume */
1007 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1008 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1010 if(FAILED(hr)) {
1011 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1012 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1013 *ppVolumeTexture = NULL;
1014 return hr;
1017 /* Set its container to this object */
1018 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1020 /* calcualte the next mipmap level */
1021 tmpW = max(1, tmpW >> 1);
1022 tmpH = max(1, tmpH >> 1);
1023 tmpD = max(1, tmpD >> 1);
1025 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1027 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1028 TRACE("(%p) : Created volume texture %p\n", This, object);
1029 return WINED3D_OK;
1032 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1033 UINT Width, UINT Height, UINT Depth,
1034 DWORD Usage,
1035 WINED3DFORMAT Format, WINED3DPOOL Pool,
1036 IWineD3DVolume** ppVolume,
1037 HANDLE* pSharedHandle, IUnknown *parent) {
1039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1040 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1041 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1043 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1045 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1046 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1048 object->currentDesc.Width = Width;
1049 object->currentDesc.Height = Height;
1050 object->currentDesc.Depth = Depth;
1051 object->bytesPerPixel = formatDesc->bpp;
1053 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1054 object->lockable = TRUE;
1055 object->locked = FALSE;
1056 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1057 object->dirty = TRUE;
1059 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1062 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1063 UINT Levels, DWORD Usage,
1064 WINED3DFORMAT Format, WINED3DPOOL Pool,
1065 IWineD3DCubeTexture **ppCubeTexture,
1066 HANDLE *pSharedHandle, IUnknown *parent,
1067 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1070 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1071 unsigned int i, j;
1072 UINT tmpW;
1073 HRESULT hr;
1074 unsigned int pow2EdgeLength = EdgeLength;
1075 const GlPixelFormatDesc *glDesc;
1076 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1078 /* TODO: It should only be possible to create textures for formats
1079 that are reported as supported */
1080 if (WINED3DFMT_UNKNOWN >= Format) {
1081 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1082 return WINED3DERR_INVALIDCALL;
1085 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1086 WARN("(%p) : Tried to create not supported cube texture\n", This);
1087 return WINED3DERR_INVALIDCALL;
1090 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1091 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1093 TRACE("(%p) Create Cube Texture\n", This);
1095 /** Non-power2 support **/
1097 /* Find the nearest pow2 match */
1098 pow2EdgeLength = 1;
1099 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1101 object->edgeLength = EdgeLength;
1102 /* TODO: support for native non-power 2 */
1103 /* Precalculated scaling for 'faked' non power of two texture coords */
1104 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1106 /* Calculate levels for mip mapping */
1107 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1108 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1109 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1110 return WINED3DERR_INVALIDCALL;
1112 if(Levels > 1) {
1113 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1114 return WINED3DERR_INVALIDCALL;
1116 Levels = 1;
1117 } else if (Levels == 0) {
1118 object->baseTexture.levels++;
1119 tmpW = EdgeLength;
1120 while (tmpW > 1) {
1121 tmpW = max(1, tmpW >> 1);
1122 object->baseTexture.levels++;
1124 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1127 /* Generate all the surfaces */
1128 tmpW = EdgeLength;
1129 for (i = 0; i < object->baseTexture.levels; i++) {
1131 /* Create the 6 faces */
1132 for (j = 0; j < 6; j++) {
1134 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1135 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1137 if(hr!= WINED3D_OK) {
1138 /* clean up */
1139 int k;
1140 int l;
1141 for (l = 0; l < j; l++) {
1142 IWineD3DSurface_Release(object->surfaces[j][i]);
1144 for (k = 0; k < i; k++) {
1145 for (l = 0; l < 6; l++) {
1146 IWineD3DSurface_Release(object->surfaces[l][j]);
1150 FIXME("(%p) Failed to create surface\n",object);
1151 HeapFree(GetProcessHeap(),0,object);
1152 *ppCubeTexture = NULL;
1153 return hr;
1155 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1156 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1158 tmpW = max(1, tmpW >> 1);
1160 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1162 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1163 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1164 return WINED3D_OK;
1167 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1169 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1170 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1172 /* Just a check to see if we support this type of query */
1173 switch(Type) {
1174 case WINED3DQUERYTYPE_OCCLUSION:
1175 TRACE("(%p) occlusion query\n", This);
1176 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1177 hr = WINED3D_OK;
1178 else
1179 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1180 break;
1182 case WINED3DQUERYTYPE_EVENT:
1183 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1184 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1185 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1187 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1189 hr = WINED3D_OK;
1190 break;
1192 case WINED3DQUERYTYPE_VCACHE:
1193 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1194 case WINED3DQUERYTYPE_VERTEXSTATS:
1195 case WINED3DQUERYTYPE_TIMESTAMP:
1196 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1197 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1198 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1199 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1200 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1201 case WINED3DQUERYTYPE_PIXELTIMINGS:
1202 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1203 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1204 default:
1205 FIXME("(%p) Unhandled query type %d\n", This, Type);
1207 if(NULL == ppQuery || hr != WINED3D_OK) {
1208 return hr;
1211 D3DCREATEOBJECTINSTANCE(object, Query)
1212 object->type = Type;
1213 /* allocated the 'extended' data based on the type of query requested */
1214 switch(Type){
1215 case WINED3DQUERYTYPE_OCCLUSION:
1216 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1217 TRACE("(%p) Allocating data for an occlusion query\n", This);
1218 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1219 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1220 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1221 break;
1223 case WINED3DQUERYTYPE_EVENT:
1224 if(GL_SUPPORT(APPLE_FENCE)) {
1225 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1226 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1227 checkGLcall("glGenFencesAPPLE");
1228 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1229 } else if(GL_SUPPORT(NV_FENCE)) {
1230 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1231 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1232 checkGLcall("glGenFencesNV");
1233 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1235 break;
1237 case WINED3DQUERYTYPE_VCACHE:
1238 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1239 case WINED3DQUERYTYPE_VERTEXSTATS:
1240 case WINED3DQUERYTYPE_TIMESTAMP:
1241 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1242 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1243 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1244 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1245 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1246 case WINED3DQUERYTYPE_PIXELTIMINGS:
1247 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1248 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1249 default:
1250 object->extendedData = 0;
1251 FIXME("(%p) Unhandled query type %d\n",This , Type);
1253 TRACE("(%p) : Created Query %p\n", This, object);
1254 return WINED3D_OK;
1257 /*****************************************************************************
1258 * IWineD3DDeviceImpl_SetupFullscreenWindow
1260 * Helper function that modifies a HWND's Style and ExStyle for proper
1261 * fullscreen use.
1263 * Params:
1264 * iface: Pointer to the IWineD3DDevice interface
1265 * window: Window to setup
1267 *****************************************************************************/
1268 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1271 LONG style, exStyle;
1272 /* Don't do anything if an original style is stored.
1273 * That shouldn't happen
1275 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1276 if (This->style || This->exStyle) {
1277 ERR("(%p): Want to change the window parameters of HWND %p, but "
1278 "another style is stored for restoration afterwards\n", This, window);
1281 /* Get the parameters and save them */
1282 style = GetWindowLongW(window, GWL_STYLE);
1283 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1284 This->style = style;
1285 This->exStyle = exStyle;
1287 /* Filter out window decorations */
1288 style &= ~WS_CAPTION;
1289 style &= ~WS_THICKFRAME;
1290 exStyle &= ~WS_EX_WINDOWEDGE;
1291 exStyle &= ~WS_EX_CLIENTEDGE;
1293 /* Make sure the window is managed, otherwise we won't get keyboard input */
1294 style |= WS_POPUP | WS_SYSMENU;
1296 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1297 This->style, This->exStyle, style, exStyle);
1299 SetWindowLongW(window, GWL_STYLE, style);
1300 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1302 /* Inform the window about the update. */
1303 SetWindowPos(window, HWND_TOP, 0, 0,
1304 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1305 ShowWindow(window, SW_NORMAL);
1308 /*****************************************************************************
1309 * IWineD3DDeviceImpl_RestoreWindow
1311 * Helper function that restores a windows' properties when taking it out
1312 * of fullscreen mode
1314 * Params:
1315 * iface: Pointer to the IWineD3DDevice interface
1316 * window: Window to setup
1318 *****************************************************************************/
1319 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1322 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1323 * switch, do nothing
1325 if (!This->style && !This->exStyle) return;
1327 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1328 This, window, This->style, This->exStyle);
1330 SetWindowLongW(window, GWL_STYLE, This->style);
1331 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1333 /* Delete the old values */
1334 This->style = 0;
1335 This->exStyle = 0;
1337 /* Inform the window about the update */
1338 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1339 0, 0, 0, 0, /* Pos, Size, ignored */
1340 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1343 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1344 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1345 IUnknown* parent,
1346 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1347 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1350 HDC hDc;
1351 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1352 HRESULT hr = WINED3D_OK;
1353 IUnknown *bufferParent;
1355 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1357 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1358 * does a device hold a reference to a swap chain giving them a lifetime of the device
1359 * or does the swap chain notify the device of its destruction.
1360 *******************************/
1362 /* Check the params */
1363 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1364 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1365 return WINED3DERR_INVALIDCALL;
1366 } else if (pPresentationParameters->BackBufferCount > 1) {
1367 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");
1370 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1372 /*********************
1373 * Lookup the window Handle and the relating X window handle
1374 ********************/
1376 /* Setup hwnd we are using, plus which display this equates to */
1377 object->win_handle = pPresentationParameters->hDeviceWindow;
1378 if (!object->win_handle) {
1379 object->win_handle = This->createParms.hFocusWindow;
1382 hDc = GetDC(object->win_handle);
1383 TRACE("Using hDc %p\n", hDc);
1385 if (NULL == hDc) {
1386 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1387 return WINED3DERR_NOTAVAILABLE;
1390 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1391 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1392 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1393 ReleaseDC(object->win_handle, hDc);
1395 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1396 * then the corresponding dimension of the client area of the hDeviceWindow
1397 * (or the focus window, if hDeviceWindow is NULL) is taken.
1398 **********************/
1400 if (pPresentationParameters->Windowed &&
1401 ((pPresentationParameters->BackBufferWidth == 0) ||
1402 (pPresentationParameters->BackBufferHeight == 0) ||
1403 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1405 RECT Rect;
1406 GetClientRect(object->win_handle, &Rect);
1408 if (pPresentationParameters->BackBufferWidth == 0) {
1409 pPresentationParameters->BackBufferWidth = Rect.right;
1410 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1412 if (pPresentationParameters->BackBufferHeight == 0) {
1413 pPresentationParameters->BackBufferHeight = Rect.bottom;
1414 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1416 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1417 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1418 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1422 /* Put the correct figures in the presentation parameters */
1423 TRACE("Copying across presentation parameters\n");
1424 object->presentParms = *pPresentationParameters;
1426 TRACE("calling rendertarget CB\n");
1427 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1428 parent,
1429 object->presentParms.BackBufferWidth,
1430 object->presentParms.BackBufferHeight,
1431 object->presentParms.BackBufferFormat,
1432 object->presentParms.MultiSampleType,
1433 object->presentParms.MultiSampleQuality,
1434 TRUE /* Lockable */,
1435 &object->frontBuffer,
1436 NULL /* pShared (always null)*/);
1437 if (object->frontBuffer != NULL) {
1438 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1439 } else {
1440 ERR("Failed to create the front buffer\n");
1441 goto error;
1445 * Create an opengl context for the display visual
1446 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1447 * use different properties after that point in time. FIXME: How to handle when requested format
1448 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1449 * it chooses is identical to the one already being used!
1450 **********************************/
1451 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1453 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1454 if(!object->context)
1455 return E_OUTOFMEMORY;
1456 object->num_contexts = 1;
1458 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1459 if (!object->context[0]) {
1460 ERR("Failed to create a new context\n");
1461 hr = WINED3DERR_NOTAVAILABLE;
1462 goto error;
1463 } else {
1464 TRACE("Context created (HWND=%p, glContext=%p)\n",
1465 object->win_handle, object->context[0]->glCtx);
1468 /*********************
1469 * Windowed / Fullscreen
1470 *******************/
1473 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1474 * so we should really check to see if there is a fullscreen swapchain already
1475 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1476 **************************************/
1478 if (!pPresentationParameters->Windowed) {
1480 DEVMODEW devmode;
1481 HDC hdc;
1482 int bpp = 0;
1483 RECT clip_rc;
1485 /* Get info on the current display setup */
1486 hdc = GetDC(0);
1487 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1488 ReleaseDC(0, hdc);
1490 /* Change the display settings */
1491 memset(&devmode, 0, sizeof(devmode));
1492 devmode.dmSize = sizeof(devmode);
1493 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1494 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1495 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1496 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1497 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1499 /* For GetDisplayMode */
1500 This->ddraw_width = devmode.dmPelsWidth;
1501 This->ddraw_height = devmode.dmPelsHeight;
1502 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1504 IWineD3DDevice_SetFullscreen(iface, TRUE);
1506 /* And finally clip mouse to our screen */
1507 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1508 ClipCursor(&clip_rc);
1511 /*********************
1512 * Create the back, front and stencil buffers
1513 *******************/
1514 if(object->presentParms.BackBufferCount > 0) {
1515 int i;
1517 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1518 if(!object->backBuffer) {
1519 ERR("Out of memory\n");
1520 hr = E_OUTOFMEMORY;
1521 goto error;
1524 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1525 TRACE("calling rendertarget CB\n");
1526 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1527 parent,
1528 object->presentParms.BackBufferWidth,
1529 object->presentParms.BackBufferHeight,
1530 object->presentParms.BackBufferFormat,
1531 object->presentParms.MultiSampleType,
1532 object->presentParms.MultiSampleQuality,
1533 TRUE /* Lockable */,
1534 &object->backBuffer[i],
1535 NULL /* pShared (always null)*/);
1536 if(hr == WINED3D_OK && object->backBuffer[i]) {
1537 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1538 } else {
1539 ERR("Cannot create new back buffer\n");
1540 goto error;
1542 ENTER_GL();
1543 glDrawBuffer(GL_BACK);
1544 checkGLcall("glDrawBuffer(GL_BACK)");
1545 LEAVE_GL();
1547 } else {
1548 object->backBuffer = NULL;
1550 /* Single buffering - draw to front buffer */
1551 ENTER_GL();
1552 glDrawBuffer(GL_FRONT);
1553 checkGLcall("glDrawBuffer(GL_FRONT)");
1554 LEAVE_GL();
1557 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1558 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1559 TRACE("Creating depth stencil buffer\n");
1560 if (This->depthStencilBuffer == NULL ) {
1561 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1562 parent,
1563 object->presentParms.BackBufferWidth,
1564 object->presentParms.BackBufferHeight,
1565 object->presentParms.AutoDepthStencilFormat,
1566 object->presentParms.MultiSampleType,
1567 object->presentParms.MultiSampleQuality,
1568 FALSE /* FIXME: Discard */,
1569 &This->depthStencilBuffer,
1570 NULL /* pShared (always null)*/ );
1571 if (This->depthStencilBuffer != NULL)
1572 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1575 /** TODO: A check on width, height and multisample types
1576 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1577 ****************************/
1578 object->wantsDepthStencilBuffer = TRUE;
1579 } else {
1580 object->wantsDepthStencilBuffer = FALSE;
1583 TRACE("Created swapchain %p\n", object);
1584 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1585 return WINED3D_OK;
1587 error:
1588 if (object->backBuffer) {
1589 int i;
1590 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1591 if(object->backBuffer[i]) {
1592 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1593 IUnknown_Release(bufferParent); /* once for the get parent */
1594 if (IUnknown_Release(bufferParent) > 0) {
1595 FIXME("(%p) Something's still holding the back buffer\n",This);
1599 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1600 object->backBuffer = NULL;
1602 if(object->context[0])
1603 DestroyContext(This, object->context[0]);
1604 if(object->frontBuffer) {
1605 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1606 IUnknown_Release(bufferParent); /* once for the get parent */
1607 if (IUnknown_Release(bufferParent) > 0) {
1608 FIXME("(%p) Something's still holding the front buffer\n",This);
1611 HeapFree(GetProcessHeap(), 0, object);
1612 return hr;
1615 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1616 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1618 TRACE("(%p)\n", This);
1620 return This->NumberOfSwapChains;
1623 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1625 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1627 if(iSwapChain < This->NumberOfSwapChains) {
1628 *pSwapChain = This->swapchains[iSwapChain];
1629 IWineD3DSwapChain_AddRef(*pSwapChain);
1630 TRACE("(%p) returning %p\n", This, *pSwapChain);
1631 return WINED3D_OK;
1632 } else {
1633 TRACE("Swapchain out of range\n");
1634 *pSwapChain = NULL;
1635 return WINED3DERR_INVALIDCALL;
1639 /*****
1640 * Vertex Declaration
1641 *****/
1642 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1643 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1645 IWineD3DVertexDeclarationImpl *object = NULL;
1646 HRESULT hr = WINED3D_OK;
1648 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1649 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1651 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1653 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1655 return hr;
1658 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1660 unsigned int idx, idx2;
1661 unsigned int offset;
1662 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1663 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1664 BOOL has_blend_idx = has_blend &&
1665 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1666 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1667 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1668 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1669 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1670 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1671 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1673 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1674 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1676 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1677 WINED3DVERTEXELEMENT *elements = NULL;
1679 unsigned int size;
1680 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1681 if (has_blend_idx) num_blends--;
1683 /* Compute declaration size */
1684 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1685 has_psize + has_diffuse + has_specular + num_textures + 1;
1687 /* convert the declaration */
1688 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1689 if (!elements)
1690 return 0;
1692 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1693 idx = 0;
1694 if (has_pos) {
1695 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1696 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1697 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1699 else {
1700 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1701 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1703 elements[idx].UsageIndex = 0;
1704 idx++;
1706 if (has_blend && (num_blends > 0)) {
1707 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1708 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1709 else
1710 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1711 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1712 elements[idx].UsageIndex = 0;
1713 idx++;
1715 if (has_blend_idx) {
1716 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1717 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1718 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1719 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1720 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1721 else
1722 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1723 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1724 elements[idx].UsageIndex = 0;
1725 idx++;
1727 if (has_normal) {
1728 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1729 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1730 elements[idx].UsageIndex = 0;
1731 idx++;
1733 if (has_psize) {
1734 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1735 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1736 elements[idx].UsageIndex = 0;
1737 idx++;
1739 if (has_diffuse) {
1740 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1741 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1742 elements[idx].UsageIndex = 0;
1743 idx++;
1745 if (has_specular) {
1746 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1747 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1748 elements[idx].UsageIndex = 1;
1749 idx++;
1751 for (idx2 = 0; idx2 < num_textures; idx2++) {
1752 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1753 switch (numcoords) {
1754 case WINED3DFVF_TEXTUREFORMAT1:
1755 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1756 break;
1757 case WINED3DFVF_TEXTUREFORMAT2:
1758 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1759 break;
1760 case WINED3DFVF_TEXTUREFORMAT3:
1761 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1762 break;
1763 case WINED3DFVF_TEXTUREFORMAT4:
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1765 break;
1767 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1768 elements[idx].UsageIndex = idx2;
1769 idx++;
1772 /* Now compute offsets, and initialize the rest of the fields */
1773 for (idx = 0, offset = 0; idx < size-1; idx++) {
1774 elements[idx].Stream = 0;
1775 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1776 elements[idx].Offset = offset;
1777 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1780 *ppVertexElements = elements;
1781 return size;
1784 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1785 WINED3DVERTEXELEMENT* elements = NULL;
1786 size_t size;
1787 DWORD hr;
1789 size = ConvertFvfToDeclaration(Fvf, &elements);
1790 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1792 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1793 HeapFree(GetProcessHeap(), 0, elements);
1794 if (hr != S_OK) return hr;
1796 return WINED3D_OK;
1799 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1800 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1802 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1803 HRESULT hr = WINED3D_OK;
1804 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1805 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1807 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1809 if (vertex_declaration) {
1810 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1813 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1815 if (WINED3D_OK != hr) {
1816 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1817 IWineD3DVertexShader_Release(*ppVertexShader);
1818 return WINED3DERR_INVALIDCALL;
1821 return WINED3D_OK;
1824 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1826 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1827 HRESULT hr = WINED3D_OK;
1829 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1830 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1831 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1832 if (WINED3D_OK == hr) {
1833 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1834 } else {
1835 WARN("(%p) : Failed to create pixel shader\n", This);
1838 return hr;
1841 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1843 IWineD3DPaletteImpl *object;
1844 HRESULT hr;
1845 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1847 /* Create the new object */
1848 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1849 if(!object) {
1850 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1851 return E_OUTOFMEMORY;
1854 object->lpVtbl = &IWineD3DPalette_Vtbl;
1855 object->ref = 1;
1856 object->Flags = Flags;
1857 object->parent = Parent;
1858 object->wineD3DDevice = This;
1859 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1861 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1863 if(!object->hpal) {
1864 HeapFree( GetProcessHeap(), 0, object);
1865 return E_OUTOFMEMORY;
1868 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1869 if(FAILED(hr)) {
1870 IWineD3DPalette_Release((IWineD3DPalette *) object);
1871 return hr;
1874 *Palette = (IWineD3DPalette *) object;
1876 return WINED3D_OK;
1879 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1880 HBITMAP hbm;
1881 BITMAP bm;
1882 HRESULT hr;
1883 HDC dcb = NULL, dcs = NULL;
1884 WINEDDCOLORKEY colorkey;
1886 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1887 if(hbm)
1889 GetObjectA(hbm, sizeof(BITMAP), &bm);
1890 dcb = CreateCompatibleDC(NULL);
1891 if(!dcb) goto out;
1892 SelectObject(dcb, hbm);
1894 else
1896 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1897 * couldn't be loaded
1899 memset(&bm, 0, sizeof(bm));
1900 bm.bmWidth = 32;
1901 bm.bmHeight = 32;
1904 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1905 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1906 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1907 if(FAILED(hr)) {
1908 ERR("Wine logo requested, but failed to create surface\n");
1909 goto out;
1912 if(dcb) {
1913 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1914 if(FAILED(hr)) goto out;
1915 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1916 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1918 colorkey.dwColorSpaceLowValue = 0;
1919 colorkey.dwColorSpaceHighValue = 0;
1920 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1921 } else {
1922 /* Fill the surface with a white color to show that wined3d is there */
1923 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1926 out:
1927 if(dcb) {
1928 DeleteDC(dcb);
1930 if(hbm) {
1931 DeleteObject(hbm);
1933 return;
1936 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1938 IWineD3DSwapChainImpl *swapchain;
1939 HRESULT hr;
1940 DWORD state;
1942 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1943 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1945 /* TODO: Test if OpenGL is compiled in and loaded */
1947 TRACE("(%p) : Creating stateblock\n", This);
1948 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1949 hr = IWineD3DDevice_CreateStateBlock(iface,
1950 WINED3DSBT_INIT,
1951 (IWineD3DStateBlock **)&This->stateBlock,
1952 NULL);
1953 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1954 WARN("Failed to create stateblock\n");
1955 return hr;
1957 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1958 This->updateStateBlock = This->stateBlock;
1959 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1961 hr = allocate_shader_constants(This->updateStateBlock);
1962 if (WINED3D_OK != hr)
1963 return hr;
1965 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1966 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1967 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1969 /* Initialize the texture unit mapping to a 1:1 mapping */
1970 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1971 if (state < GL_LIMITS(fragment_samplers)) {
1972 This->texUnitMap[state] = state;
1973 This->rev_tex_unit_map[state] = state;
1974 } else {
1975 This->texUnitMap[state] = -1;
1976 This->rev_tex_unit_map[state] = -1;
1980 /* Setup the implicit swapchain */
1981 TRACE("Creating implicit swapchain\n");
1982 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1983 if (FAILED(hr) || !swapchain) {
1984 WARN("Failed to create implicit swapchain\n");
1985 return hr;
1988 This->NumberOfSwapChains = 1;
1989 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1990 if(!This->swapchains) {
1991 ERR("Out of memory!\n");
1992 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1993 return E_OUTOFMEMORY;
1995 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1997 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1999 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2000 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2001 This->render_targets[0] = swapchain->backBuffer[0];
2002 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2004 else {
2005 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2006 This->render_targets[0] = swapchain->frontBuffer;
2007 This->lastActiveRenderTarget = swapchain->frontBuffer;
2009 IWineD3DSurface_AddRef(This->render_targets[0]);
2010 This->activeContext = swapchain->context[0];
2011 This->lastThread = GetCurrentThreadId();
2013 /* Depth Stencil support */
2014 This->stencilBufferTarget = This->depthStencilBuffer;
2015 if (NULL != This->stencilBufferTarget) {
2016 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2019 /* Set up some starting GL setup */
2020 ENTER_GL();
2022 /* Setup all the devices defaults */
2023 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2024 #if 0
2025 IWineD3DImpl_CheckGraphicsMemory();
2026 #endif
2028 { /* Set a default viewport */
2029 WINED3DVIEWPORT vp;
2030 vp.X = 0;
2031 vp.Y = 0;
2032 vp.Width = pPresentationParameters->BackBufferWidth;
2033 vp.Height = pPresentationParameters->BackBufferHeight;
2034 vp.MinZ = 0.0f;
2035 vp.MaxZ = 1.0f;
2036 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2039 /* Initialize the current view state */
2040 This->view_ident = 1;
2041 This->contexts[0]->last_was_rhw = 0;
2042 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2043 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2045 switch(wined3d_settings.offscreen_rendering_mode) {
2046 case ORM_FBO:
2047 case ORM_PBUFFER:
2048 This->offscreenBuffer = GL_BACK;
2049 break;
2051 case ORM_BACKBUFFER:
2053 if(GL_LIMITS(aux_buffers) > 0) {
2054 TRACE("Using auxilliary buffer for offscreen rendering\n");
2055 This->offscreenBuffer = GL_AUX0;
2056 } else {
2057 TRACE("Using back buffer for offscreen rendering\n");
2058 This->offscreenBuffer = GL_BACK;
2063 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2064 LEAVE_GL();
2066 /* Clear the screen */
2067 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2068 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2069 0x00, 1.0, 0);
2071 This->d3d_initialized = TRUE;
2073 if(wined3d_settings.logo) {
2074 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2076 return WINED3D_OK;
2079 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2081 int sampler;
2082 UINT i;
2083 TRACE("(%p)\n", This);
2085 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2087 /* I don't think that the interface guarants that the device is destroyed from the same thread
2088 * it was created. Thus make sure a context is active for the glDelete* calls
2090 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2092 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2094 TRACE("Deleting high order patches\n");
2095 for(i = 0; i < PATCHMAP_SIZE; i++) {
2096 struct list *e1, *e2;
2097 struct WineD3DRectPatch *patch;
2098 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2099 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2100 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2104 /* Delete the pbuffer context if there is any */
2105 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2107 /* Delete the mouse cursor texture */
2108 if(This->cursorTexture) {
2109 ENTER_GL();
2110 glDeleteTextures(1, &This->cursorTexture);
2111 LEAVE_GL();
2112 This->cursorTexture = 0;
2115 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2116 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2118 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2119 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2122 /* Release the update stateblock */
2123 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2124 if(This->updateStateBlock != This->stateBlock)
2125 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2127 This->updateStateBlock = NULL;
2129 { /* because were not doing proper internal refcounts releasing the primary state block
2130 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2131 to set this->stateBlock = NULL; first */
2132 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2133 This->stateBlock = NULL;
2135 /* Release the stateblock */
2136 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2137 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2141 /* Release the buffers (with sanity checks)*/
2142 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2143 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2144 if(This->depthStencilBuffer != This->stencilBufferTarget)
2145 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2147 This->stencilBufferTarget = NULL;
2149 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2150 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2151 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2153 TRACE("Setting rendertarget to NULL\n");
2154 This->render_targets[0] = NULL;
2156 if (This->depthStencilBuffer) {
2157 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2158 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2160 This->depthStencilBuffer = NULL;
2163 for(i=0; i < This->NumberOfSwapChains; i++) {
2164 TRACE("Releasing the implicit swapchain %d\n", i);
2165 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2166 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2170 HeapFree(GetProcessHeap(), 0, This->swapchains);
2171 This->swapchains = NULL;
2172 This->NumberOfSwapChains = 0;
2174 HeapFree(GetProcessHeap(), 0, This->render_targets);
2175 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2176 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2177 This->render_targets = NULL;
2178 This->fbo_color_attachments = NULL;
2179 This->draw_buffers = NULL;
2182 This->d3d_initialized = FALSE;
2183 return WINED3D_OK;
2186 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2188 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2190 /* Setup the window for fullscreen mode */
2191 if(fullscreen && !This->ddraw_fullscreen) {
2192 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2193 } else if(!fullscreen && This->ddraw_fullscreen) {
2194 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2197 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2198 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2199 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2200 * separately.
2202 This->ddraw_fullscreen = fullscreen;
2205 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2206 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2207 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2209 * There is no way to deactivate thread safety once it is enabled
2211 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2214 /*For now just store the flag(needed in case of ddraw) */
2215 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2217 return;
2220 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2221 DEVMODEW devmode;
2222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2223 LONG ret;
2224 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2225 RECT clip_rc;
2227 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2229 /* Resize the screen even without a window:
2230 * The app could have unset it with SetCooperativeLevel, but not called
2231 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2232 * but we don't have any hwnd
2235 memset(&devmode, 0, sizeof(devmode));
2236 devmode.dmSize = sizeof(devmode);
2237 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2238 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2239 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2240 devmode.dmPelsWidth = pMode->Width;
2241 devmode.dmPelsHeight = pMode->Height;
2243 devmode.dmDisplayFrequency = pMode->RefreshRate;
2244 if (pMode->RefreshRate != 0) {
2245 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2248 /* Only change the mode if necessary */
2249 if( (This->ddraw_width == pMode->Width) &&
2250 (This->ddraw_height == pMode->Height) &&
2251 (This->ddraw_format == pMode->Format) &&
2252 (pMode->RefreshRate == 0) ) {
2253 return WINED3D_OK;
2256 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2257 if (ret != DISP_CHANGE_SUCCESSFUL) {
2258 if(devmode.dmDisplayFrequency != 0) {
2259 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2260 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2261 devmode.dmDisplayFrequency = 0;
2262 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2264 if(ret != DISP_CHANGE_SUCCESSFUL) {
2265 return WINED3DERR_NOTAVAILABLE;
2269 /* Store the new values */
2270 This->ddraw_width = pMode->Width;
2271 This->ddraw_height = pMode->Height;
2272 This->ddraw_format = pMode->Format;
2274 /* Only do this with a window of course */
2275 if(This->ddraw_window)
2276 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2278 /* And finally clip mouse to our screen */
2279 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2280 ClipCursor(&clip_rc);
2282 return WINED3D_OK;
2285 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2287 *ppD3D= This->wineD3D;
2288 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2289 IWineD3D_AddRef(*ppD3D);
2290 return WINED3D_OK;
2293 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2296 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2297 (This->adapter->TextureRam/(1024*1024)),
2298 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2299 /* return simulated texture memory left */
2300 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2305 /*****
2306 * Get / Set FVF
2307 *****/
2308 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2311 /* Update the current state block */
2312 This->updateStateBlock->changed.fvf = TRUE;
2314 if(This->updateStateBlock->fvf == fvf) {
2315 TRACE("Application is setting the old fvf over, nothing to do\n");
2316 return WINED3D_OK;
2319 This->updateStateBlock->fvf = fvf;
2320 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2322 return WINED3D_OK;
2326 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2328 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2329 *pfvf = This->stateBlock->fvf;
2330 return WINED3D_OK;
2333 /*****
2334 * Get / Set Stream Source
2335 *****/
2336 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2338 IWineD3DVertexBuffer *oldSrc;
2340 if (StreamNumber >= MAX_STREAMS) {
2341 WARN("Stream out of range %d\n", StreamNumber);
2342 return WINED3DERR_INVALIDCALL;
2345 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2346 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2348 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2350 if(oldSrc == pStreamData &&
2351 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2352 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2353 TRACE("Application is setting the old values over, nothing to do\n");
2354 return WINED3D_OK;
2357 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2358 if (pStreamData) {
2359 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2360 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2363 /* Handle recording of state blocks */
2364 if (This->isRecordingState) {
2365 TRACE("Recording... not performing anything\n");
2366 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2367 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2368 return WINED3D_OK;
2371 /* Need to do a getParent and pass the reffs up */
2372 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2373 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2374 so for now, just count internally */
2375 if (pStreamData != NULL) {
2376 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2377 InterlockedIncrement(&vbImpl->bindCount);
2378 IWineD3DVertexBuffer_AddRef(pStreamData);
2380 if (oldSrc != NULL) {
2381 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2382 IWineD3DVertexBuffer_Release(oldSrc);
2385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2387 return WINED3D_OK;
2390 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2393 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2394 This->stateBlock->streamSource[StreamNumber],
2395 This->stateBlock->streamOffset[StreamNumber],
2396 This->stateBlock->streamStride[StreamNumber]);
2398 if (StreamNumber >= MAX_STREAMS) {
2399 WARN("Stream out of range %d\n", StreamNumber);
2400 return WINED3DERR_INVALIDCALL;
2402 *pStream = This->stateBlock->streamSource[StreamNumber];
2403 *pStride = This->stateBlock->streamStride[StreamNumber];
2404 if (pOffset) {
2405 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2408 if (*pStream != NULL) {
2409 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2411 return WINED3D_OK;
2414 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2416 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2417 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2419 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2420 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2422 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2423 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2425 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2426 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2430 return WINED3D_OK;
2433 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2436 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2437 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2439 TRACE("(%p) : returning %d\n", This, *Divider);
2441 return WINED3D_OK;
2444 /*****
2445 * Get / Set & Multiply Transform
2446 *****/
2447 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2450 /* Most of this routine, comments included copied from ddraw tree initially: */
2451 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2453 /* Handle recording of state blocks */
2454 if (This->isRecordingState) {
2455 TRACE("Recording... not performing anything\n");
2456 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2457 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2458 return WINED3D_OK;
2462 * If the new matrix is the same as the current one,
2463 * we cut off any further processing. this seems to be a reasonable
2464 * optimization because as was noticed, some apps (warcraft3 for example)
2465 * tend towards setting the same matrix repeatedly for some reason.
2467 * From here on we assume that the new matrix is different, wherever it matters.
2469 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2470 TRACE("The app is setting the same matrix over again\n");
2471 return WINED3D_OK;
2472 } else {
2473 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2477 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2478 where ViewMat = Camera space, WorldMat = world space.
2480 In OpenGL, camera and world space is combined into GL_MODELVIEW
2481 matrix. The Projection matrix stay projection matrix.
2484 /* Capture the times we can just ignore the change for now */
2485 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2486 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2487 /* Handled by the state manager */
2490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2491 return WINED3D_OK;
2494 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2496 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2497 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2498 return WINED3D_OK;
2501 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2502 WINED3DMATRIX *mat = NULL;
2503 WINED3DMATRIX temp;
2505 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2506 * below means it will be recorded in a state block change, but it
2507 * works regardless where it is recorded.
2508 * If this is found to be wrong, change to StateBlock.
2510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2513 if (State < HIGHEST_TRANSFORMSTATE)
2515 mat = &This->updateStateBlock->transforms[State];
2516 } else {
2517 FIXME("Unhandled transform state!!\n");
2520 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2522 /* Apply change via set transform - will reapply to eg. lights this way */
2523 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2526 /*****
2527 * Get / Set Light
2528 *****/
2529 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2530 you can reference any indexes you want as long as that number max are enabled at any
2531 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2532 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2533 but when recording, just build a chain pretty much of commands to be replayed. */
2535 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2536 float rho;
2537 PLIGHTINFOEL *object = NULL;
2538 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2539 struct list *e;
2541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2544 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2545 * the gl driver.
2547 if(!pLight) {
2548 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2549 return WINED3DERR_INVALIDCALL;
2552 switch(pLight->Type) {
2553 case WINED3DLIGHT_POINT:
2554 case WINED3DLIGHT_SPOT:
2555 case WINED3DLIGHT_PARALLELPOINT:
2556 case WINED3DLIGHT_GLSPOT:
2557 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2558 * most wanted
2560 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2561 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2562 return WINED3DERR_INVALIDCALL;
2564 break;
2566 case WINED3DLIGHT_DIRECTIONAL:
2567 /* Ignores attenuation */
2568 break;
2570 default:
2571 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2572 return WINED3DERR_INVALIDCALL;
2575 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2576 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2577 if(object->OriginalIndex == Index) break;
2578 object = NULL;
2581 if(!object) {
2582 TRACE("Adding new light\n");
2583 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2584 if(!object) {
2585 ERR("Out of memory error when allocating a light\n");
2586 return E_OUTOFMEMORY;
2588 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2589 object->glIndex = -1;
2590 object->OriginalIndex = Index;
2591 object->changed = TRUE;
2594 /* Initialize the object */
2595 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,
2596 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2597 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2598 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2599 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2600 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2601 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2603 /* Save away the information */
2604 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2606 switch (pLight->Type) {
2607 case WINED3DLIGHT_POINT:
2608 /* Position */
2609 object->lightPosn[0] = pLight->Position.x;
2610 object->lightPosn[1] = pLight->Position.y;
2611 object->lightPosn[2] = pLight->Position.z;
2612 object->lightPosn[3] = 1.0f;
2613 object->cutoff = 180.0f;
2614 /* FIXME: Range */
2615 break;
2617 case WINED3DLIGHT_DIRECTIONAL:
2618 /* Direction */
2619 object->lightPosn[0] = -pLight->Direction.x;
2620 object->lightPosn[1] = -pLight->Direction.y;
2621 object->lightPosn[2] = -pLight->Direction.z;
2622 object->lightPosn[3] = 0.0;
2623 object->exponent = 0.0f;
2624 object->cutoff = 180.0f;
2625 break;
2627 case WINED3DLIGHT_SPOT:
2628 /* Position */
2629 object->lightPosn[0] = pLight->Position.x;
2630 object->lightPosn[1] = pLight->Position.y;
2631 object->lightPosn[2] = pLight->Position.z;
2632 object->lightPosn[3] = 1.0;
2634 /* Direction */
2635 object->lightDirn[0] = pLight->Direction.x;
2636 object->lightDirn[1] = pLight->Direction.y;
2637 object->lightDirn[2] = pLight->Direction.z;
2638 object->lightDirn[3] = 1.0;
2641 * opengl-ish and d3d-ish spot lights use too different models for the
2642 * light "intensity" as a function of the angle towards the main light direction,
2643 * so we only can approximate very roughly.
2644 * however spot lights are rather rarely used in games (if ever used at all).
2645 * furthermore if still used, probably nobody pays attention to such details.
2647 if (pLight->Falloff == 0) {
2648 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2649 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2650 * will always be 1.0 for both of them, and we don't have to care for the
2651 * rest of the rather complex calculation
2653 object->exponent = 0;
2654 } else {
2655 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2656 if (rho < 0.0001) rho = 0.0001f;
2657 object->exponent = -0.3/log(cos(rho/2));
2659 if (object->exponent > 128.0) {
2660 object->exponent = 128.0;
2662 object->cutoff = pLight->Phi*90/M_PI;
2664 /* FIXME: Range */
2665 break;
2667 default:
2668 FIXME("Unrecognized light type %d\n", pLight->Type);
2671 /* Update the live definitions if the light is currently assigned a glIndex */
2672 if (object->glIndex != -1 && !This->isRecordingState) {
2673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2675 return WINED3D_OK;
2678 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2679 PLIGHTINFOEL *lightInfo = NULL;
2680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2681 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2682 struct list *e;
2683 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2685 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2686 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2687 if(lightInfo->OriginalIndex == Index) break;
2688 lightInfo = NULL;
2691 if (lightInfo == NULL) {
2692 TRACE("Light information requested but light not defined\n");
2693 return WINED3DERR_INVALIDCALL;
2696 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2697 return WINED3D_OK;
2700 /*****
2701 * Get / Set Light Enable
2702 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2703 *****/
2704 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2705 PLIGHTINFOEL *lightInfo = NULL;
2706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2707 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2708 struct list *e;
2709 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2711 /* Tests show true = 128...not clear why */
2712 Enable = Enable? 128: 0;
2714 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2715 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2716 if(lightInfo->OriginalIndex == Index) break;
2717 lightInfo = NULL;
2719 TRACE("Found light: %p\n", lightInfo);
2721 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2722 if (lightInfo == NULL) {
2724 TRACE("Light enabled requested but light not defined, so defining one!\n");
2725 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2727 /* Search for it again! Should be fairly quick as near head of list */
2728 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2729 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2730 if(lightInfo->OriginalIndex == Index) break;
2731 lightInfo = NULL;
2733 if (lightInfo == NULL) {
2734 FIXME("Adding default lights has failed dismally\n");
2735 return WINED3DERR_INVALIDCALL;
2739 lightInfo->enabledChanged = TRUE;
2740 if(!Enable) {
2741 if(lightInfo->glIndex != -1) {
2742 if(!This->isRecordingState) {
2743 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2746 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2747 lightInfo->glIndex = -1;
2748 } else {
2749 TRACE("Light already disabled, nothing to do\n");
2751 } else {
2752 if (lightInfo->glIndex != -1) {
2753 /* nop */
2754 TRACE("Nothing to do as light was enabled\n");
2755 } else {
2756 int i;
2757 /* Find a free gl light */
2758 for(i = 0; i < This->maxConcurrentLights; i++) {
2759 if(This->stateBlock->activeLights[i] == NULL) {
2760 This->stateBlock->activeLights[i] = lightInfo;
2761 lightInfo->glIndex = i;
2762 break;
2765 if(lightInfo->glIndex == -1) {
2766 ERR("Too many concurrently active lights\n");
2767 return WINED3DERR_INVALIDCALL;
2770 /* i == lightInfo->glIndex */
2771 if(!This->isRecordingState) {
2772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2777 return WINED3D_OK;
2780 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2782 PLIGHTINFOEL *lightInfo = NULL;
2783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2784 struct list *e;
2785 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2786 TRACE("(%p) : for idx(%d)\n", This, Index);
2788 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2789 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2790 if(lightInfo->OriginalIndex == Index) break;
2791 lightInfo = NULL;
2794 if (lightInfo == NULL) {
2795 TRACE("Light enabled state requested but light not defined\n");
2796 return WINED3DERR_INVALIDCALL;
2798 /* true is 128 according to SetLightEnable */
2799 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2800 return WINED3D_OK;
2803 /*****
2804 * Get / Set Clip Planes
2805 *****/
2806 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2810 /* Validate Index */
2811 if (Index >= GL_LIMITS(clipplanes)) {
2812 TRACE("Application has requested clipplane this device doesn't support\n");
2813 return WINED3DERR_INVALIDCALL;
2816 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2818 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2819 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2820 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2821 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2822 TRACE("Application is setting old values over, nothing to do\n");
2823 return WINED3D_OK;
2826 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2827 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2828 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2829 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2831 /* Handle recording of state blocks */
2832 if (This->isRecordingState) {
2833 TRACE("Recording... not performing anything\n");
2834 return WINED3D_OK;
2837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2839 return WINED3D_OK;
2842 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2844 TRACE("(%p) : for idx %d\n", This, Index);
2846 /* Validate Index */
2847 if (Index >= GL_LIMITS(clipplanes)) {
2848 TRACE("Application has requested clipplane this device doesn't support\n");
2849 return WINED3DERR_INVALIDCALL;
2852 pPlane[0] = This->stateBlock->clipplane[Index][0];
2853 pPlane[1] = This->stateBlock->clipplane[Index][1];
2854 pPlane[2] = This->stateBlock->clipplane[Index][2];
2855 pPlane[3] = This->stateBlock->clipplane[Index][3];
2856 return WINED3D_OK;
2859 /*****
2860 * Get / Set Clip Plane Status
2861 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2862 *****/
2863 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2865 FIXME("(%p) : stub\n", This);
2866 if (NULL == pClipStatus) {
2867 return WINED3DERR_INVALIDCALL;
2869 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2870 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2871 return WINED3D_OK;
2874 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2876 FIXME("(%p) : stub\n", This);
2877 if (NULL == pClipStatus) {
2878 return WINED3DERR_INVALIDCALL;
2880 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2881 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2882 return WINED3D_OK;
2885 /*****
2886 * Get / Set Material
2887 *****/
2888 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2891 This->updateStateBlock->changed.material = TRUE;
2892 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2894 /* Handle recording of state blocks */
2895 if (This->isRecordingState) {
2896 TRACE("Recording... not performing anything\n");
2897 return WINED3D_OK;
2900 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2901 return WINED3D_OK;
2904 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2906 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2907 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2908 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2909 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2910 pMaterial->Ambient.b, pMaterial->Ambient.a);
2911 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2912 pMaterial->Specular.b, pMaterial->Specular.a);
2913 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2914 pMaterial->Emissive.b, pMaterial->Emissive.a);
2915 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2917 return WINED3D_OK;
2920 /*****
2921 * Get / Set Indices
2922 *****/
2923 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2925 IWineD3DIndexBuffer *oldIdxs;
2927 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2928 oldIdxs = This->updateStateBlock->pIndexData;
2930 This->updateStateBlock->changed.indices = TRUE;
2931 This->updateStateBlock->pIndexData = pIndexData;
2933 /* Handle recording of state blocks */
2934 if (This->isRecordingState) {
2935 TRACE("Recording... not performing anything\n");
2936 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2937 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2938 return WINED3D_OK;
2941 if(oldIdxs != pIndexData) {
2942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2943 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2944 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2946 return WINED3D_OK;
2949 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 *ppIndexData = This->stateBlock->pIndexData;
2954 /* up ref count on ppindexdata */
2955 if (*ppIndexData) {
2956 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2957 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2958 }else{
2959 TRACE("(%p) No index data set\n", This);
2961 TRACE("Returning %p\n", *ppIndexData);
2963 return WINED3D_OK;
2966 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2967 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2969 TRACE("(%p)->(%d)\n", This, BaseIndex);
2971 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2972 TRACE("Application is setting the old value over, nothing to do\n");
2973 return WINED3D_OK;
2976 This->updateStateBlock->baseVertexIndex = BaseIndex;
2978 if (This->isRecordingState) {
2979 TRACE("Recording... not performing anything\n");
2980 return WINED3D_OK;
2982 /* The base vertex index affects the stream sources */
2983 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2984 return WINED3D_OK;
2987 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2989 TRACE("(%p) : base_index %p\n", This, base_index);
2991 *base_index = This->stateBlock->baseVertexIndex;
2993 TRACE("Returning %u\n", *base_index);
2995 return WINED3D_OK;
2998 /*****
2999 * Get / Set Viewports
3000 *****/
3001 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p)\n", This);
3005 This->updateStateBlock->changed.viewport = TRUE;
3006 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3008 /* Handle recording of state blocks */
3009 if (This->isRecordingState) {
3010 TRACE("Recording... not performing anything\n");
3011 return WINED3D_OK;
3014 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3015 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3017 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3018 return WINED3D_OK;
3022 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 TRACE("(%p)\n", This);
3025 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3026 return WINED3D_OK;
3029 /*****
3030 * Get / Set Render States
3031 * TODO: Verify against dx9 definitions
3032 *****/
3033 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 DWORD oldValue = This->stateBlock->renderState[State];
3038 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3040 This->updateStateBlock->changed.renderState[State] = TRUE;
3041 This->updateStateBlock->renderState[State] = Value;
3043 /* Handle recording of state blocks */
3044 if (This->isRecordingState) {
3045 TRACE("Recording... not performing anything\n");
3046 return WINED3D_OK;
3049 /* Compared here and not before the assignment to allow proper stateblock recording */
3050 if(Value == oldValue) {
3051 TRACE("Application is setting the old value over, nothing to do\n");
3052 } else {
3053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3056 return WINED3D_OK;
3059 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3061 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3062 *pValue = This->stateBlock->renderState[State];
3063 return WINED3D_OK;
3066 /*****
3067 * Get / Set Sampler States
3068 * TODO: Verify against dx9 definitions
3069 *****/
3071 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3073 DWORD oldValue;
3075 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3076 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3078 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3079 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3083 * SetSampler is designed to allow for more than the standard up to 8 textures
3084 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3085 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3087 * http://developer.nvidia.com/object/General_FAQ.html#t6
3089 * There are two new settings for GForce
3090 * the sampler one:
3091 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3092 * and the texture one:
3093 * GL_MAX_TEXTURE_COORDS_ARB.
3094 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3095 ******************/
3097 oldValue = This->stateBlock->samplerState[Sampler][Type];
3098 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3099 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3101 /* Handle recording of state blocks */
3102 if (This->isRecordingState) {
3103 TRACE("Recording... not performing anything\n");
3104 return WINED3D_OK;
3107 if(oldValue == Value) {
3108 TRACE("Application is setting the old value over, nothing to do\n");
3109 return WINED3D_OK;
3112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3114 return WINED3D_OK;
3117 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3120 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3121 This, Sampler, debug_d3dsamplerstate(Type), Type);
3123 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3124 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3127 *Value = This->stateBlock->samplerState[Sampler][Type];
3128 TRACE("(%p) : Returning %#x\n", This, *Value);
3130 return WINED3D_OK;
3133 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 This->updateStateBlock->changed.scissorRect = TRUE;
3137 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3138 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3139 return WINED3D_OK;
3141 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3143 if(This->isRecordingState) {
3144 TRACE("Recording... not performing anything\n");
3145 return WINED3D_OK;
3148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3150 return WINED3D_OK;
3153 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3157 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3158 return WINED3D_OK;
3161 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3163 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3165 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3167 This->updateStateBlock->vertexDecl = pDecl;
3168 This->updateStateBlock->changed.vertexDecl = TRUE;
3170 if (This->isRecordingState) {
3171 TRACE("Recording... not performing anything\n");
3172 return WINED3D_OK;
3173 } else if(pDecl == oldDecl) {
3174 /* Checked after the assignment to allow proper stateblock recording */
3175 TRACE("Application is setting the old declaration over, nothing to do\n");
3176 return WINED3D_OK;
3179 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3180 return WINED3D_OK;
3183 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3186 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3188 *ppDecl = This->stateBlock->vertexDecl;
3189 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3190 return WINED3D_OK;
3193 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3195 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3197 This->updateStateBlock->vertexShader = pShader;
3198 This->updateStateBlock->changed.vertexShader = TRUE;
3200 if (This->isRecordingState) {
3201 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3202 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3203 TRACE("Recording... not performing anything\n");
3204 return WINED3D_OK;
3205 } else if(oldShader == pShader) {
3206 /* Checked here to allow proper stateblock recording */
3207 TRACE("App is setting the old shader over, nothing to do\n");
3208 return WINED3D_OK;
3211 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3212 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3213 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3217 return WINED3D_OK;
3220 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3223 if (NULL == ppShader) {
3224 return WINED3DERR_INVALIDCALL;
3226 *ppShader = This->stateBlock->vertexShader;
3227 if( NULL != *ppShader)
3228 IWineD3DVertexShader_AddRef(*ppShader);
3230 TRACE("(%p) : returning %p\n", This, *ppShader);
3231 return WINED3D_OK;
3234 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3235 IWineD3DDevice *iface,
3236 UINT start,
3237 CONST BOOL *srcData,
3238 UINT count) {
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3241 int i, cnt = min(count, MAX_CONST_B - start);
3243 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3244 iface, srcData, start, count);
3246 if (srcData == NULL || cnt < 0)
3247 return WINED3DERR_INVALIDCALL;
3249 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3250 for (i = 0; i < cnt; i++)
3251 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3253 for (i = start; i < cnt + start; ++i) {
3254 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3259 return WINED3D_OK;
3262 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3263 IWineD3DDevice *iface,
3264 UINT start,
3265 BOOL *dstData,
3266 UINT count) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3269 int cnt = min(count, MAX_CONST_B - start);
3271 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3272 iface, dstData, start, count);
3274 if (dstData == NULL || cnt < 0)
3275 return WINED3DERR_INVALIDCALL;
3277 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3278 return WINED3D_OK;
3281 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3282 IWineD3DDevice *iface,
3283 UINT start,
3284 CONST int *srcData,
3285 UINT count) {
3287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3288 int i, cnt = min(count, MAX_CONST_I - start);
3290 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3291 iface, srcData, start, count);
3293 if (srcData == NULL || cnt < 0)
3294 return WINED3DERR_INVALIDCALL;
3296 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3297 for (i = 0; i < cnt; i++)
3298 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3299 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3301 for (i = start; i < cnt + start; ++i) {
3302 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3307 return WINED3D_OK;
3310 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3311 IWineD3DDevice *iface,
3312 UINT start,
3313 int *dstData,
3314 UINT count) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3317 int cnt = min(count, MAX_CONST_I - start);
3319 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3320 iface, dstData, start, count);
3322 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3323 return WINED3DERR_INVALIDCALL;
3325 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3326 return WINED3D_OK;
3329 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3330 IWineD3DDevice *iface,
3331 UINT start,
3332 CONST float *srcData,
3333 UINT count) {
3335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3336 int i;
3338 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3339 iface, srcData, start, count);
3341 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3342 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3343 return WINED3DERR_INVALIDCALL;
3345 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3346 if(TRACE_ON(d3d)) {
3347 for (i = 0; i < count; i++)
3348 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3349 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3352 for (i = start; i < count + start; ++i) {
3353 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3354 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3355 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3356 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3357 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3359 ptr->idx[ptr->count++] = i;
3360 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3366 return WINED3D_OK;
3369 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3370 IWineD3DDevice *iface,
3371 UINT start,
3372 float *dstData,
3373 UINT count) {
3375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3378 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3379 iface, dstData, start, count);
3381 if (dstData == NULL || cnt < 0)
3382 return WINED3DERR_INVALIDCALL;
3384 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3385 return WINED3D_OK;
3388 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3389 DWORD i;
3390 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3395 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3396 int i = This->rev_tex_unit_map[unit];
3397 int j = This->texUnitMap[stage];
3399 This->texUnitMap[stage] = unit;
3400 if (i != -1 && i != stage) {
3401 This->texUnitMap[i] = -1;
3404 This->rev_tex_unit_map[unit] = stage;
3405 if (j != -1 && j != unit) {
3406 This->rev_tex_unit_map[j] = -1;
3410 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3411 int i;
3413 for (i = 0; i < MAX_TEXTURES; ++i) {
3414 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3415 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3416 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3417 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3418 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3419 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3420 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3421 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3423 if (color_op == WINED3DTOP_DISABLE) {
3424 /* Not used, and disable higher stages */
3425 while (i < MAX_TEXTURES) {
3426 This->fixed_function_usage_map[i] = FALSE;
3427 ++i;
3429 break;
3432 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3433 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3434 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3435 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3436 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3437 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3438 This->fixed_function_usage_map[i] = TRUE;
3439 } else {
3440 This->fixed_function_usage_map[i] = FALSE;
3443 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3444 This->fixed_function_usage_map[i+1] = TRUE;
3449 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3450 int i, tex;
3452 device_update_fixed_function_usage_map(This);
3454 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3455 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3456 if (!This->fixed_function_usage_map[i]) continue;
3458 if (This->texUnitMap[i] != i) {
3459 device_map_stage(This, i, i);
3460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3461 markTextureStagesDirty(This, i);
3464 return;
3467 /* Now work out the mapping */
3468 tex = 0;
3469 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3470 if (!This->fixed_function_usage_map[i]) continue;
3472 if (This->texUnitMap[i] != tex) {
3473 device_map_stage(This, i, tex);
3474 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3475 markTextureStagesDirty(This, i);
3478 ++tex;
3482 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3483 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3484 int i;
3486 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3487 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3488 device_map_stage(This, i, i);
3489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3490 if (i < MAX_TEXTURES) {
3491 markTextureStagesDirty(This, i);
3497 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3498 int current_mapping = This->rev_tex_unit_map[unit];
3500 if (current_mapping == -1) {
3501 /* Not currently used */
3502 return TRUE;
3505 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3506 /* Used by a fragment sampler */
3508 if (!pshader_sampler_tokens) {
3509 /* No pixel shader, check fixed function */
3510 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3513 /* Pixel shader, check the shader's sampler map */
3514 return !pshader_sampler_tokens[current_mapping];
3517 /* Used by a vertex sampler */
3518 return !vshader_sampler_tokens[current_mapping];
3521 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3522 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3523 DWORD *pshader_sampler_tokens = NULL;
3524 int start = GL_LIMITS(combined_samplers) - 1;
3525 int i;
3527 if (ps) {
3528 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3530 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3531 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3532 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3535 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3536 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3537 if (vshader_sampler_tokens[i]) {
3538 if (This->texUnitMap[vsampler_idx] != -1) {
3539 /* Already mapped somewhere */
3540 continue;
3543 while (start >= 0) {
3544 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3545 device_map_stage(This, vsampler_idx, start);
3546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3548 --start;
3549 break;
3552 --start;
3558 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3559 BOOL vs = use_vs(This);
3560 BOOL ps = use_ps(This);
3562 * Rules are:
3563 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3564 * that would be really messy and require shader recompilation
3565 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3566 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3568 if (ps) {
3569 device_map_psamplers(This);
3570 } else {
3571 device_map_fixed_function_samplers(This);
3574 if (vs) {
3575 device_map_vsamplers(This, ps);
3579 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3581 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3582 This->updateStateBlock->pixelShader = pShader;
3583 This->updateStateBlock->changed.pixelShader = TRUE;
3585 /* Handle recording of state blocks */
3586 if (This->isRecordingState) {
3587 TRACE("Recording... not performing anything\n");
3590 if (This->isRecordingState) {
3591 TRACE("Recording... not performing anything\n");
3592 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3593 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3594 return WINED3D_OK;
3597 if(pShader == oldShader) {
3598 TRACE("App is setting the old pixel shader over, nothing to do\n");
3599 return WINED3D_OK;
3602 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3603 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3605 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3608 return WINED3D_OK;
3611 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3614 if (NULL == ppShader) {
3615 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3616 return WINED3DERR_INVALIDCALL;
3619 *ppShader = This->stateBlock->pixelShader;
3620 if (NULL != *ppShader) {
3621 IWineD3DPixelShader_AddRef(*ppShader);
3623 TRACE("(%p) : returning %p\n", This, *ppShader);
3624 return WINED3D_OK;
3627 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3628 IWineD3DDevice *iface,
3629 UINT start,
3630 CONST BOOL *srcData,
3631 UINT count) {
3633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3634 int i, cnt = min(count, MAX_CONST_B - start);
3636 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3637 iface, srcData, start, count);
3639 if (srcData == NULL || cnt < 0)
3640 return WINED3DERR_INVALIDCALL;
3642 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3643 for (i = 0; i < cnt; i++)
3644 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3646 for (i = start; i < cnt + start; ++i) {
3647 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3652 return WINED3D_OK;
3655 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3656 IWineD3DDevice *iface,
3657 UINT start,
3658 BOOL *dstData,
3659 UINT count) {
3661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3662 int cnt = min(count, MAX_CONST_B - start);
3664 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3665 iface, dstData, start, count);
3667 if (dstData == NULL || cnt < 0)
3668 return WINED3DERR_INVALIDCALL;
3670 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3671 return WINED3D_OK;
3674 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3675 IWineD3DDevice *iface,
3676 UINT start,
3677 CONST int *srcData,
3678 UINT count) {
3680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3681 int i, cnt = min(count, MAX_CONST_I - start);
3683 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3684 iface, srcData, start, count);
3686 if (srcData == NULL || cnt < 0)
3687 return WINED3DERR_INVALIDCALL;
3689 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3690 for (i = 0; i < cnt; i++)
3691 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3692 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3694 for (i = start; i < cnt + start; ++i) {
3695 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3700 return WINED3D_OK;
3703 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3704 IWineD3DDevice *iface,
3705 UINT start,
3706 int *dstData,
3707 UINT count) {
3709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3710 int cnt = min(count, MAX_CONST_I - start);
3712 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3713 iface, dstData, start, count);
3715 if (dstData == NULL || cnt < 0)
3716 return WINED3DERR_INVALIDCALL;
3718 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3719 return WINED3D_OK;
3722 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3723 IWineD3DDevice *iface,
3724 UINT start,
3725 CONST float *srcData,
3726 UINT count) {
3728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3729 int i;
3731 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3732 iface, srcData, start, count);
3734 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3735 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3736 return WINED3DERR_INVALIDCALL;
3738 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3739 if(TRACE_ON(d3d)) {
3740 for (i = 0; i < count; i++)
3741 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3742 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3745 for (i = start; i < count + start; ++i) {
3746 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3747 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3748 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3749 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3750 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3752 ptr->idx[ptr->count++] = i;
3753 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3757 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3759 return WINED3D_OK;
3762 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3763 IWineD3DDevice *iface,
3764 UINT start,
3765 float *dstData,
3766 UINT count) {
3768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3769 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3771 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3772 iface, dstData, start, count);
3774 if (dstData == NULL || cnt < 0)
3775 return WINED3DERR_INVALIDCALL;
3777 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3778 return WINED3D_OK;
3781 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3782 static HRESULT
3783 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3784 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3785 unsigned int i;
3786 DWORD DestFVF = dest->fvf;
3787 WINED3DVIEWPORT vp;
3788 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3789 BOOL doClip;
3790 int numTextures;
3792 if (lpStrideData->u.s.normal.lpData) {
3793 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3796 if (lpStrideData->u.s.position.lpData == NULL) {
3797 ERR("Source has no position mask\n");
3798 return WINED3DERR_INVALIDCALL;
3801 /* We might access VBOs from this code, so hold the lock */
3802 ENTER_GL();
3804 if (dest->resource.allocatedMemory == NULL) {
3805 /* This may happen if we do direct locking into a vbo. Unlikely,
3806 * but theoretically possible(ddraw processvertices test)
3808 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3809 if(!dest->resource.allocatedMemory) {
3810 LEAVE_GL();
3811 ERR("Out of memory\n");
3812 return E_OUTOFMEMORY;
3814 if(dest->vbo) {
3815 void *src;
3816 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3817 checkGLcall("glBindBufferARB");
3818 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3819 if(src) {
3820 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3822 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3823 checkGLcall("glUnmapBufferARB");
3827 /* Get a pointer into the destination vbo(create one if none exists) and
3828 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3830 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3831 CreateVBO(dest);
3834 if(dest->vbo) {
3835 unsigned char extrabytes = 0;
3836 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3837 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3838 * this may write 4 extra bytes beyond the area that should be written
3840 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3841 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3842 if(!dest_conv_addr) {
3843 ERR("Out of memory\n");
3844 /* Continue without storing converted vertices */
3846 dest_conv = dest_conv_addr;
3849 /* Should I clip?
3850 * a) WINED3DRS_CLIPPING is enabled
3851 * b) WINED3DVOP_CLIP is passed
3853 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3854 static BOOL warned = FALSE;
3856 * The clipping code is not quite correct. Some things need
3857 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3858 * so disable clipping for now.
3859 * (The graphics in Half-Life are broken, and my processvertices
3860 * test crashes with IDirect3DDevice3)
3861 doClip = TRUE;
3863 doClip = FALSE;
3864 if(!warned) {
3865 warned = TRUE;
3866 FIXME("Clipping is broken and disabled for now\n");
3868 } else doClip = FALSE;
3869 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3871 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3872 WINED3DTS_VIEW,
3873 &view_mat);
3874 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3875 WINED3DTS_PROJECTION,
3876 &proj_mat);
3877 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3878 WINED3DTS_WORLDMATRIX(0),
3879 &world_mat);
3881 TRACE("View mat:\n");
3882 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);
3883 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);
3884 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);
3885 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);
3887 TRACE("Proj mat:\n");
3888 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);
3889 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);
3890 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);
3891 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);
3893 TRACE("World mat:\n");
3894 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);
3895 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);
3896 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);
3897 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);
3899 /* Get the viewport */
3900 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3901 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3902 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3904 multiply_matrix(&mat,&view_mat,&world_mat);
3905 multiply_matrix(&mat,&proj_mat,&mat);
3907 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3909 for (i = 0; i < dwCount; i+= 1) {
3910 unsigned int tex_index;
3912 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3913 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3914 /* The position first */
3915 float *p =
3916 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3917 float x, y, z, rhw;
3918 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3920 /* Multiplication with world, view and projection matrix */
3921 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);
3922 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);
3923 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);
3924 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);
3926 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3928 /* WARNING: The following things are taken from d3d7 and were not yet checked
3929 * against d3d8 or d3d9!
3932 /* Clipping conditions: From
3933 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3935 * A vertex is clipped if it does not match the following requirements
3936 * -rhw < x <= rhw
3937 * -rhw < y <= rhw
3938 * 0 < z <= rhw
3939 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3941 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3942 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3946 if( !doClip ||
3947 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3948 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3949 ( rhw > eps ) ) ) {
3951 /* "Normal" viewport transformation (not clipped)
3952 * 1) The values are divided by rhw
3953 * 2) The y axis is negative, so multiply it with -1
3954 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3955 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3956 * 4) Multiply x with Width/2 and add Width/2
3957 * 5) The same for the height
3958 * 6) Add the viewpoint X and Y to the 2D coordinates and
3959 * The minimum Z value to z
3960 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3962 * Well, basically it's simply a linear transformation into viewport
3963 * coordinates
3966 x /= rhw;
3967 y /= rhw;
3968 z /= rhw;
3970 y *= -1;
3972 x *= vp.Width / 2;
3973 y *= vp.Height / 2;
3974 z *= vp.MaxZ - vp.MinZ;
3976 x += vp.Width / 2 + vp.X;
3977 y += vp.Height / 2 + vp.Y;
3978 z += vp.MinZ;
3980 rhw = 1 / rhw;
3981 } else {
3982 /* That vertex got clipped
3983 * Contrary to OpenGL it is not dropped completely, it just
3984 * undergoes a different calculation.
3986 TRACE("Vertex got clipped\n");
3987 x += rhw;
3988 y += rhw;
3990 x /= 2;
3991 y /= 2;
3993 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3994 * outside of the main vertex buffer memory. That needs some more
3995 * investigation...
3999 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4002 ( (float *) dest_ptr)[0] = x;
4003 ( (float *) dest_ptr)[1] = y;
4004 ( (float *) dest_ptr)[2] = z;
4005 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4007 dest_ptr += 3 * sizeof(float);
4009 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4010 dest_ptr += sizeof(float);
4013 if(dest_conv) {
4014 float w = 1 / rhw;
4015 ( (float *) dest_conv)[0] = x * w;
4016 ( (float *) dest_conv)[1] = y * w;
4017 ( (float *) dest_conv)[2] = z * w;
4018 ( (float *) dest_conv)[3] = w;
4020 dest_conv += 3 * sizeof(float);
4022 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4023 dest_conv += sizeof(float);
4027 if (DestFVF & WINED3DFVF_PSIZE) {
4028 dest_ptr += sizeof(DWORD);
4029 if(dest_conv) dest_conv += sizeof(DWORD);
4031 if (DestFVF & WINED3DFVF_NORMAL) {
4032 float *normal =
4033 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4034 /* AFAIK this should go into the lighting information */
4035 FIXME("Didn't expect the destination to have a normal\n");
4036 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4037 if(dest_conv) {
4038 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4042 if (DestFVF & WINED3DFVF_DIFFUSE) {
4043 DWORD *color_d =
4044 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4045 if(!color_d) {
4046 static BOOL warned = FALSE;
4048 if(!warned) {
4049 ERR("No diffuse color in source, but destination has one\n");
4050 warned = TRUE;
4053 *( (DWORD *) dest_ptr) = 0xffffffff;
4054 dest_ptr += sizeof(DWORD);
4056 if(dest_conv) {
4057 *( (DWORD *) dest_conv) = 0xffffffff;
4058 dest_conv += sizeof(DWORD);
4061 else {
4062 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4063 if(dest_conv) {
4064 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4065 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4066 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4067 dest_conv += sizeof(DWORD);
4072 if (DestFVF & WINED3DFVF_SPECULAR) {
4073 /* What's the color value in the feedback buffer? */
4074 DWORD *color_s =
4075 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4076 if(!color_s) {
4077 static BOOL warned = FALSE;
4079 if(!warned) {
4080 ERR("No specular color in source, but destination has one\n");
4081 warned = TRUE;
4084 *( (DWORD *) dest_ptr) = 0xFF000000;
4085 dest_ptr += sizeof(DWORD);
4087 if(dest_conv) {
4088 *( (DWORD *) dest_conv) = 0xFF000000;
4089 dest_conv += sizeof(DWORD);
4092 else {
4093 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4094 if(dest_conv) {
4095 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4096 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4097 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4098 dest_conv += sizeof(DWORD);
4103 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4104 float *tex_coord =
4105 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4106 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4107 if(!tex_coord) {
4108 ERR("No source texture, but destination requests one\n");
4109 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4110 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4112 else {
4113 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4114 if(dest_conv) {
4115 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4121 if(dest_conv) {
4122 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4123 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4124 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4125 dwCount * get_flexible_vertex_size(DestFVF),
4126 dest_conv_addr));
4127 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4128 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4131 LEAVE_GL();
4133 return WINED3D_OK;
4135 #undef copy_and_next
4137 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4139 WineDirect3DVertexStridedData strided;
4140 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4141 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4143 if(pVertexDecl) {
4144 ERR("Output vertex declaration not implemented yet\n");
4147 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4148 * and this call is quite performance critical, so don't call needlessly
4150 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4151 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4154 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4155 * control the streamIsUP flag, thus restore it afterwards.
4157 This->stateBlock->streamIsUP = FALSE;
4158 memset(&strided, 0, sizeof(strided));
4159 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4160 This->stateBlock->streamIsUP = streamWasUP;
4162 if(vbo || SrcStartIndex) {
4163 unsigned int i;
4164 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4165 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4167 * Also get the start index in, but only loop over all elements if there's something to add at all.
4169 #define FIXSRC(type) \
4170 if(strided.u.s.type.VBO) { \
4171 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4172 strided.u.s.type.VBO = 0; \
4173 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4174 ENTER_GL(); \
4175 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4176 vb->vbo = 0; \
4177 LEAVE_GL(); \
4179 if(strided.u.s.type.lpData) { \
4180 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4182 FIXSRC(position);
4183 FIXSRC(blendWeights);
4184 FIXSRC(blendMatrixIndices);
4185 FIXSRC(normal);
4186 FIXSRC(pSize);
4187 FIXSRC(diffuse);
4188 FIXSRC(specular);
4189 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4190 FIXSRC(texCoords[i]);
4192 FIXSRC(position2);
4193 FIXSRC(normal2);
4194 FIXSRC(tangent);
4195 FIXSRC(binormal);
4196 FIXSRC(tessFactor);
4197 FIXSRC(fog);
4198 FIXSRC(depth);
4199 FIXSRC(sample);
4200 #undef FIXSRC
4203 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4206 /*****
4207 * Get / Set Texture Stage States
4208 * TODO: Verify against dx9 definitions
4209 *****/
4210 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4212 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4214 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4216 if (Stage >= MAX_TEXTURES) {
4217 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4218 return WINED3D_OK;
4221 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4222 This->updateStateBlock->textureState[Stage][Type] = Value;
4224 if (This->isRecordingState) {
4225 TRACE("Recording... not performing anything\n");
4226 return WINED3D_OK;
4229 /* Checked after the assignments to allow proper stateblock recording */
4230 if(oldValue == Value) {
4231 TRACE("App is setting the old value over, nothing to do\n");
4232 return WINED3D_OK;
4235 if(Stage > This->stateBlock->lowest_disabled_stage &&
4236 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4237 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4238 * Changes in other states are important on disabled stages too
4240 return WINED3D_OK;
4243 if(Type == WINED3DTSS_COLOROP) {
4244 int i;
4246 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4247 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4248 * they have to be disabled
4250 * The current stage is dirtified below.
4252 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4253 TRACE("Additionally dirtifying stage %d\n", i);
4254 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4256 This->stateBlock->lowest_disabled_stage = Stage;
4257 TRACE("New lowest disabled: %d\n", Stage);
4258 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4259 /* Previously disabled stage enabled. Stages above it may need enabling
4260 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4261 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4263 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4266 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4267 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4268 break;
4270 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4273 This->stateBlock->lowest_disabled_stage = i;
4274 TRACE("New lowest disabled: %d\n", i);
4276 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4277 /* TODO: Built a stage -> texture unit mapping for register combiners */
4281 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4283 return WINED3D_OK;
4286 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4288 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4289 *pValue = This->updateStateBlock->textureState[Stage][Type];
4290 return WINED3D_OK;
4293 /*****
4294 * Get / Set Texture
4295 *****/
4296 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4298 IWineD3DBaseTexture *oldTexture;
4300 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4302 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4303 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4306 oldTexture = This->updateStateBlock->textures[Stage];
4308 if(pTexture != NULL) {
4309 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4311 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4312 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4313 return WINED3DERR_INVALIDCALL;
4315 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4318 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4319 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4321 This->updateStateBlock->changed.textures[Stage] = TRUE;
4322 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4323 This->updateStateBlock->textures[Stage] = pTexture;
4325 /* Handle recording of state blocks */
4326 if (This->isRecordingState) {
4327 TRACE("Recording... not performing anything\n");
4328 return WINED3D_OK;
4331 if(oldTexture == pTexture) {
4332 TRACE("App is setting the same texture again, nothing to do\n");
4333 return WINED3D_OK;
4336 /** NOTE: MSDN says that setTexture increases the reference count,
4337 * and the the application must set the texture back to null (or have a leaky application),
4338 * This means we should pass the refcount up to the parent
4339 *******************************/
4340 if (NULL != This->updateStateBlock->textures[Stage]) {
4341 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4342 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4344 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4345 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4346 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4347 * so the COLOROP and ALPHAOP have to be dirtified.
4349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4352 if(bindCount == 1) {
4353 new->baseTexture.sampler = Stage;
4355 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4359 if (NULL != oldTexture) {
4360 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4361 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4363 IWineD3DBaseTexture_Release(oldTexture);
4364 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4369 if(bindCount && old->baseTexture.sampler == Stage) {
4370 int i;
4371 /* Have to do a search for the other sampler(s) where the texture is bound to
4372 * Shouldn't happen as long as apps bind a texture only to one stage
4374 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4375 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4376 if(This->updateStateBlock->textures[i] == oldTexture) {
4377 old->baseTexture.sampler = i;
4378 break;
4384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4386 return WINED3D_OK;
4389 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4392 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4394 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4395 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4398 *ppTexture=This->stateBlock->textures[Stage];
4399 if (*ppTexture)
4400 IWineD3DBaseTexture_AddRef(*ppTexture);
4402 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4404 return WINED3D_OK;
4407 /*****
4408 * Get Back Buffer
4409 *****/
4410 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4411 IWineD3DSurface **ppBackBuffer) {
4412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4413 IWineD3DSwapChain *swapChain;
4414 HRESULT hr;
4416 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4418 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4419 if (hr == WINED3D_OK) {
4420 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4421 IWineD3DSwapChain_Release(swapChain);
4422 } else {
4423 *ppBackBuffer = NULL;
4425 return hr;
4428 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4430 WARN("(%p) : stub, calling idirect3d for now\n", This);
4431 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4434 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436 IWineD3DSwapChain *swapChain;
4437 HRESULT hr;
4439 if(iSwapChain > 0) {
4440 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4441 if (hr == WINED3D_OK) {
4442 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4443 IWineD3DSwapChain_Release(swapChain);
4444 } else {
4445 FIXME("(%p) Error getting display mode\n", This);
4447 } else {
4448 /* Don't read the real display mode,
4449 but return the stored mode instead. X11 can't change the color
4450 depth, and some apps are pretty angry if they SetDisplayMode from
4451 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4453 Also don't relay to the swapchain because with ddraw it's possible
4454 that there isn't a swapchain at all */
4455 pMode->Width = This->ddraw_width;
4456 pMode->Height = This->ddraw_height;
4457 pMode->Format = This->ddraw_format;
4458 pMode->RefreshRate = 0;
4459 hr = WINED3D_OK;
4462 return hr;
4465 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4467 TRACE("(%p)->(%p)\n", This, hWnd);
4469 if(This->ddraw_fullscreen) {
4470 if(This->ddraw_window && This->ddraw_window != hWnd) {
4471 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4473 if(hWnd && This->ddraw_window != hWnd) {
4474 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4478 This->ddraw_window = hWnd;
4479 return WINED3D_OK;
4482 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 TRACE("(%p)->(%p)\n", This, hWnd);
4486 *hWnd = This->ddraw_window;
4487 return WINED3D_OK;
4490 /*****
4491 * Stateblock related functions
4492 *****/
4494 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4496 IWineD3DStateBlockImpl *object;
4497 HRESULT temp_result;
4498 int i;
4500 TRACE("(%p)\n", This);
4502 if (This->isRecordingState) {
4503 return WINED3DERR_INVALIDCALL;
4506 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4507 if (NULL == object ) {
4508 FIXME("(%p)Error allocating memory for stateblock\n", This);
4509 return E_OUTOFMEMORY;
4511 TRACE("(%p) created object %p\n", This, object);
4512 object->wineD3DDevice= This;
4513 /** FIXME: object->parent = parent; **/
4514 object->parent = NULL;
4515 object->blockType = WINED3DSBT_RECORDED;
4516 object->ref = 1;
4517 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4519 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4520 list_init(&object->lightMap[i]);
4523 temp_result = allocate_shader_constants(object);
4524 if (WINED3D_OK != temp_result)
4525 return temp_result;
4527 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4528 This->updateStateBlock = object;
4529 This->isRecordingState = TRUE;
4531 TRACE("(%p) recording stateblock %p\n",This , object);
4532 return WINED3D_OK;
4535 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4537 unsigned int i, j;
4538 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4540 if (!This->isRecordingState) {
4541 FIXME("(%p) not recording! returning error\n", This);
4542 *ppStateBlock = NULL;
4543 return WINED3DERR_INVALIDCALL;
4546 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4547 if(object->changed.renderState[i]) {
4548 object->contained_render_states[object->num_contained_render_states] = i;
4549 object->num_contained_render_states++;
4552 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4553 if(object->changed.transform[i]) {
4554 object->contained_transform_states[object->num_contained_transform_states] = i;
4555 object->num_contained_transform_states++;
4558 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4559 if(object->changed.vertexShaderConstantsF[i]) {
4560 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4561 object->num_contained_vs_consts_f++;
4564 for(i = 0; i < MAX_CONST_I; i++) {
4565 if(object->changed.vertexShaderConstantsI[i]) {
4566 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4567 object->num_contained_vs_consts_i++;
4570 for(i = 0; i < MAX_CONST_B; i++) {
4571 if(object->changed.vertexShaderConstantsB[i]) {
4572 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4573 object->num_contained_vs_consts_b++;
4576 for(i = 0; i < MAX_CONST_I; i++) {
4577 if(object->changed.pixelShaderConstantsI[i]) {
4578 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4579 object->num_contained_ps_consts_i++;
4582 for(i = 0; i < MAX_CONST_B; i++) {
4583 if(object->changed.pixelShaderConstantsB[i]) {
4584 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4585 object->num_contained_ps_consts_b++;
4588 for(i = 0; i < MAX_TEXTURES; i++) {
4589 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4590 if(object->changed.textureState[i][j]) {
4591 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4592 object->contained_tss_states[object->num_contained_tss_states].state = j;
4593 object->num_contained_tss_states++;
4597 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4598 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4599 if(object->changed.samplerState[i][j]) {
4600 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4601 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4602 object->num_contained_sampler_states++;
4607 *ppStateBlock = (IWineD3DStateBlock*) object;
4608 This->isRecordingState = FALSE;
4609 This->updateStateBlock = This->stateBlock;
4610 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4611 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4612 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4613 return WINED3D_OK;
4616 /*****
4617 * Scene related functions
4618 *****/
4619 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4620 /* At the moment we have no need for any functionality at the beginning
4621 of a scene */
4622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 TRACE("(%p)\n", This);
4625 if(This->inScene) {
4626 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4627 return WINED3DERR_INVALIDCALL;
4629 This->inScene = TRUE;
4630 return WINED3D_OK;
4633 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4635 TRACE("(%p)\n", This);
4637 if(!This->inScene) {
4638 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4639 return WINED3DERR_INVALIDCALL;
4642 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4643 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4645 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4646 ENTER_GL();
4647 glFlush();
4648 checkGLcall("glFlush");
4649 LEAVE_GL();
4651 This->inScene = FALSE;
4652 return WINED3D_OK;
4655 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4656 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4657 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4659 IWineD3DSwapChain *swapChain = NULL;
4660 int i;
4661 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4663 TRACE("(%p) Presenting the frame\n", This);
4665 for(i = 0 ; i < swapchains ; i ++) {
4667 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4668 TRACE("presentinng chain %d, %p\n", i, swapChain);
4669 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4670 IWineD3DSwapChain_Release(swapChain);
4673 return WINED3D_OK;
4676 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4677 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4679 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4681 GLbitfield glMask = 0;
4682 unsigned int i;
4683 CONST WINED3DRECT* curRect;
4685 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4686 Count, pRects, Flags, Color, Z, Stencil);
4688 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4689 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4690 /* TODO: What about depth stencil buffers without stencil bits? */
4691 return WINED3DERR_INVALIDCALL;
4694 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4695 * and not the last active one.
4697 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4698 ENTER_GL();
4700 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4701 apply_fbo_state(iface);
4704 if (Count > 0 && pRects) {
4705 curRect = pRects;
4706 } else {
4707 curRect = NULL;
4710 /* Only set the values up once, as they are not changing */
4711 if (Flags & WINED3DCLEAR_STENCIL) {
4712 glClearStencil(Stencil);
4713 checkGLcall("glClearStencil");
4714 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4715 glStencilMask(0xFFFFFFFF);
4718 if (Flags & WINED3DCLEAR_ZBUFFER) {
4719 glDepthMask(GL_TRUE);
4720 glClearDepth(Z);
4721 checkGLcall("glClearDepth");
4722 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4723 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4726 if (Flags & WINED3DCLEAR_TARGET) {
4727 TRACE("Clearing screen with glClear to color %x\n", Color);
4728 glClearColor(D3DCOLOR_R(Color),
4729 D3DCOLOR_G(Color),
4730 D3DCOLOR_B(Color),
4731 D3DCOLOR_A(Color));
4732 checkGLcall("glClearColor");
4734 /* Clear ALL colors! */
4735 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4736 glMask = glMask | GL_COLOR_BUFFER_BIT;
4739 if (!curRect) {
4740 /* In drawable flag is set below */
4742 if (This->render_offscreen) {
4743 glScissor(This->stateBlock->viewport.X,
4744 This->stateBlock->viewport.Y,
4745 This->stateBlock->viewport.Width,
4746 This->stateBlock->viewport.Height);
4747 } else {
4748 glScissor(This->stateBlock->viewport.X,
4749 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4750 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4751 This->stateBlock->viewport.Width,
4752 This->stateBlock->viewport.Height);
4754 checkGLcall("glScissor");
4755 glClear(glMask);
4756 checkGLcall("glClear");
4757 } else {
4758 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4759 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4761 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4762 curRect[0].x2 < target->currentDesc.Width ||
4763 curRect[0].y2 < target->currentDesc.Height) {
4764 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4765 blt_to_drawable(This, target);
4769 /* Now process each rect in turn */
4770 for (i = 0; i < Count; i++) {
4771 /* Note gl uses lower left, width/height */
4772 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4773 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4774 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4775 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4777 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4778 * The rectangle is not cleared, no error is returned, but further rectanlges are
4779 * still cleared if they are valid
4781 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4782 TRACE("Rectangle with negative dimensions, ignoring\n");
4783 continue;
4786 if(This->render_offscreen) {
4787 glScissor(curRect[i].x1, curRect[i].y1,
4788 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4789 } else {
4790 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4791 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4793 checkGLcall("glScissor");
4795 glClear(glMask);
4796 checkGLcall("glClear");
4800 /* Restore the old values (why..?) */
4801 if (Flags & WINED3DCLEAR_STENCIL) {
4802 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4804 if (Flags & WINED3DCLEAR_TARGET) {
4805 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4806 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4807 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4808 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4809 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4812 LEAVE_GL();
4814 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4815 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4817 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4818 target->Flags |= SFLAG_INTEXTURE;
4819 target->Flags &= ~SFLAG_INSYSMEM;
4820 } else {
4821 target->Flags |= SFLAG_INDRAWABLE;
4822 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4824 return WINED3D_OK;
4827 /*****
4828 * Drawing functions
4829 *****/
4830 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4831 UINT PrimitiveCount) {
4833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4835 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4836 debug_d3dprimitivetype(PrimitiveType),
4837 StartVertex, PrimitiveCount);
4839 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4840 if(This->stateBlock->streamIsUP) {
4841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4842 This->stateBlock->streamIsUP = FALSE;
4845 if(This->stateBlock->loadBaseVertexIndex != 0) {
4846 This->stateBlock->loadBaseVertexIndex = 0;
4847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4849 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4850 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4851 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4852 return WINED3D_OK;
4855 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4856 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4857 WINED3DPRIMITIVETYPE PrimitiveType,
4858 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4861 UINT idxStride = 2;
4862 IWineD3DIndexBuffer *pIB;
4863 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4864 GLuint vbo;
4866 pIB = This->stateBlock->pIndexData;
4867 if (!pIB) {
4868 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4869 * without an index buffer set. (The first time at least...)
4870 * D3D8 simply dies, but I doubt it can do much harm to return
4871 * D3DERR_INVALIDCALL there as well. */
4872 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4873 return WINED3DERR_INVALIDCALL;
4876 if(This->stateBlock->streamIsUP) {
4877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4878 This->stateBlock->streamIsUP = FALSE;
4880 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4882 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4883 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4884 minIndex, NumVertices, startIndex, primCount);
4886 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4887 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4888 idxStride = 2;
4889 } else {
4890 idxStride = 4;
4893 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4894 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4895 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4898 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4899 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4901 return WINED3D_OK;
4904 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4905 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4906 UINT VertexStreamZeroStride) {
4907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4908 IWineD3DVertexBuffer *vb;
4910 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4911 debug_d3dprimitivetype(PrimitiveType),
4912 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4914 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4915 vb = This->stateBlock->streamSource[0];
4916 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4917 if(vb) IWineD3DVertexBuffer_Release(vb);
4918 This->stateBlock->streamOffset[0] = 0;
4919 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4920 This->stateBlock->streamIsUP = TRUE;
4921 This->stateBlock->loadBaseVertexIndex = 0;
4923 /* TODO: Only mark dirty if drawing from a different UP address */
4924 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4926 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4927 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4929 /* MSDN specifies stream zero settings must be set to NULL */
4930 This->stateBlock->streamStride[0] = 0;
4931 This->stateBlock->streamSource[0] = NULL;
4933 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4934 * the new stream sources or use UP drawing again
4936 return WINED3D_OK;
4939 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4940 UINT MinVertexIndex, UINT NumVertices,
4941 UINT PrimitiveCount, CONST void* pIndexData,
4942 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4943 UINT VertexStreamZeroStride) {
4944 int idxStride;
4945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4946 IWineD3DVertexBuffer *vb;
4947 IWineD3DIndexBuffer *ib;
4949 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4950 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4951 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4952 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4954 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4955 idxStride = 2;
4956 } else {
4957 idxStride = 4;
4960 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4961 vb = This->stateBlock->streamSource[0];
4962 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4963 if(vb) IWineD3DVertexBuffer_Release(vb);
4964 This->stateBlock->streamIsUP = TRUE;
4965 This->stateBlock->streamOffset[0] = 0;
4966 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4968 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4969 This->stateBlock->baseVertexIndex = 0;
4970 This->stateBlock->loadBaseVertexIndex = 0;
4971 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4975 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4977 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4978 This->stateBlock->streamSource[0] = NULL;
4979 This->stateBlock->streamStride[0] = 0;
4980 ib = This->stateBlock->pIndexData;
4981 if(ib) {
4982 IWineD3DIndexBuffer_Release(ib);
4983 This->stateBlock->pIndexData = NULL;
4985 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4986 * SetStreamSource to specify a vertex buffer
4989 return WINED3D_OK;
4992 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4995 /* Mark the state dirty until we have nicer tracking
4996 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4997 * that value.
4999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5001 This->stateBlock->baseVertexIndex = 0;
5002 This->up_strided = DrawPrimStrideData;
5003 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5004 This->up_strided = NULL;
5005 return WINED3D_OK;
5008 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5010 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5012 /* Mark the state dirty until we have nicer tracking
5013 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5014 * that value.
5016 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5017 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5018 This->stateBlock->streamIsUP = TRUE;
5019 This->stateBlock->baseVertexIndex = 0;
5020 This->up_strided = DrawPrimStrideData;
5021 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5022 This->up_strided = NULL;
5023 return WINED3D_OK;
5026 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5027 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5028 * not callable by the app directly no parameter validation checks are needed here.
5030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5031 WINED3DLOCKED_BOX src;
5032 WINED3DLOCKED_BOX dst;
5033 HRESULT hr;
5034 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5036 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5037 * dirtification to improve loading performance.
5039 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5040 if(FAILED(hr)) return hr;
5041 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5042 if(FAILED(hr)) {
5043 IWineD3DVolume_UnlockBox(pSourceVolume);
5044 return hr;
5047 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5049 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5050 if(FAILED(hr)) {
5051 IWineD3DVolume_UnlockBox(pSourceVolume);
5052 } else {
5053 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5055 return hr;
5058 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5059 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5061 HRESULT hr = WINED3D_OK;
5062 WINED3DRESOURCETYPE sourceType;
5063 WINED3DRESOURCETYPE destinationType;
5064 int i ,levels;
5066 /* TODO: think about moving the code into IWineD3DBaseTexture */
5068 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5070 /* verify that the source and destination textures aren't NULL */
5071 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5072 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5073 This, pSourceTexture, pDestinationTexture);
5074 hr = WINED3DERR_INVALIDCALL;
5077 if (pSourceTexture == pDestinationTexture) {
5078 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5079 This, pSourceTexture, pDestinationTexture);
5080 hr = WINED3DERR_INVALIDCALL;
5082 /* Verify that the source and destination textures are the same type */
5083 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5084 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5086 if (sourceType != destinationType) {
5087 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5088 This);
5089 hr = WINED3DERR_INVALIDCALL;
5092 /* check that both textures have the identical numbers of levels */
5093 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5094 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5095 hr = WINED3DERR_INVALIDCALL;
5098 if (WINED3D_OK == hr) {
5100 /* Make sure that the destination texture is loaded */
5101 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5103 /* Update every surface level of the texture */
5104 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5106 switch (sourceType) {
5107 case WINED3DRTYPE_TEXTURE:
5109 IWineD3DSurface *srcSurface;
5110 IWineD3DSurface *destSurface;
5112 for (i = 0 ; i < levels ; ++i) {
5113 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5114 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5115 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5116 IWineD3DSurface_Release(srcSurface);
5117 IWineD3DSurface_Release(destSurface);
5118 if (WINED3D_OK != hr) {
5119 WARN("(%p) : Call to update surface failed\n", This);
5120 return hr;
5124 break;
5125 case WINED3DRTYPE_CUBETEXTURE:
5127 IWineD3DSurface *srcSurface;
5128 IWineD3DSurface *destSurface;
5129 WINED3DCUBEMAP_FACES faceType;
5131 for (i = 0 ; i < levels ; ++i) {
5132 /* Update each cube face */
5133 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5134 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5135 if (WINED3D_OK != hr) {
5136 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5137 } else {
5138 TRACE("Got srcSurface %p\n", srcSurface);
5140 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5141 if (WINED3D_OK != hr) {
5142 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5143 } else {
5144 TRACE("Got desrSurface %p\n", destSurface);
5146 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5147 IWineD3DSurface_Release(srcSurface);
5148 IWineD3DSurface_Release(destSurface);
5149 if (WINED3D_OK != hr) {
5150 WARN("(%p) : Call to update surface failed\n", This);
5151 return hr;
5156 break;
5158 case WINED3DRTYPE_VOLUMETEXTURE:
5160 IWineD3DVolume *srcVolume = NULL;
5161 IWineD3DVolume *destVolume = NULL;
5163 for (i = 0 ; i < levels ; ++i) {
5164 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5165 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5166 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5167 IWineD3DVolume_Release(srcVolume);
5168 IWineD3DVolume_Release(destVolume);
5169 if (WINED3D_OK != hr) {
5170 WARN("(%p) : Call to update volume failed\n", This);
5171 return hr;
5175 break;
5177 default:
5178 FIXME("(%p) : Unsupported source and destination type\n", This);
5179 hr = WINED3DERR_INVALIDCALL;
5183 return hr;
5186 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5187 IWineD3DSwapChain *swapChain;
5188 HRESULT hr;
5189 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5190 if(hr == WINED3D_OK) {
5191 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5192 IWineD3DSwapChain_Release(swapChain);
5194 return hr;
5197 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5199 /* return a sensible default */
5200 *pNumPasses = 1;
5201 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5202 FIXME("(%p) : stub\n", This);
5203 return WINED3D_OK;
5206 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5208 int j;
5209 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5210 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5211 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5212 return WINED3DERR_INVALIDCALL;
5214 for (j = 0; j < 256; ++j) {
5215 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5216 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5217 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5218 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5220 TRACE("(%p) : returning\n", This);
5221 return WINED3D_OK;
5224 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5226 int j;
5227 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5228 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5229 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5230 return WINED3DERR_INVALIDCALL;
5232 for (j = 0; j < 256; ++j) {
5233 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5234 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5235 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5236 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5238 TRACE("(%p) : returning\n", This);
5239 return WINED3D_OK;
5242 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5244 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5245 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5246 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5247 return WINED3DERR_INVALIDCALL;
5249 /*TODO: stateblocks */
5250 This->currentPalette = PaletteNumber;
5251 TRACE("(%p) : returning\n", This);
5252 return WINED3D_OK;
5255 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5257 if (PaletteNumber == NULL) {
5258 WARN("(%p) : returning Invalid Call\n", This);
5259 return WINED3DERR_INVALIDCALL;
5261 /*TODO: stateblocks */
5262 *PaletteNumber = This->currentPalette;
5263 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5264 return WINED3D_OK;
5267 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5269 static BOOL showFixmes = TRUE;
5270 if (showFixmes) {
5271 FIXME("(%p) : stub\n", This);
5272 showFixmes = FALSE;
5275 This->softwareVertexProcessing = bSoftware;
5276 return WINED3D_OK;
5280 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5282 static BOOL showFixmes = TRUE;
5283 if (showFixmes) {
5284 FIXME("(%p) : stub\n", This);
5285 showFixmes = FALSE;
5287 return This->softwareVertexProcessing;
5291 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5293 IWineD3DSwapChain *swapChain;
5294 HRESULT hr;
5296 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5298 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5299 if(hr == WINED3D_OK){
5300 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5301 IWineD3DSwapChain_Release(swapChain);
5302 }else{
5303 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5305 return hr;
5309 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5311 static BOOL showfixmes = TRUE;
5312 if(nSegments != 0.0f) {
5313 if( showfixmes) {
5314 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5315 showfixmes = FALSE;
5318 return WINED3D_OK;
5321 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5323 static BOOL showfixmes = TRUE;
5324 if( showfixmes) {
5325 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5326 showfixmes = FALSE;
5328 return 0.0f;
5331 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5333 /** TODO: remove casts to IWineD3DSurfaceImpl
5334 * NOTE: move code to surface to accomplish this
5335 ****************************************/
5336 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5337 int srcWidth, srcHeight;
5338 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5339 WINED3DFORMAT destFormat, srcFormat;
5340 UINT destSize;
5341 int srcLeft, destLeft, destTop;
5342 WINED3DPOOL srcPool, destPool;
5343 int offset = 0;
5344 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5345 glDescriptor *glDescription = NULL;
5346 GLenum dummy;
5347 int bpp;
5348 CONVERT_TYPES convert = NO_CONVERSION;
5350 WINED3DSURFACE_DESC winedesc;
5352 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5353 memset(&winedesc, 0, sizeof(winedesc));
5354 winedesc.Width = &srcSurfaceWidth;
5355 winedesc.Height = &srcSurfaceHeight;
5356 winedesc.Pool = &srcPool;
5357 winedesc.Format = &srcFormat;
5359 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5361 winedesc.Width = &destSurfaceWidth;
5362 winedesc.Height = &destSurfaceHeight;
5363 winedesc.Pool = &destPool;
5364 winedesc.Format = &destFormat;
5365 winedesc.Size = &destSize;
5367 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5369 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5370 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5371 return WINED3DERR_INVALIDCALL;
5374 /* This call loads the opengl surface directly, instead of copying the surface to the
5375 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5376 * copy in sysmem and use regular surface loading.
5378 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5379 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5380 if(convert != NO_CONVERSION) {
5381 return IWineD3DSurface_BltFast(pDestinationSurface,
5382 pDestPoint ? pDestPoint->x : 0,
5383 pDestPoint ? pDestPoint->y : 0,
5384 pSourceSurface, (RECT *) pSourceRect, 0);
5387 if (destFormat == WINED3DFMT_UNKNOWN) {
5388 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5389 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5391 /* Get the update surface description */
5392 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5395 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5397 ENTER_GL();
5399 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5400 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5401 checkGLcall("glActiveTextureARB");
5404 /* Make sure the surface is loaded and up to date */
5405 IWineD3DSurface_PreLoad(pDestinationSurface);
5407 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5409 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5410 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5411 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5412 srcLeft = pSourceRect ? pSourceRect->left : 0;
5413 destLeft = pDestPoint ? pDestPoint->x : 0;
5414 destTop = pDestPoint ? pDestPoint->y : 0;
5417 /* This function doesn't support compressed textures
5418 the pitch is just bytesPerPixel * width */
5419 if(srcWidth != srcSurfaceWidth || srcLeft ){
5420 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5421 offset += srcLeft * pSrcSurface->bytesPerPixel;
5422 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5424 /* TODO DXT formats */
5426 if(pSourceRect != NULL && pSourceRect->top != 0){
5427 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5429 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5430 ,This
5431 ,glDescription->level
5432 ,destLeft
5433 ,destTop
5434 ,srcWidth
5435 ,srcHeight
5436 ,glDescription->glFormat
5437 ,glDescription->glType
5438 ,IWineD3DSurface_GetData(pSourceSurface)
5441 /* Sanity check */
5442 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5444 /* need to lock the surface to get the data */
5445 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5448 /* TODO: Cube and volume support */
5449 if(rowoffset != 0){
5450 /* not a whole row so we have to do it a line at a time */
5451 int j;
5453 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5454 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5456 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5458 glTexSubImage2D(glDescription->target
5459 ,glDescription->level
5460 ,destLeft
5462 ,srcWidth
5464 ,glDescription->glFormat
5465 ,glDescription->glType
5466 ,data /* could be quicker using */
5468 data += rowoffset;
5471 } else { /* Full width, so just write out the whole texture */
5473 if (WINED3DFMT_DXT1 == destFormat ||
5474 WINED3DFMT_DXT2 == destFormat ||
5475 WINED3DFMT_DXT3 == destFormat ||
5476 WINED3DFMT_DXT4 == destFormat ||
5477 WINED3DFMT_DXT5 == destFormat) {
5478 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5479 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5480 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5481 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5482 } if (destFormat != srcFormat) {
5483 FIXME("Updating mixed format compressed texture is not curretly support\n");
5484 } else {
5485 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5486 glDescription->level,
5487 glDescription->glFormatInternal,
5488 srcWidth,
5489 srcHeight,
5491 destSize,
5492 IWineD3DSurface_GetData(pSourceSurface));
5494 } else {
5495 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5499 } else {
5500 glTexSubImage2D(glDescription->target
5501 ,glDescription->level
5502 ,destLeft
5503 ,destTop
5504 ,srcWidth
5505 ,srcHeight
5506 ,glDescription->glFormat
5507 ,glDescription->glType
5508 ,IWineD3DSurface_GetData(pSourceSurface)
5512 checkGLcall("glTexSubImage2D");
5514 LEAVE_GL();
5516 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5517 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5520 return WINED3D_OK;
5523 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5525 struct WineD3DRectPatch *patch;
5526 unsigned int i;
5527 struct list *e;
5528 BOOL found;
5529 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5531 if(!(Handle || pRectPatchInfo)) {
5532 /* TODO: Write a test for the return value, thus the FIXME */
5533 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5534 return WINED3DERR_INVALIDCALL;
5537 if(Handle) {
5538 i = PATCHMAP_HASHFUNC(Handle);
5539 found = FALSE;
5540 LIST_FOR_EACH(e, &This->patches[i]) {
5541 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5542 if(patch->Handle == Handle) {
5543 found = TRUE;
5544 break;
5548 if(!found) {
5549 TRACE("Patch does not exist. Creating a new one\n");
5550 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5551 patch->Handle = Handle;
5552 list_add_head(&This->patches[i], &patch->entry);
5553 } else {
5554 TRACE("Found existing patch %p\n", patch);
5556 } else {
5557 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5558 * attributes we have to tesselate, read back, and draw. This needs a patch
5559 * management structure instance. Create one.
5561 * A possible improvement is to check if a vertex shader is used, and if not directly
5562 * draw the patch.
5564 FIXME("Drawing an uncached patch. This is slow\n");
5565 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5568 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5569 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5570 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5571 HRESULT hr;
5572 TRACE("Tesselation density or patch info changed, retesselating\n");
5574 if(pRectPatchInfo) {
5575 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5577 patch->numSegs[0] = pNumSegs[0];
5578 patch->numSegs[1] = pNumSegs[1];
5579 patch->numSegs[2] = pNumSegs[2];
5580 patch->numSegs[3] = pNumSegs[3];
5582 hr = tesselate_rectpatch(This, patch);
5583 if(FAILED(hr)) {
5584 WARN("Patch tesselation failed\n");
5586 /* Do not release the handle to store the params of the patch */
5587 if(!Handle) {
5588 HeapFree(GetProcessHeap(), 0, patch);
5590 return hr;
5594 This->currentPatch = patch;
5595 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5596 This->currentPatch = NULL;
5598 /* Destroy uncached patches */
5599 if(!Handle) {
5600 HeapFree(GetProcessHeap(), 0, patch->mem);
5601 HeapFree(GetProcessHeap(), 0, patch);
5603 return WINED3D_OK;
5606 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5607 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5609 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5610 FIXME("(%p) : Stub\n", This);
5611 return WINED3D_OK;
5614 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5616 int i;
5617 struct WineD3DRectPatch *patch;
5618 struct list *e;
5619 TRACE("(%p) Handle(%d)\n", This, Handle);
5621 i = PATCHMAP_HASHFUNC(Handle);
5622 LIST_FOR_EACH(e, &This->patches[i]) {
5623 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5624 if(patch->Handle == Handle) {
5625 TRACE("Deleting patch %p\n", patch);
5626 list_remove(&patch->entry);
5627 HeapFree(GetProcessHeap(), 0, patch->mem);
5628 HeapFree(GetProcessHeap(), 0, patch);
5629 return WINED3D_OK;
5633 /* TODO: Write a test for the return value */
5634 FIXME("Attempt to destroy nonexistant patch\n");
5635 return WINED3DERR_INVALIDCALL;
5638 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5639 HRESULT hr;
5640 IWineD3DSwapChain *swapchain;
5642 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5643 if (SUCCEEDED(hr)) {
5644 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5645 return swapchain;
5648 return NULL;
5651 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5654 if (!*fbo) {
5655 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5656 checkGLcall("glGenFramebuffersEXT()");
5658 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5659 checkGLcall("glBindFramebuffer()");
5662 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5663 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5664 IWineD3DBaseTextureImpl *texture_impl;
5665 GLenum texttarget, target;
5666 GLint old_binding;
5668 texttarget = surface_impl->glDescription.target;
5669 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5670 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5672 IWineD3DSurface_PreLoad(surface);
5674 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5675 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5676 glBindTexture(target, old_binding);
5678 /* Update base texture states array */
5679 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5680 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5681 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5682 if (texture_impl->baseTexture.bindCount) {
5683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5686 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5689 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5690 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5692 checkGLcall("attach_surface_fbo");
5695 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5697 IWineD3DSwapChain *swapchain;
5699 swapchain = get_swapchain(surface);
5700 if (swapchain) {
5701 GLenum buffer;
5703 TRACE("Surface %p is onscreen\n", surface);
5705 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5706 buffer = surface_get_gl_buffer(surface, swapchain);
5707 glDrawBuffer(buffer);
5708 checkGLcall("glDrawBuffer()");
5709 } else {
5710 TRACE("Surface %p is offscreen\n", surface);
5711 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5712 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5715 if (rect) {
5716 glEnable(GL_SCISSOR_TEST);
5717 if(!swapchain) {
5718 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5719 } else {
5720 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5721 rect->x2 - rect->x1, rect->y2 - rect->y1);
5723 checkGLcall("glScissor");
5724 } else {
5725 glDisable(GL_SCISSOR_TEST);
5727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5729 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5732 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5733 glClear(GL_COLOR_BUFFER_BIT);
5734 checkGLcall("glClear");
5736 if (This->render_offscreen) {
5737 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5738 } else {
5739 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5740 checkGLcall("glBindFramebuffer()");
5743 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5744 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5745 glDrawBuffer(GL_BACK);
5746 checkGLcall("glDrawBuffer()");
5750 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5751 unsigned int r, g, b, a;
5752 DWORD ret;
5754 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5755 destfmt == WINED3DFMT_R8G8B8)
5756 return color;
5758 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5760 a = (color & 0xff000000) >> 24;
5761 r = (color & 0x00ff0000) >> 16;
5762 g = (color & 0x0000ff00) >> 8;
5763 b = (color & 0x000000ff) >> 0;
5765 switch(destfmt)
5767 case WINED3DFMT_R5G6B5:
5768 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5769 r = (r * 32) / 256;
5770 g = (g * 64) / 256;
5771 b = (b * 32) / 256;
5772 ret = r << 11;
5773 ret |= g << 5;
5774 ret |= b;
5775 TRACE("Returning %08x\n", ret);
5776 return ret;
5778 case WINED3DFMT_X1R5G5B5:
5779 case WINED3DFMT_A1R5G5B5:
5780 a = (a * 2) / 256;
5781 r = (r * 32) / 256;
5782 g = (g * 32) / 256;
5783 b = (b * 32) / 256;
5784 ret = a << 15;
5785 ret |= r << 10;
5786 ret |= g << 5;
5787 ret |= b << 0;
5788 TRACE("Returning %08x\n", ret);
5789 return ret;
5791 case WINED3DFMT_A8:
5792 TRACE("Returning %08x\n", a);
5793 return a;
5795 case WINED3DFMT_X4R4G4B4:
5796 case WINED3DFMT_A4R4G4B4:
5797 a = (a * 16) / 256;
5798 r = (r * 16) / 256;
5799 g = (g * 16) / 256;
5800 b = (b * 16) / 256;
5801 ret = a << 12;
5802 ret |= r << 8;
5803 ret |= g << 4;
5804 ret |= b << 0;
5805 TRACE("Returning %08x\n", ret);
5806 return ret;
5808 case WINED3DFMT_R3G3B2:
5809 r = (r * 8) / 256;
5810 g = (g * 8) / 256;
5811 b = (b * 4) / 256;
5812 ret = r << 5;
5813 ret |= g << 2;
5814 ret |= b << 0;
5815 TRACE("Returning %08x\n", ret);
5816 return ret;
5818 case WINED3DFMT_X8B8G8R8:
5819 case WINED3DFMT_A8B8G8R8:
5820 ret = a << 24;
5821 ret |= b << 16;
5822 ret |= g << 8;
5823 ret |= r << 0;
5824 TRACE("Returning %08x\n", ret);
5825 return ret;
5827 case WINED3DFMT_A2R10G10B10:
5828 a = (a * 4) / 256;
5829 r = (r * 1024) / 256;
5830 g = (g * 1024) / 256;
5831 b = (b * 1024) / 256;
5832 ret = a << 30;
5833 ret |= r << 20;
5834 ret |= g << 10;
5835 ret |= b << 0;
5836 TRACE("Returning %08x\n", ret);
5837 return ret;
5839 case WINED3DFMT_A2B10G10R10:
5840 a = (a * 4) / 256;
5841 r = (r * 1024) / 256;
5842 g = (g * 1024) / 256;
5843 b = (b * 1024) / 256;
5844 ret = a << 30;
5845 ret |= b << 20;
5846 ret |= g << 10;
5847 ret |= r << 0;
5848 TRACE("Returning %08x\n", ret);
5849 return ret;
5851 default:
5852 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5853 return 0;
5857 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5859 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5860 WINEDDBLTFX BltFx;
5861 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5863 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5864 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5865 return WINED3DERR_INVALIDCALL;
5868 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5869 color_fill_fbo(iface, pSurface, pRect, color);
5870 return WINED3D_OK;
5871 } else {
5872 /* Just forward this to the DirectDraw blitting engine */
5873 memset(&BltFx, 0, sizeof(BltFx));
5874 BltFx.dwSize = sizeof(BltFx);
5875 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
5876 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5880 /* rendertarget and deptth stencil functions */
5881 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5884 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5885 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5886 return WINED3DERR_INVALIDCALL;
5889 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5890 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5891 /* Note inc ref on returned surface */
5892 if(*ppRenderTarget != NULL)
5893 IWineD3DSurface_AddRef(*ppRenderTarget);
5894 return WINED3D_OK;
5897 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5899 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5900 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5901 IWineD3DSwapChainImpl *Swapchain;
5902 HRESULT hr;
5904 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5906 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5907 if(hr != WINED3D_OK) {
5908 ERR("Can't get the swapchain\n");
5909 return hr;
5912 /* Make sure to release the swapchain */
5913 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5915 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5916 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5917 return WINED3DERR_INVALIDCALL;
5919 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5920 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5921 return WINED3DERR_INVALIDCALL;
5924 if(Swapchain->frontBuffer != Front) {
5925 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5927 if(Swapchain->frontBuffer)
5928 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5929 Swapchain->frontBuffer = Front;
5931 if(Swapchain->frontBuffer) {
5932 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5936 if(Back && !Swapchain->backBuffer) {
5937 /* We need memory for the back buffer array - only one back buffer this way */
5938 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5939 if(!Swapchain->backBuffer) {
5940 ERR("Out of memory\n");
5941 return E_OUTOFMEMORY;
5945 if(Swapchain->backBuffer[0] != Back) {
5946 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5948 /* What to do about the context here in the case of multithreading? Not sure.
5949 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5951 ENTER_GL();
5952 if(!Swapchain->backBuffer[0]) {
5953 /* GL was told to draw to the front buffer at creation,
5954 * undo that
5956 glDrawBuffer(GL_BACK);
5957 checkGLcall("glDrawBuffer(GL_BACK)");
5958 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5959 Swapchain->presentParms.BackBufferCount = 1;
5960 } else if (!Back) {
5961 /* That makes problems - disable for now */
5962 /* glDrawBuffer(GL_FRONT); */
5963 checkGLcall("glDrawBuffer(GL_FRONT)");
5964 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5965 Swapchain->presentParms.BackBufferCount = 0;
5967 LEAVE_GL();
5969 if(Swapchain->backBuffer[0])
5970 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5971 Swapchain->backBuffer[0] = Back;
5973 if(Swapchain->backBuffer[0]) {
5974 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5975 } else {
5976 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5981 return WINED3D_OK;
5984 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5986 *ppZStencilSurface = This->depthStencilBuffer;
5987 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5989 if(*ppZStencilSurface != NULL) {
5990 /* Note inc ref on returned surface */
5991 IWineD3DSurface_AddRef(*ppZStencilSurface);
5992 return WINED3D_OK;
5993 } else {
5994 return WINED3DERR_NOTFOUND;
5998 /* TODO: Handle stencil attachments */
5999 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6001 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6003 TRACE("Set depth stencil to %p\n", depth_stencil);
6005 if (depth_stencil_impl) {
6006 if (depth_stencil_impl->current_renderbuffer) {
6007 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6008 checkGLcall("glFramebufferRenderbufferEXT()");
6009 } else {
6010 IWineD3DBaseTextureImpl *texture_impl;
6011 GLenum texttarget, target;
6012 GLint old_binding = 0;
6014 texttarget = depth_stencil_impl->glDescription.target;
6015 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
6016 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6018 IWineD3DSurface_PreLoad(depth_stencil);
6020 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6021 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6022 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6023 glBindTexture(target, old_binding);
6025 /* Update base texture states array */
6026 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6027 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6028 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6029 if (texture_impl->baseTexture.bindCount) {
6030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6033 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6036 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6037 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6038 checkGLcall("glFramebufferTexture2DEXT()");
6040 } else {
6041 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6042 checkGLcall("glFramebufferTexture2DEXT()");
6046 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6048 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6050 TRACE("Set render target %u to %p\n", idx, render_target);
6052 if (rtimpl) {
6053 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6054 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6055 } else {
6056 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6057 checkGLcall("glFramebufferTexture2DEXT()");
6059 This->draw_buffers[idx] = GL_NONE;
6063 static void check_fbo_status(IWineD3DDevice *iface) {
6064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6065 GLenum status;
6067 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6068 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6069 TRACE("FBO complete\n");
6070 } else {
6071 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6073 /* Dump the FBO attachments */
6074 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
6075 IWineD3DSurfaceImpl *attachment;
6076 int i;
6078 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6079 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6080 if (attachment) {
6081 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6082 attachment->pow2Width, attachment->pow2Height);
6085 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6086 if (attachment) {
6087 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6088 attachment->pow2Width, attachment->pow2Height);
6094 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6096 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6097 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6099 if (!ds_impl) return FALSE;
6101 if (ds_impl->current_renderbuffer) {
6102 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6103 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6106 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6107 rt_impl->pow2Height != ds_impl->pow2Height);
6110 void apply_fbo_state(IWineD3DDevice *iface) {
6111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6112 unsigned int i;
6114 if (This->render_offscreen) {
6115 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6117 /* Apply render targets */
6118 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6119 IWineD3DSurface *render_target = This->render_targets[i];
6120 if (This->fbo_color_attachments[i] != render_target) {
6121 set_render_target_fbo(iface, i, render_target);
6122 This->fbo_color_attachments[i] = render_target;
6126 /* Apply depth targets */
6127 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6128 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6129 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6131 if (This->stencilBufferTarget) {
6132 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6134 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6135 This->fbo_depth_attachment = This->stencilBufferTarget;
6138 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6139 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6140 checkGLcall("glDrawBuffers()");
6141 } else {
6142 glDrawBuffer(This->draw_buffers[0]);
6143 checkGLcall("glDrawBuffer()");
6145 } else {
6146 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6149 check_fbo_status(iface);
6152 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6153 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6155 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6156 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6157 GLenum gl_filter;
6159 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6160 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6161 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6162 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6164 switch (filter) {
6165 case WINED3DTEXF_LINEAR:
6166 gl_filter = GL_LINEAR;
6167 break;
6169 default:
6170 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6171 case WINED3DTEXF_NONE:
6172 case WINED3DTEXF_POINT:
6173 gl_filter = GL_NEAREST;
6174 break;
6177 /* Attach src surface to src fbo */
6178 src_swapchain = get_swapchain(src_surface);
6179 if (src_swapchain) {
6180 GLenum buffer;
6182 TRACE("Source surface %p is onscreen\n", src_surface);
6183 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6185 ENTER_GL();
6186 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6187 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6188 glReadBuffer(buffer);
6189 checkGLcall("glReadBuffer()");
6191 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6192 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6193 } else {
6194 TRACE("Source surface %p is offscreen\n", src_surface);
6195 ENTER_GL();
6196 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6197 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6198 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6199 checkGLcall("glReadBuffer()");
6201 LEAVE_GL();
6203 /* Attach dst surface to dst fbo */
6204 dst_swapchain = get_swapchain(dst_surface);
6205 if (dst_swapchain) {
6206 GLenum buffer;
6208 TRACE("Destination surface %p is onscreen\n", dst_surface);
6209 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6211 ENTER_GL();
6212 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6213 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6214 glDrawBuffer(buffer);
6215 checkGLcall("glDrawBuffer()");
6217 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6218 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6219 } else {
6220 TRACE("Destination surface %p is offscreen\n", dst_surface);
6222 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6223 if(!src_swapchain) {
6224 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6227 ENTER_GL();
6228 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6229 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6230 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6231 checkGLcall("glDrawBuffer()");
6233 glDisable(GL_SCISSOR_TEST);
6234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6236 if (flip) {
6237 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6238 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6239 checkGLcall("glBlitFramebuffer()");
6240 } else {
6241 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6242 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6243 checkGLcall("glBlitFramebuffer()");
6246 if (This->render_offscreen) {
6247 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6248 } else {
6249 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6250 checkGLcall("glBindFramebuffer()");
6253 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6254 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6255 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6256 glDrawBuffer(GL_BACK);
6257 checkGLcall("glDrawBuffer()");
6259 LEAVE_GL();
6262 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6264 WINED3DVIEWPORT viewport;
6266 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6268 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6269 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6270 return WINED3DERR_INVALIDCALL;
6273 /* MSDN says that null disables the render target
6274 but a device must always be associated with a render target
6275 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6277 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6278 for more details
6280 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6281 FIXME("Trying to set render target 0 to NULL\n");
6282 return WINED3DERR_INVALIDCALL;
6284 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6285 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);
6286 return WINED3DERR_INVALIDCALL;
6289 /* If we are trying to set what we already have, don't bother */
6290 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6291 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6292 return WINED3D_OK;
6294 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6295 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6296 This->render_targets[RenderTargetIndex] = pRenderTarget;
6298 /* Render target 0 is special */
6299 if(RenderTargetIndex == 0) {
6300 /* Finally, reset the viewport as the MSDN states. */
6301 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6302 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6303 viewport.X = 0;
6304 viewport.Y = 0;
6305 viewport.MaxZ = 1.0f;
6306 viewport.MinZ = 0.0f;
6307 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6308 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6309 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6311 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6313 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6314 * ctx properly.
6315 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6316 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6318 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6320 return WINED3D_OK;
6323 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6325 HRESULT hr = WINED3D_OK;
6326 IWineD3DSurface *tmp;
6328 TRACE("(%p) Swapping z-buffer\n",This);
6330 if (pNewZStencil == This->stencilBufferTarget) {
6331 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6332 } else {
6333 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6334 * depending on the renter target implementation being used.
6335 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6336 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6337 * stencil buffer and incure an extra memory overhead
6338 ******************************************************/
6340 tmp = This->stencilBufferTarget;
6341 This->stencilBufferTarget = pNewZStencil;
6342 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6343 /* should we be calling the parent or the wined3d surface? */
6344 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6345 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6346 hr = WINED3D_OK;
6348 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6349 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6352 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6356 return hr;
6359 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6360 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6362 /* TODO: the use of Impl is deprecated. */
6363 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6364 WINED3DLOCKED_RECT lockedRect;
6366 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6368 /* some basic validation checks */
6369 if(This->cursorTexture) {
6370 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6371 ENTER_GL();
6372 glDeleteTextures(1, &This->cursorTexture);
6373 LEAVE_GL();
6374 This->cursorTexture = 0;
6377 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6378 This->haveHardwareCursor = TRUE;
6379 else
6380 This->haveHardwareCursor = FALSE;
6382 if(pCursorBitmap) {
6383 WINED3DLOCKED_RECT rect;
6385 /* MSDN: Cursor must be A8R8G8B8 */
6386 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6387 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6388 return WINED3DERR_INVALIDCALL;
6391 /* MSDN: Cursor must be smaller than the display mode */
6392 if(pSur->currentDesc.Width > This->ddraw_width ||
6393 pSur->currentDesc.Height > This->ddraw_height) {
6394 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);
6395 return WINED3DERR_INVALIDCALL;
6398 if (!This->haveHardwareCursor) {
6399 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6401 /* Do not store the surface's pointer because the application may
6402 * release it after setting the cursor image. Windows doesn't
6403 * addref the set surface, so we can't do this either without
6404 * creating circular refcount dependencies. Copy out the gl texture
6405 * instead.
6407 This->cursorWidth = pSur->currentDesc.Width;
6408 This->cursorHeight = pSur->currentDesc.Height;
6409 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6411 const GlPixelFormatDesc *glDesc;
6412 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6413 char *mem, *bits = (char *)rect.pBits;
6414 GLint intfmt = glDesc->glInternal;
6415 GLint format = glDesc->glFormat;
6416 GLint type = glDesc->glType;
6417 INT height = This->cursorHeight;
6418 INT width = This->cursorWidth;
6419 INT bpp = tableEntry->bpp;
6420 INT i;
6422 /* Reformat the texture memory (pitch and width can be
6423 * different) */
6424 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6425 for(i = 0; i < height; i++)
6426 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6427 IWineD3DSurface_UnlockRect(pCursorBitmap);
6428 ENTER_GL();
6430 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6431 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6432 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6435 /* Make sure that a proper texture unit is selected */
6436 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6437 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6438 checkGLcall("glActiveTextureARB");
6440 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6441 /* Create a new cursor texture */
6442 glGenTextures(1, &This->cursorTexture);
6443 checkGLcall("glGenTextures");
6444 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6445 checkGLcall("glBindTexture");
6446 /* Copy the bitmap memory into the cursor texture */
6447 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6448 HeapFree(GetProcessHeap(), 0, mem);
6449 checkGLcall("glTexImage2D");
6451 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6452 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6453 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6456 LEAVE_GL();
6458 else
6460 FIXME("A cursor texture was not returned.\n");
6461 This->cursorTexture = 0;
6464 else
6466 /* Draw a hardware cursor */
6467 ICONINFO cursorInfo;
6468 HCURSOR cursor;
6469 /* Create and clear maskBits because it is not needed for
6470 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6471 * chunks. */
6472 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6473 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6474 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6475 WINED3DLOCK_NO_DIRTY_UPDATE |
6476 WINED3DLOCK_READONLY
6478 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6479 pSur->currentDesc.Height);
6481 cursorInfo.fIcon = FALSE;
6482 cursorInfo.xHotspot = XHotSpot;
6483 cursorInfo.yHotspot = YHotSpot;
6484 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6485 pSur->currentDesc.Height, 1,
6486 1, &maskBits);
6487 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6488 pSur->currentDesc.Height, 1,
6489 32, lockedRect.pBits);
6490 IWineD3DSurface_UnlockRect(pCursorBitmap);
6491 /* Create our cursor and clean up. */
6492 cursor = CreateIconIndirect(&cursorInfo);
6493 SetCursor(cursor);
6494 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6495 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6496 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6497 This->hardwareCursor = cursor;
6498 HeapFree(GetProcessHeap(), 0, maskBits);
6502 This->xHotSpot = XHotSpot;
6503 This->yHotSpot = YHotSpot;
6504 return WINED3D_OK;
6507 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6509 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6511 This->xScreenSpace = XScreenSpace;
6512 This->yScreenSpace = YScreenSpace;
6514 return;
6518 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6520 BOOL oldVisible = This->bCursorVisible;
6521 POINT pt;
6523 TRACE("(%p) : visible(%d)\n", This, bShow);
6526 * When ShowCursor is first called it should make the cursor appear at the OS's last
6527 * known cursor position. Because of this, some applications just repetitively call
6528 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6530 GetCursorPos(&pt);
6531 This->xScreenSpace = pt.x;
6532 This->yScreenSpace = pt.y;
6534 if (This->haveHardwareCursor) {
6535 This->bCursorVisible = bShow;
6536 if (bShow)
6537 SetCursor(This->hardwareCursor);
6538 else
6539 SetCursor(NULL);
6541 else
6543 if (This->cursorTexture)
6544 This->bCursorVisible = bShow;
6547 return oldVisible;
6550 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6552 TRACE("(%p) : state (%u)\n", This, This->state);
6553 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6554 switch (This->state) {
6555 case WINED3D_OK:
6556 return WINED3D_OK;
6557 case WINED3DERR_DEVICELOST:
6559 ResourceList *resourceList = This->resources;
6560 while (NULL != resourceList) {
6561 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6562 return WINED3DERR_DEVICENOTRESET;
6563 resourceList = resourceList->next;
6565 return WINED3DERR_DEVICELOST;
6567 case WINED3DERR_DRIVERINTERNALERROR:
6568 return WINED3DERR_DRIVERINTERNALERROR;
6571 /* Unknown state */
6572 return WINED3DERR_DRIVERINTERNALERROR;
6576 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6578 /** FIXME: Resource tracking needs to be done,
6579 * The closes we can do to this is set the priorities of all managed textures low
6580 * and then reset them.
6581 ***********************************************************/
6582 FIXME("(%p) : stub\n", This);
6583 return WINED3D_OK;
6586 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6587 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6589 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6590 if(surface->Flags & SFLAG_DIBSECTION) {
6591 /* Release the DC */
6592 SelectObject(surface->hDC, surface->dib.holdbitmap);
6593 DeleteDC(surface->hDC);
6594 /* Release the DIB section */
6595 DeleteObject(surface->dib.DIBsection);
6596 surface->dib.bitmap_data = NULL;
6597 surface->resource.allocatedMemory = NULL;
6598 surface->Flags &= ~SFLAG_DIBSECTION;
6600 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6601 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6602 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6603 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6604 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6605 } else {
6606 surface->pow2Width = surface->pow2Height = 1;
6607 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6608 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6610 if(surface->glDescription.textureName) {
6611 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6612 ENTER_GL();
6613 glDeleteTextures(1, &surface->glDescription.textureName);
6614 LEAVE_GL();
6615 surface->glDescription.textureName = 0;
6616 surface->Flags &= ~SFLAG_CLIENT;
6618 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6619 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6620 surface->Flags |= SFLAG_NONPOW2;
6621 } else {
6622 surface->Flags &= ~SFLAG_NONPOW2;
6624 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6625 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6628 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6630 IWineD3DSwapChainImpl *swapchain;
6631 HRESULT hr;
6632 BOOL DisplayModeChanged = FALSE;
6633 WINED3DDISPLAYMODE mode;
6634 TRACE("(%p)\n", This);
6636 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6637 if(FAILED(hr)) {
6638 ERR("Failed to get the first implicit swapchain\n");
6639 return hr;
6642 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6643 * on an existing gl context, so there's no real need for recreation.
6645 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6647 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6649 TRACE("New params:\n");
6650 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6651 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6652 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6653 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6654 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6655 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6656 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6657 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6658 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6659 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6660 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6661 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6662 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6664 /* No special treatment of these parameters. Just store them */
6665 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6666 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6667 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6668 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6670 /* What to do about these? */
6671 if(pPresentationParameters->BackBufferCount != 0 &&
6672 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6673 ERR("Cannot change the back buffer count yet\n");
6675 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6676 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6677 ERR("Cannot change the back buffer format yet\n");
6679 if(pPresentationParameters->hDeviceWindow != NULL &&
6680 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6681 ERR("Cannot change the device window yet\n");
6683 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6684 ERR("What do do about a changed auto depth stencil parameter?\n");
6687 if(pPresentationParameters->Windowed) {
6688 mode.Width = swapchain->orig_width;
6689 mode.Height = swapchain->orig_height;
6690 mode.RefreshRate = 0;
6691 mode.Format = swapchain->presentParms.BackBufferFormat;
6692 } else {
6693 mode.Width = pPresentationParameters->BackBufferWidth;
6694 mode.Height = pPresentationParameters->BackBufferHeight;
6695 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6696 mode.Format = swapchain->presentParms.BackBufferFormat;
6699 /* Should Width == 800 && Height == 0 set 800x600? */
6700 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6701 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6702 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6704 WINED3DVIEWPORT vp;
6705 int i;
6707 vp.X = 0;
6708 vp.Y = 0;
6709 vp.Width = pPresentationParameters->BackBufferWidth;
6710 vp.Height = pPresentationParameters->BackBufferHeight;
6711 vp.MinZ = 0;
6712 vp.MaxZ = 1;
6714 if(!pPresentationParameters->Windowed) {
6715 DisplayModeChanged = TRUE;
6717 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6718 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6720 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6721 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6722 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6725 /* Now set the new viewport */
6726 IWineD3DDevice_SetViewport(iface, &vp);
6729 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6730 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6731 DisplayModeChanged) {
6733 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6734 if(!pPresentationParameters->Windowed) {
6735 IWineD3DDevice_SetFullscreen(iface, TRUE);
6738 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6740 /* Switching out of fullscreen mode? First set the original res, then change the window */
6741 if(pPresentationParameters->Windowed) {
6742 IWineD3DDevice_SetFullscreen(iface, FALSE);
6744 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6747 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6748 return WINED3D_OK;
6751 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6753 /** FIXME: always true at the moment **/
6754 if(!bEnableDialogs) {
6755 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6757 return WINED3D_OK;
6761 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6763 TRACE("(%p) : pParameters %p\n", This, pParameters);
6765 *pParameters = This->createParms;
6766 return WINED3D_OK;
6769 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6770 IWineD3DSwapChain *swapchain;
6771 HRESULT hrc = WINED3D_OK;
6773 TRACE("Relaying to swapchain\n");
6775 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6776 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6777 IWineD3DSwapChain_Release(swapchain);
6779 return;
6782 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6783 IWineD3DSwapChain *swapchain;
6784 HRESULT hrc = WINED3D_OK;
6786 TRACE("Relaying to swapchain\n");
6788 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6789 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6790 IWineD3DSwapChain_Release(swapchain);
6792 return;
6796 /** ********************************************************
6797 * Notification functions
6798 ** ********************************************************/
6799 /** This function must be called in the release of a resource when ref == 0,
6800 * the contents of resource must still be correct,
6801 * any handels to other resource held by the caller must be closed
6802 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6803 *****************************************************/
6804 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6806 ResourceList* resourceList;
6808 TRACE("(%p) : resource %p\n", This, resource);
6809 /* add a new texture to the frot of the linked list */
6810 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6811 resourceList->resource = resource;
6813 /* Get the old head */
6814 resourceList->next = This->resources;
6816 This->resources = resourceList;
6817 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6819 return;
6822 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6824 ResourceList* resourceList = NULL;
6825 ResourceList* previousResourceList = NULL;
6827 TRACE("(%p) : resource %p\n", This, resource);
6829 resourceList = This->resources;
6831 while (resourceList != NULL) {
6832 if(resourceList->resource == resource) break;
6833 previousResourceList = resourceList;
6834 resourceList = resourceList->next;
6837 if (resourceList == NULL) {
6838 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6839 return;
6840 } else {
6841 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6843 /* make sure we don't leave a hole in the list */
6844 if (previousResourceList != NULL) {
6845 previousResourceList->next = resourceList->next;
6846 } else {
6847 This->resources = resourceList->next;
6850 return;
6854 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6856 int counter;
6858 TRACE("(%p) : resource %p\n", This, resource);
6859 switch(IWineD3DResource_GetType(resource)){
6860 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6861 case WINED3DRTYPE_SURFACE: {
6862 unsigned int i;
6864 /* Cleanup any FBO attachments if d3d is enabled */
6865 if(This->d3d_initialized) {
6866 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6867 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6869 TRACE("Last active render target destroyed\n");
6870 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6871 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6872 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6873 * and the lastActiveRenderTarget member shouldn't matter
6875 if(swapchain) {
6876 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6877 TRACE("Activating primary back buffer\n");
6878 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6879 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6880 /* Single buffering environment */
6881 TRACE("Activating primary front buffer\n");
6882 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6883 } else {
6884 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6885 /* Implicit render target destroyed, that means the device is being destroyed
6886 * whatever we set here, it shouldn't matter
6888 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6890 } else {
6891 /* May happen during ddraw uninitialization */
6892 TRACE("Render target set, but swapchain does not exist!\n");
6893 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
6897 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6898 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6899 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6900 set_render_target_fbo(iface, i, NULL);
6901 This->fbo_color_attachments[i] = NULL;
6904 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6905 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6906 set_depth_stencil_fbo(iface, NULL);
6907 This->fbo_depth_attachment = NULL;
6911 break;
6913 case WINED3DRTYPE_TEXTURE:
6914 case WINED3DRTYPE_CUBETEXTURE:
6915 case WINED3DRTYPE_VOLUMETEXTURE:
6916 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6917 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6918 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6919 This->stateBlock->textures[counter] = NULL;
6921 if (This->updateStateBlock != This->stateBlock ){
6922 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6923 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6924 This->updateStateBlock->textures[counter] = NULL;
6928 break;
6929 case WINED3DRTYPE_VOLUME:
6930 /* TODO: nothing really? */
6931 break;
6932 case WINED3DRTYPE_VERTEXBUFFER:
6933 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6935 int streamNumber;
6936 TRACE("Cleaning up stream pointers\n");
6938 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6939 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6940 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6942 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6943 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6944 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6945 This->updateStateBlock->streamSource[streamNumber] = 0;
6946 /* Set changed flag? */
6949 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) */
6950 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6951 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6952 This->stateBlock->streamSource[streamNumber] = 0;
6955 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6956 else { /* This shouldn't happen */
6957 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6959 #endif
6963 break;
6964 case WINED3DRTYPE_INDEXBUFFER:
6965 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6966 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6967 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6968 This->updateStateBlock->pIndexData = NULL;
6971 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6972 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6973 This->stateBlock->pIndexData = NULL;
6977 break;
6978 default:
6979 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6980 break;
6984 /* Remove the resoruce from the resourceStore */
6985 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6987 TRACE("Resource released\n");
6991 /**********************************************************
6992 * IWineD3DDevice VTbl follows
6993 **********************************************************/
6995 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6997 /*** IUnknown methods ***/
6998 IWineD3DDeviceImpl_QueryInterface,
6999 IWineD3DDeviceImpl_AddRef,
7000 IWineD3DDeviceImpl_Release,
7001 /*** IWineD3DDevice methods ***/
7002 IWineD3DDeviceImpl_GetParent,
7003 /*** Creation methods**/
7004 IWineD3DDeviceImpl_CreateVertexBuffer,
7005 IWineD3DDeviceImpl_CreateIndexBuffer,
7006 IWineD3DDeviceImpl_CreateStateBlock,
7007 IWineD3DDeviceImpl_CreateSurface,
7008 IWineD3DDeviceImpl_CreateTexture,
7009 IWineD3DDeviceImpl_CreateVolumeTexture,
7010 IWineD3DDeviceImpl_CreateVolume,
7011 IWineD3DDeviceImpl_CreateCubeTexture,
7012 IWineD3DDeviceImpl_CreateQuery,
7013 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7014 IWineD3DDeviceImpl_CreateVertexDeclaration,
7015 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7016 IWineD3DDeviceImpl_CreateVertexShader,
7017 IWineD3DDeviceImpl_CreatePixelShader,
7018 IWineD3DDeviceImpl_CreatePalette,
7019 /*** Odd functions **/
7020 IWineD3DDeviceImpl_Init3D,
7021 IWineD3DDeviceImpl_Uninit3D,
7022 IWineD3DDeviceImpl_SetFullscreen,
7023 IWineD3DDeviceImpl_SetMultithreaded,
7024 IWineD3DDeviceImpl_EvictManagedResources,
7025 IWineD3DDeviceImpl_GetAvailableTextureMem,
7026 IWineD3DDeviceImpl_GetBackBuffer,
7027 IWineD3DDeviceImpl_GetCreationParameters,
7028 IWineD3DDeviceImpl_GetDeviceCaps,
7029 IWineD3DDeviceImpl_GetDirect3D,
7030 IWineD3DDeviceImpl_GetDisplayMode,
7031 IWineD3DDeviceImpl_SetDisplayMode,
7032 IWineD3DDeviceImpl_GetHWND,
7033 IWineD3DDeviceImpl_SetHWND,
7034 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7035 IWineD3DDeviceImpl_GetRasterStatus,
7036 IWineD3DDeviceImpl_GetSwapChain,
7037 IWineD3DDeviceImpl_Reset,
7038 IWineD3DDeviceImpl_SetDialogBoxMode,
7039 IWineD3DDeviceImpl_SetCursorProperties,
7040 IWineD3DDeviceImpl_SetCursorPosition,
7041 IWineD3DDeviceImpl_ShowCursor,
7042 IWineD3DDeviceImpl_TestCooperativeLevel,
7043 /*** Getters and setters **/
7044 IWineD3DDeviceImpl_SetClipPlane,
7045 IWineD3DDeviceImpl_GetClipPlane,
7046 IWineD3DDeviceImpl_SetClipStatus,
7047 IWineD3DDeviceImpl_GetClipStatus,
7048 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7049 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7050 IWineD3DDeviceImpl_SetDepthStencilSurface,
7051 IWineD3DDeviceImpl_GetDepthStencilSurface,
7052 IWineD3DDeviceImpl_SetFVF,
7053 IWineD3DDeviceImpl_GetFVF,
7054 IWineD3DDeviceImpl_SetGammaRamp,
7055 IWineD3DDeviceImpl_GetGammaRamp,
7056 IWineD3DDeviceImpl_SetIndices,
7057 IWineD3DDeviceImpl_GetIndices,
7058 IWineD3DDeviceImpl_SetBaseVertexIndex,
7059 IWineD3DDeviceImpl_GetBaseVertexIndex,
7060 IWineD3DDeviceImpl_SetLight,
7061 IWineD3DDeviceImpl_GetLight,
7062 IWineD3DDeviceImpl_SetLightEnable,
7063 IWineD3DDeviceImpl_GetLightEnable,
7064 IWineD3DDeviceImpl_SetMaterial,
7065 IWineD3DDeviceImpl_GetMaterial,
7066 IWineD3DDeviceImpl_SetNPatchMode,
7067 IWineD3DDeviceImpl_GetNPatchMode,
7068 IWineD3DDeviceImpl_SetPaletteEntries,
7069 IWineD3DDeviceImpl_GetPaletteEntries,
7070 IWineD3DDeviceImpl_SetPixelShader,
7071 IWineD3DDeviceImpl_GetPixelShader,
7072 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7073 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7074 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7075 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7076 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7077 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7078 IWineD3DDeviceImpl_SetRenderState,
7079 IWineD3DDeviceImpl_GetRenderState,
7080 IWineD3DDeviceImpl_SetRenderTarget,
7081 IWineD3DDeviceImpl_GetRenderTarget,
7082 IWineD3DDeviceImpl_SetFrontBackBuffers,
7083 IWineD3DDeviceImpl_SetSamplerState,
7084 IWineD3DDeviceImpl_GetSamplerState,
7085 IWineD3DDeviceImpl_SetScissorRect,
7086 IWineD3DDeviceImpl_GetScissorRect,
7087 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7088 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7089 IWineD3DDeviceImpl_SetStreamSource,
7090 IWineD3DDeviceImpl_GetStreamSource,
7091 IWineD3DDeviceImpl_SetStreamSourceFreq,
7092 IWineD3DDeviceImpl_GetStreamSourceFreq,
7093 IWineD3DDeviceImpl_SetTexture,
7094 IWineD3DDeviceImpl_GetTexture,
7095 IWineD3DDeviceImpl_SetTextureStageState,
7096 IWineD3DDeviceImpl_GetTextureStageState,
7097 IWineD3DDeviceImpl_SetTransform,
7098 IWineD3DDeviceImpl_GetTransform,
7099 IWineD3DDeviceImpl_SetVertexDeclaration,
7100 IWineD3DDeviceImpl_GetVertexDeclaration,
7101 IWineD3DDeviceImpl_SetVertexShader,
7102 IWineD3DDeviceImpl_GetVertexShader,
7103 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7104 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7105 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7106 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7107 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7108 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7109 IWineD3DDeviceImpl_SetViewport,
7110 IWineD3DDeviceImpl_GetViewport,
7111 IWineD3DDeviceImpl_MultiplyTransform,
7112 IWineD3DDeviceImpl_ValidateDevice,
7113 IWineD3DDeviceImpl_ProcessVertices,
7114 /*** State block ***/
7115 IWineD3DDeviceImpl_BeginStateBlock,
7116 IWineD3DDeviceImpl_EndStateBlock,
7117 /*** Scene management ***/
7118 IWineD3DDeviceImpl_BeginScene,
7119 IWineD3DDeviceImpl_EndScene,
7120 IWineD3DDeviceImpl_Present,
7121 IWineD3DDeviceImpl_Clear,
7122 /*** Drawing ***/
7123 IWineD3DDeviceImpl_DrawPrimitive,
7124 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7125 IWineD3DDeviceImpl_DrawPrimitiveUP,
7126 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7127 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7128 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7129 IWineD3DDeviceImpl_DrawRectPatch,
7130 IWineD3DDeviceImpl_DrawTriPatch,
7131 IWineD3DDeviceImpl_DeletePatch,
7132 IWineD3DDeviceImpl_ColorFill,
7133 IWineD3DDeviceImpl_UpdateTexture,
7134 IWineD3DDeviceImpl_UpdateSurface,
7135 IWineD3DDeviceImpl_GetFrontBufferData,
7136 /*** object tracking ***/
7137 IWineD3DDeviceImpl_ResourceReleased
7141 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7142 WINED3DRS_ALPHABLENDENABLE ,
7143 WINED3DRS_ALPHAFUNC ,
7144 WINED3DRS_ALPHAREF ,
7145 WINED3DRS_ALPHATESTENABLE ,
7146 WINED3DRS_BLENDOP ,
7147 WINED3DRS_COLORWRITEENABLE ,
7148 WINED3DRS_DESTBLEND ,
7149 WINED3DRS_DITHERENABLE ,
7150 WINED3DRS_FILLMODE ,
7151 WINED3DRS_FOGDENSITY ,
7152 WINED3DRS_FOGEND ,
7153 WINED3DRS_FOGSTART ,
7154 WINED3DRS_LASTPIXEL ,
7155 WINED3DRS_SHADEMODE ,
7156 WINED3DRS_SRCBLEND ,
7157 WINED3DRS_STENCILENABLE ,
7158 WINED3DRS_STENCILFAIL ,
7159 WINED3DRS_STENCILFUNC ,
7160 WINED3DRS_STENCILMASK ,
7161 WINED3DRS_STENCILPASS ,
7162 WINED3DRS_STENCILREF ,
7163 WINED3DRS_STENCILWRITEMASK ,
7164 WINED3DRS_STENCILZFAIL ,
7165 WINED3DRS_TEXTUREFACTOR ,
7166 WINED3DRS_WRAP0 ,
7167 WINED3DRS_WRAP1 ,
7168 WINED3DRS_WRAP2 ,
7169 WINED3DRS_WRAP3 ,
7170 WINED3DRS_WRAP4 ,
7171 WINED3DRS_WRAP5 ,
7172 WINED3DRS_WRAP6 ,
7173 WINED3DRS_WRAP7 ,
7174 WINED3DRS_ZENABLE ,
7175 WINED3DRS_ZFUNC ,
7176 WINED3DRS_ZWRITEENABLE
7179 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7180 WINED3DTSS_ADDRESSW ,
7181 WINED3DTSS_ALPHAARG0 ,
7182 WINED3DTSS_ALPHAARG1 ,
7183 WINED3DTSS_ALPHAARG2 ,
7184 WINED3DTSS_ALPHAOP ,
7185 WINED3DTSS_BUMPENVLOFFSET ,
7186 WINED3DTSS_BUMPENVLSCALE ,
7187 WINED3DTSS_BUMPENVMAT00 ,
7188 WINED3DTSS_BUMPENVMAT01 ,
7189 WINED3DTSS_BUMPENVMAT10 ,
7190 WINED3DTSS_BUMPENVMAT11 ,
7191 WINED3DTSS_COLORARG0 ,
7192 WINED3DTSS_COLORARG1 ,
7193 WINED3DTSS_COLORARG2 ,
7194 WINED3DTSS_COLOROP ,
7195 WINED3DTSS_RESULTARG ,
7196 WINED3DTSS_TEXCOORDINDEX ,
7197 WINED3DTSS_TEXTURETRANSFORMFLAGS
7200 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7201 WINED3DSAMP_ADDRESSU ,
7202 WINED3DSAMP_ADDRESSV ,
7203 WINED3DSAMP_ADDRESSW ,
7204 WINED3DSAMP_BORDERCOLOR ,
7205 WINED3DSAMP_MAGFILTER ,
7206 WINED3DSAMP_MINFILTER ,
7207 WINED3DSAMP_MIPFILTER ,
7208 WINED3DSAMP_MIPMAPLODBIAS ,
7209 WINED3DSAMP_MAXMIPLEVEL ,
7210 WINED3DSAMP_MAXANISOTROPY ,
7211 WINED3DSAMP_SRGBTEXTURE ,
7212 WINED3DSAMP_ELEMENTINDEX
7215 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7216 WINED3DRS_AMBIENT ,
7217 WINED3DRS_AMBIENTMATERIALSOURCE ,
7218 WINED3DRS_CLIPPING ,
7219 WINED3DRS_CLIPPLANEENABLE ,
7220 WINED3DRS_COLORVERTEX ,
7221 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7222 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7223 WINED3DRS_FOGDENSITY ,
7224 WINED3DRS_FOGEND ,
7225 WINED3DRS_FOGSTART ,
7226 WINED3DRS_FOGTABLEMODE ,
7227 WINED3DRS_FOGVERTEXMODE ,
7228 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7229 WINED3DRS_LIGHTING ,
7230 WINED3DRS_LOCALVIEWER ,
7231 WINED3DRS_MULTISAMPLEANTIALIAS ,
7232 WINED3DRS_MULTISAMPLEMASK ,
7233 WINED3DRS_NORMALIZENORMALS ,
7234 WINED3DRS_PATCHEDGESTYLE ,
7235 WINED3DRS_POINTSCALE_A ,
7236 WINED3DRS_POINTSCALE_B ,
7237 WINED3DRS_POINTSCALE_C ,
7238 WINED3DRS_POINTSCALEENABLE ,
7239 WINED3DRS_POINTSIZE ,
7240 WINED3DRS_POINTSIZE_MAX ,
7241 WINED3DRS_POINTSIZE_MIN ,
7242 WINED3DRS_POINTSPRITEENABLE ,
7243 WINED3DRS_RANGEFOGENABLE ,
7244 WINED3DRS_SPECULARMATERIALSOURCE ,
7245 WINED3DRS_TWEENFACTOR ,
7246 WINED3DRS_VERTEXBLEND ,
7247 WINED3DRS_CULLMODE ,
7248 WINED3DRS_FOGCOLOR
7251 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7252 WINED3DTSS_TEXCOORDINDEX ,
7253 WINED3DTSS_TEXTURETRANSFORMFLAGS
7256 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7257 WINED3DSAMP_DMAPOFFSET
7260 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7261 DWORD rep = StateTable[state].representative;
7262 DWORD idx;
7263 BYTE shift;
7264 UINT i;
7265 WineD3DContext *context;
7267 if(!rep) return;
7268 for(i = 0; i < This->numContexts; i++) {
7269 context = This->contexts[i];
7270 if(isStateDirty(context, rep)) continue;
7272 context->dirtyArray[context->numDirtyEntries++] = rep;
7273 idx = rep >> 5;
7274 shift = rep & 0x1f;
7275 context->isStateDirty[idx] |= (1 << shift);