wined3d: Keep track of shaders.
[wine/hacks.git] / dlls / wined3d / device.c
blobe0e3bf222658d599561a25d772961c51171bde3e
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
195 This = NULL;
197 return refCount;
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
207 return WINED3D_OK;
210 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
211 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
212 GLenum error, glUsage;
213 DWORD vboUsage = object->resource.usage;
214 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
215 WARN("Creating a vbo failed once, not trying again\n");
216 return;
219 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
221 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
222 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
223 ENTER_GL();
225 /* Make sure that the gl error is cleared. Do not use checkGLcall
226 * here because checkGLcall just prints a fixme and continues. However,
227 * if an error during VBO creation occurs we can fall back to non-vbo operation
228 * with full functionality(but performance loss)
230 while(glGetError() != GL_NO_ERROR);
232 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
233 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
234 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
235 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
236 * to check if the rhw and color values are in the correct format.
239 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
240 error = glGetError();
241 if(object->vbo == 0 || error != GL_NO_ERROR) {
242 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
243 goto error;
246 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
247 error = glGetError();
248 if(error != GL_NO_ERROR) {
249 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
250 goto error;
253 /* Don't use static, because dx apps tend to update the buffer
254 * quite often even if they specify 0 usage. Because we always keep the local copy
255 * we never read from the vbo and can create a write only opengl buffer.
257 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
258 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
259 case WINED3DUSAGE_DYNAMIC:
260 TRACE("Gl usage = GL_STREAM_DRAW\n");
261 glUsage = GL_STREAM_DRAW_ARB;
262 break;
263 case WINED3DUSAGE_WRITEONLY:
264 default:
265 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
266 glUsage = GL_DYNAMIC_DRAW_ARB;
267 break;
270 /* Reserve memory for the buffer. The amount of data won't change
271 * so we are safe with calling glBufferData once with a NULL ptr and
272 * calling glBufferSubData on updates
274 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
275 error = glGetError();
276 if(error != GL_NO_ERROR) {
277 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
278 goto error;
280 object->vbo_size = object->resource.size;
281 object->vbo_usage = glUsage;
283 LEAVE_GL();
285 return;
286 error:
287 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
288 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
289 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
290 object->vbo = 0;
291 object->Flags |= VBFLAG_VBOCREATEFAIL;
292 LEAVE_GL();
293 return;
296 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
297 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
298 IUnknown *parent) {
299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
300 IWineD3DVertexBufferImpl *object;
301 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
302 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
303 BOOL conv;
305 if(Size == 0) {
306 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
307 *ppVertexBuffer = NULL;
308 return WINED3DERR_INVALIDCALL;
309 } else if(Pool == WINED3DPOOL_SCRATCH) {
310 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
311 * anyway, SCRATCH vertex buffers aren't useable anywhere
313 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
314 *ppVertexBuffer = NULL;
315 return WINED3DERR_INVALIDCALL;
318 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
320 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
321 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
323 object->fvf = FVF;
325 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
326 * drawStridedFast (half-life 2).
328 * Basically converting the vertices in the buffer is quite expensive, and observations
329 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
330 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
332 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
333 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
334 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
335 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
336 * dx7 apps.
337 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
338 * more. In this call we can convert dx7 buffers too.
340 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
341 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
342 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
343 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
344 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
345 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
346 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
347 } else if(dxVersion <= 7 && conv) {
348 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
349 } else {
350 CreateVBO(object);
352 return WINED3D_OK;
355 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
356 GLenum error, glUsage;
357 TRACE("Creating VBO for Index Buffer %p\n", object);
359 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
360 * restored on the next draw
362 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
364 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
365 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
366 ENTER_GL();
368 while(glGetError());
370 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
371 error = glGetError();
372 if(error != GL_NO_ERROR || object->vbo == 0) {
373 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
374 goto out;
377 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
378 error = glGetError();
379 if(error != GL_NO_ERROR) {
380 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
381 goto out;
384 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
385 * copy no readback will be needed
387 glUsage = GL_STATIC_DRAW_ARB;
388 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
389 error = glGetError();
390 if(error != GL_NO_ERROR) {
391 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
392 goto out;
394 LEAVE_GL();
395 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
396 return;
398 out:
399 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
400 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
401 LEAVE_GL();
402 object->vbo = 0;
405 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
406 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
407 HANDLE *sharedHandle, IUnknown *parent) {
408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
409 IWineD3DIndexBufferImpl *object;
410 TRACE("(%p) Creating index buffer\n", This);
412 /* Allocate the storage for the device */
413 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
415 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
416 CreateIndexBufferVBO(This, object);
419 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
420 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
421 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
423 return WINED3D_OK;
426 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
429 IWineD3DStateBlockImpl *object;
430 int i, j;
431 HRESULT temp_result;
433 D3DCREATEOBJECTINSTANCE(object, StateBlock)
434 object->blockType = Type;
436 for(i = 0; i < LIGHTMAP_SIZE; i++) {
437 list_init(&object->lightMap[i]);
440 /* Special case - Used during initialization to produce a placeholder stateblock
441 so other functions called can update a state block */
442 if (Type == WINED3DSBT_INIT) {
443 /* Don't bother increasing the reference count otherwise a device will never
444 be freed due to circular dependencies */
445 return WINED3D_OK;
448 temp_result = allocate_shader_constants(object);
449 if (WINED3D_OK != temp_result)
450 return temp_result;
452 /* Otherwise, might as well set the whole state block to the appropriate values */
453 if (This->stateBlock != NULL)
454 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
455 else
456 memset(object->streamFreq, 1, sizeof(object->streamFreq));
458 /* Reset the ref and type after kludging it */
459 object->wineD3DDevice = This;
460 object->ref = 1;
461 object->blockType = Type;
463 TRACE("Updating changed flags appropriate for type %d\n", Type);
465 if (Type == WINED3DSBT_ALL) {
467 TRACE("ALL => Pretend everything has changed\n");
468 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
470 /* Lights are not part of the changed / set structure */
471 for(j = 0; j < LIGHTMAP_SIZE; j++) {
472 struct list *e;
473 LIST_FOR_EACH(e, &object->lightMap[j]) {
474 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
475 light->changed = TRUE;
476 light->enabledChanged = TRUE;
479 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
480 object->contained_render_states[j - 1] = j;
482 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
483 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
484 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
485 object->contained_transform_states[j - 1] = j;
487 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
488 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
489 object->contained_vs_consts_f[j] = j;
491 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
492 for(j = 0; j < MAX_CONST_I; j++) {
493 object->contained_vs_consts_i[j] = j;
495 object->num_contained_vs_consts_i = MAX_CONST_I;
496 for(j = 0; j < MAX_CONST_B; j++) {
497 object->contained_vs_consts_b[j] = j;
499 object->num_contained_vs_consts_b = MAX_CONST_B;
500 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
501 object->contained_ps_consts_f[j] = j;
503 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
504 for(j = 0; j < MAX_CONST_I; j++) {
505 object->contained_ps_consts_i[j] = j;
507 object->num_contained_ps_consts_i = MAX_CONST_I;
508 for(j = 0; j < MAX_CONST_B; j++) {
509 object->contained_ps_consts_b[j] = j;
511 object->num_contained_ps_consts_b = MAX_CONST_B;
512 for(i = 0; i < MAX_TEXTURES; i++) {
513 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
514 object->contained_tss_states[object->num_contained_tss_states].stage = i;
515 object->contained_tss_states[object->num_contained_tss_states].state = j;
516 object->num_contained_tss_states++;
519 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
520 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
521 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
522 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
523 object->num_contained_sampler_states++;
527 for(i = 0; i < MAX_STREAMS; i++) {
528 if(object->streamSource[i]) {
529 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
532 if(object->pIndexData) {
533 IWineD3DIndexBuffer_AddRef(object->pIndexData);
535 if(object->vertexShader) {
536 IWineD3DVertexShader_AddRef(object->vertexShader);
538 if(object->pixelShader) {
539 IWineD3DPixelShader_AddRef(object->pixelShader);
542 } else if (Type == WINED3DSBT_PIXELSTATE) {
544 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
545 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
547 object->changed.pixelShader = TRUE;
549 /* Pixel Shader Constants */
550 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
551 object->contained_ps_consts_f[i] = i;
552 object->changed.pixelShaderConstantsF[i] = TRUE;
554 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
555 for (i = 0; i < MAX_CONST_B; ++i) {
556 object->contained_ps_consts_b[i] = i;
557 object->changed.pixelShaderConstantsB[i] = TRUE;
559 object->num_contained_ps_consts_b = MAX_CONST_B;
560 for (i = 0; i < MAX_CONST_I; ++i) {
561 object->contained_ps_consts_i[i] = i;
562 object->changed.pixelShaderConstantsI[i] = TRUE;
564 object->num_contained_ps_consts_i = MAX_CONST_I;
566 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
567 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
568 object->contained_render_states[i] = SavedPixelStates_R[i];
570 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
571 for (j = 0; j < MAX_TEXTURES; j++) {
572 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
573 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
574 object->contained_tss_states[object->num_contained_tss_states].stage = j;
575 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
576 object->num_contained_tss_states++;
579 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
580 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
581 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
582 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
583 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
584 object->num_contained_sampler_states++;
587 if(object->pixelShader) {
588 IWineD3DPixelShader_AddRef(object->pixelShader);
591 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
592 * on them. This makes releasing the buffer easier
594 for(i = 0; i < MAX_STREAMS; i++) {
595 object->streamSource[i] = NULL;
597 object->pIndexData = NULL;
598 object->vertexShader = NULL;
600 } else if (Type == WINED3DSBT_VERTEXSTATE) {
602 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
603 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
605 object->changed.vertexShader = TRUE;
607 /* Vertex Shader Constants */
608 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
609 object->changed.vertexShaderConstantsF[i] = TRUE;
610 object->contained_vs_consts_f[i] = i;
612 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
613 for (i = 0; i < MAX_CONST_B; ++i) {
614 object->changed.vertexShaderConstantsB[i] = TRUE;
615 object->contained_vs_consts_b[i] = i;
617 object->num_contained_vs_consts_b = MAX_CONST_B;
618 for (i = 0; i < MAX_CONST_I; ++i) {
619 object->changed.vertexShaderConstantsI[i] = TRUE;
620 object->contained_vs_consts_i[i] = i;
622 object->num_contained_vs_consts_i = MAX_CONST_I;
623 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
624 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
625 object->contained_render_states[i] = SavedVertexStates_R[i];
627 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
628 for (j = 0; j < MAX_TEXTURES; j++) {
629 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
630 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
631 object->contained_tss_states[object->num_contained_tss_states].stage = j;
632 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
633 object->num_contained_tss_states++;
636 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
637 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
638 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
639 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
640 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
641 object->num_contained_sampler_states++;
645 for(j = 0; j < LIGHTMAP_SIZE; j++) {
646 struct list *e;
647 LIST_FOR_EACH(e, &object->lightMap[j]) {
648 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
649 light->changed = TRUE;
650 light->enabledChanged = TRUE;
654 for(i = 0; i < MAX_STREAMS; i++) {
655 if(object->streamSource[i]) {
656 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
659 if(object->vertexShader) {
660 IWineD3DVertexShader_AddRef(object->vertexShader);
662 object->pIndexData = NULL;
663 object->pixelShader = NULL;
664 } else {
665 FIXME("Unrecognized state block type %d\n", Type);
668 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
669 return WINED3D_OK;
672 /* ************************************
673 MSDN:
674 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
676 Discard
677 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
679 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.
681 ******************************** */
683 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) {
684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
685 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
686 unsigned int Size = 1;
687 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
688 TRACE("(%p) Create surface\n",This);
690 /** FIXME: Check ranges on the inputs are valid
691 * MSDN
692 * MultisampleQuality
693 * [in] Quality level. The valid range is between zero and one less than the level
694 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
695 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
696 * values of paired render targets, depth stencil surfaces, and the MultiSample type
697 * must all match.
698 *******************************/
702 * TODO: Discard MSDN
703 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
705 * If this flag is set, the contents of the depth stencil buffer will be
706 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
707 * with a different depth surface.
709 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
710 ***************************/
712 if(MultisampleQuality > 0) {
713 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
714 MultisampleQuality=0;
717 /** FIXME: Check that the format is supported
718 * by the device.
719 *******************************/
721 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
722 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
723 * space!
724 *********************************/
725 if (WINED3DFMT_UNKNOWN == Format) {
726 Size = 0;
727 } else if (Format == WINED3DFMT_DXT1) {
728 /* DXT1 is half byte per pixel */
729 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
731 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
732 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
733 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
734 } else {
735 /* The pitch is a multiple of 4 bytes */
736 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
737 Size *= Height;
740 /** Create and initialise the surface resource **/
741 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
742 /* "Standalone" surface */
743 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
745 object->currentDesc.Width = Width;
746 object->currentDesc.Height = Height;
747 object->currentDesc.MultiSampleType = MultiSample;
748 object->currentDesc.MultiSampleQuality = MultisampleQuality;
749 object->glDescription.level = Level;
751 /* Flags */
752 object->Flags = 0;
753 object->Flags |= Discard ? SFLAG_DISCARD : 0;
754 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
755 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
758 if (WINED3DFMT_UNKNOWN != Format) {
759 object->bytesPerPixel = tableEntry->bpp;
760 } else {
761 object->bytesPerPixel = 0;
764 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
766 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
768 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
769 * this function is too deep to need to care about things like this.
770 * Levels need to be checked too, and possibly Type since they all affect what can be done.
771 * ****************************************/
772 switch(Pool) {
773 case WINED3DPOOL_SCRATCH:
774 if(!Lockable)
775 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
776 "which are mutually exclusive, setting lockable to TRUE\n");
777 Lockable = TRUE;
778 break;
779 case WINED3DPOOL_SYSTEMMEM:
780 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
781 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
782 case WINED3DPOOL_MANAGED:
783 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
784 "Usage of DYNAMIC which are mutually exclusive, not doing "
785 "anything just telling you.\n");
786 break;
787 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
788 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
789 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
790 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
791 break;
792 default:
793 FIXME("(%p) Unknown pool %d\n", This, Pool);
794 break;
797 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
798 FIXME("Trying to create a render target that isn't in the default pool\n");
801 /* mark the texture as dirty so that it gets loaded first time around*/
802 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
803 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
804 This, Width, Height, Format, debug_d3dformat(Format),
805 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
807 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
808 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
809 This->ddraw_primary = (IWineD3DSurface *) object;
811 /* Look at the implementation and set the correct Vtable */
812 switch(Impl) {
813 case SURFACE_OPENGL:
814 /* Check if a 3D adapter is available when creating gl surfaces */
815 if(!This->adapter) {
816 ERR("OpenGL surfaces are not available without opengl\n");
817 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
818 HeapFree(GetProcessHeap(), 0, object);
819 return WINED3DERR_NOTAVAILABLE;
821 break;
823 case SURFACE_GDI:
824 object->lpVtbl = &IWineGDISurface_Vtbl;
825 break;
827 default:
828 /* To be sure to catch this */
829 ERR("Unknown requested surface implementation %d!\n", Impl);
830 IWineD3DSurface_Release((IWineD3DSurface *) object);
831 return WINED3DERR_INVALIDCALL;
834 list_init(&object->renderbuffers);
836 /* Call the private setup routine */
837 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
841 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
842 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
843 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
844 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
847 IWineD3DTextureImpl *object;
848 unsigned int i;
849 UINT tmpW;
850 UINT tmpH;
851 HRESULT hr;
852 unsigned int pow2Width;
853 unsigned int pow2Height;
854 const GlPixelFormatDesc *glDesc;
855 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
858 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
859 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
860 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
862 /* TODO: It should only be possible to create textures for formats
863 that are reported as supported */
864 if (WINED3DFMT_UNKNOWN >= Format) {
865 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
866 return WINED3DERR_INVALIDCALL;
869 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
870 D3DINITIALIZEBASETEXTURE(object->baseTexture);
871 object->width = Width;
872 object->height = Height;
874 /** Non-power2 support **/
875 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
876 pow2Width = Width;
877 pow2Height = Height;
878 } else {
879 /* Find the nearest pow2 match */
880 pow2Width = pow2Height = 1;
881 while (pow2Width < Width) pow2Width <<= 1;
882 while (pow2Height < Height) pow2Height <<= 1;
884 if(pow2Width != Width || pow2Height != Height) {
885 if(Levels > 1) {
886 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
887 HeapFree(GetProcessHeap(), 0, object);
888 *ppTexture = NULL;
889 return WINED3DERR_INVALIDCALL;
890 } else {
891 Levels = 1;
896 /** FIXME: add support for real non-power-two if it's provided by the video card **/
897 /* Precalculated scaling for 'faked' non power of two texture coords */
898 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
899 (Width != pow2Width || Height != pow2Height)) {
900 object->baseTexture.pow2Matrix[0] = (float)Width;
901 object->baseTexture.pow2Matrix[5] = (float)Height;
902 object->baseTexture.pow2Matrix[10] = 1.0;
903 object->baseTexture.pow2Matrix[15] = 1.0;
904 object->target = GL_TEXTURE_RECTANGLE_ARB;
905 } else {
906 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
907 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
908 object->baseTexture.pow2Matrix[10] = 1.0;
909 object->baseTexture.pow2Matrix[15] = 1.0;
910 object->target = GL_TEXTURE_2D;
912 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
914 /* Calculate levels for mip mapping */
915 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
916 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
917 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
918 return WINED3DERR_INVALIDCALL;
920 if(Levels > 1) {
921 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
922 return WINED3DERR_INVALIDCALL;
924 object->baseTexture.levels = 1;
925 } else if (Levels == 0) {
926 TRACE("calculating levels %d\n", object->baseTexture.levels);
927 object->baseTexture.levels++;
928 tmpW = Width;
929 tmpH = Height;
930 while (tmpW > 1 || tmpH > 1) {
931 tmpW = max(1, tmpW >> 1);
932 tmpH = max(1, tmpH >> 1);
933 object->baseTexture.levels++;
935 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
938 /* Generate all the surfaces */
939 tmpW = Width;
940 tmpH = Height;
941 for (i = 0; i < object->baseTexture.levels; i++)
943 /* use the callback to create the texture surface */
944 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
945 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
946 FIXME("Failed to create surface %p\n", object);
947 /* clean up */
948 object->surfaces[i] = NULL;
949 IWineD3DTexture_Release((IWineD3DTexture *)object);
951 *ppTexture = NULL;
952 return hr;
955 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
956 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
957 /* calculate the next mipmap level */
958 tmpW = max(1, tmpW >> 1);
959 tmpH = max(1, tmpH >> 1);
961 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
963 TRACE("(%p) : Created texture %p\n", This, object);
964 return WINED3D_OK;
967 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
968 UINT Width, UINT Height, UINT Depth,
969 UINT Levels, DWORD Usage,
970 WINED3DFORMAT Format, WINED3DPOOL Pool,
971 IWineD3DVolumeTexture **ppVolumeTexture,
972 HANDLE *pSharedHandle, IUnknown *parent,
973 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IWineD3DVolumeTextureImpl *object;
977 unsigned int i;
978 UINT tmpW;
979 UINT tmpH;
980 UINT tmpD;
981 const GlPixelFormatDesc *glDesc;
983 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
985 /* TODO: It should only be possible to create textures for formats
986 that are reported as supported */
987 if (WINED3DFMT_UNKNOWN >= Format) {
988 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
989 return WINED3DERR_INVALIDCALL;
991 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
992 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
993 return WINED3DERR_INVALIDCALL;
996 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
997 D3DINITIALIZEBASETEXTURE(object->baseTexture);
999 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1000 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1002 object->width = Width;
1003 object->height = Height;
1004 object->depth = Depth;
1006 /* Is NP2 support for volumes needed? */
1007 object->baseTexture.pow2Matrix[ 0] = 1.0;
1008 object->baseTexture.pow2Matrix[ 5] = 1.0;
1009 object->baseTexture.pow2Matrix[10] = 1.0;
1010 object->baseTexture.pow2Matrix[15] = 1.0;
1012 /* Calculate levels for mip mapping */
1013 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1014 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1015 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1016 return WINED3DERR_INVALIDCALL;
1018 if(Levels > 1) {
1019 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1020 return WINED3DERR_INVALIDCALL;
1022 Levels = 1;
1023 } else if (Levels == 0) {
1024 object->baseTexture.levels++;
1025 tmpW = Width;
1026 tmpH = Height;
1027 tmpD = Depth;
1028 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1029 tmpW = max(1, tmpW >> 1);
1030 tmpH = max(1, tmpH >> 1);
1031 tmpD = max(1, tmpD >> 1);
1032 object->baseTexture.levels++;
1034 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1037 /* Generate all the surfaces */
1038 tmpW = Width;
1039 tmpH = Height;
1040 tmpD = Depth;
1042 for (i = 0; i < object->baseTexture.levels; i++)
1044 HRESULT hr;
1045 /* Create the volume */
1046 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1047 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1049 if(FAILED(hr)) {
1050 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1051 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1052 *ppVolumeTexture = NULL;
1053 return hr;
1056 /* Set its container to this object */
1057 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1059 /* calcualte the next mipmap level */
1060 tmpW = max(1, tmpW >> 1);
1061 tmpH = max(1, tmpH >> 1);
1062 tmpD = max(1, tmpD >> 1);
1064 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1066 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1067 TRACE("(%p) : Created volume texture %p\n", This, object);
1068 return WINED3D_OK;
1071 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1072 UINT Width, UINT Height, UINT Depth,
1073 DWORD Usage,
1074 WINED3DFORMAT Format, WINED3DPOOL Pool,
1075 IWineD3DVolume** ppVolume,
1076 HANDLE* pSharedHandle, IUnknown *parent) {
1078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1079 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1080 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1082 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1083 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1084 return WINED3DERR_INVALIDCALL;
1087 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1089 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1090 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1092 object->currentDesc.Width = Width;
1093 object->currentDesc.Height = Height;
1094 object->currentDesc.Depth = Depth;
1095 object->bytesPerPixel = formatDesc->bpp;
1097 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1098 object->lockable = TRUE;
1099 object->locked = FALSE;
1100 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1101 object->dirty = TRUE;
1103 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1106 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1107 UINT Levels, DWORD Usage,
1108 WINED3DFORMAT Format, WINED3DPOOL Pool,
1109 IWineD3DCubeTexture **ppCubeTexture,
1110 HANDLE *pSharedHandle, IUnknown *parent,
1111 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1114 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1115 unsigned int i, j;
1116 UINT tmpW;
1117 HRESULT hr;
1118 unsigned int pow2EdgeLength = EdgeLength;
1119 const GlPixelFormatDesc *glDesc;
1120 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1122 /* TODO: It should only be possible to create textures for formats
1123 that are reported as supported */
1124 if (WINED3DFMT_UNKNOWN >= Format) {
1125 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1126 return WINED3DERR_INVALIDCALL;
1129 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1130 WARN("(%p) : Tried to create not supported cube texture\n", This);
1131 return WINED3DERR_INVALIDCALL;
1134 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1135 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1137 TRACE("(%p) Create Cube Texture\n", This);
1139 /** Non-power2 support **/
1141 /* Find the nearest pow2 match */
1142 pow2EdgeLength = 1;
1143 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1145 object->edgeLength = EdgeLength;
1146 /* TODO: support for native non-power 2 */
1147 /* Precalculated scaling for 'faked' non power of two texture coords */
1148 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1149 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1150 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1151 object->baseTexture.pow2Matrix[15] = 1.0;
1153 /* Calculate levels for mip mapping */
1154 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1155 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1156 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1157 HeapFree(GetProcessHeap(), 0, object);
1158 *ppCubeTexture = NULL;
1160 return WINED3DERR_INVALIDCALL;
1162 if(Levels > 1) {
1163 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1164 HeapFree(GetProcessHeap(), 0, object);
1165 *ppCubeTexture = NULL;
1167 return WINED3DERR_INVALIDCALL;
1169 Levels = 1;
1170 } else if (Levels == 0) {
1171 object->baseTexture.levels++;
1172 tmpW = EdgeLength;
1173 while (tmpW > 1) {
1174 tmpW = max(1, tmpW >> 1);
1175 object->baseTexture.levels++;
1177 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1180 /* Generate all the surfaces */
1181 tmpW = EdgeLength;
1182 for (i = 0; i < object->baseTexture.levels; i++) {
1184 /* Create the 6 faces */
1185 for (j = 0; j < 6; j++) {
1187 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1188 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1190 if(hr!= WINED3D_OK) {
1191 /* clean up */
1192 int k;
1193 int l;
1194 for (l = 0; l < j; l++) {
1195 IWineD3DSurface_Release(object->surfaces[l][i]);
1197 for (k = 0; k < i; k++) {
1198 for (l = 0; l < 6; l++) {
1199 IWineD3DSurface_Release(object->surfaces[l][k]);
1203 FIXME("(%p) Failed to create surface\n",object);
1204 HeapFree(GetProcessHeap(),0,object);
1205 *ppCubeTexture = NULL;
1206 return hr;
1208 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1209 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1211 tmpW = max(1, tmpW >> 1);
1213 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1215 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1216 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1217 return WINED3D_OK;
1220 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1222 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1223 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1225 /* Just a check to see if we support this type of query */
1226 switch(Type) {
1227 case WINED3DQUERYTYPE_OCCLUSION:
1228 TRACE("(%p) occlusion query\n", This);
1229 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1230 hr = WINED3D_OK;
1231 else
1232 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1233 break;
1235 case WINED3DQUERYTYPE_EVENT:
1236 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1237 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1238 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1240 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1242 hr = WINED3D_OK;
1243 break;
1245 case WINED3DQUERYTYPE_VCACHE:
1246 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1247 case WINED3DQUERYTYPE_VERTEXSTATS:
1248 case WINED3DQUERYTYPE_TIMESTAMP:
1249 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1250 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1251 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1252 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1253 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1254 case WINED3DQUERYTYPE_PIXELTIMINGS:
1255 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1256 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1257 default:
1258 FIXME("(%p) Unhandled query type %d\n", This, Type);
1260 if(NULL == ppQuery || hr != WINED3D_OK) {
1261 return hr;
1264 D3DCREATEOBJECTINSTANCE(object, Query)
1265 object->type = Type;
1266 object->state = QUERY_CREATED;
1267 /* allocated the 'extended' data based on the type of query requested */
1268 switch(Type){
1269 case WINED3DQUERYTYPE_OCCLUSION:
1270 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1271 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1273 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1274 TRACE("(%p) Allocating data for an occlusion query\n", This);
1275 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1276 break;
1278 case WINED3DQUERYTYPE_EVENT:
1279 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1280 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1282 if(GL_SUPPORT(APPLE_FENCE)) {
1283 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1284 checkGLcall("glGenFencesAPPLE");
1285 } else if(GL_SUPPORT(NV_FENCE)) {
1286 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1287 checkGLcall("glGenFencesNV");
1289 break;
1291 case WINED3DQUERYTYPE_VCACHE:
1292 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1293 case WINED3DQUERYTYPE_VERTEXSTATS:
1294 case WINED3DQUERYTYPE_TIMESTAMP:
1295 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1296 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1297 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1298 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1299 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1300 case WINED3DQUERYTYPE_PIXELTIMINGS:
1301 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1302 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1303 default:
1304 object->extendedData = 0;
1305 FIXME("(%p) Unhandled query type %d\n",This , Type);
1307 TRACE("(%p) : Created Query %p\n", This, object);
1308 return WINED3D_OK;
1311 /*****************************************************************************
1312 * IWineD3DDeviceImpl_SetupFullscreenWindow
1314 * Helper function that modifies a HWND's Style and ExStyle for proper
1315 * fullscreen use.
1317 * Params:
1318 * iface: Pointer to the IWineD3DDevice interface
1319 * window: Window to setup
1321 *****************************************************************************/
1322 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1325 LONG style, exStyle;
1326 /* Don't do anything if an original style is stored.
1327 * That shouldn't happen
1329 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1330 if (This->style || This->exStyle) {
1331 ERR("(%p): Want to change the window parameters of HWND %p, but "
1332 "another style is stored for restoration afterwards\n", This, window);
1335 /* Get the parameters and save them */
1336 style = GetWindowLongW(window, GWL_STYLE);
1337 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1338 This->style = style;
1339 This->exStyle = exStyle;
1341 /* Filter out window decorations */
1342 style &= ~WS_CAPTION;
1343 style &= ~WS_THICKFRAME;
1344 exStyle &= ~WS_EX_WINDOWEDGE;
1345 exStyle &= ~WS_EX_CLIENTEDGE;
1347 /* Make sure the window is managed, otherwise we won't get keyboard input */
1348 style |= WS_POPUP | WS_SYSMENU;
1350 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1351 This->style, This->exStyle, style, exStyle);
1353 SetWindowLongW(window, GWL_STYLE, style);
1354 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1356 /* Inform the window about the update. */
1357 SetWindowPos(window, HWND_TOP, 0, 0,
1358 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1359 ShowWindow(window, SW_NORMAL);
1362 /*****************************************************************************
1363 * IWineD3DDeviceImpl_RestoreWindow
1365 * Helper function that restores a windows' properties when taking it out
1366 * of fullscreen mode
1368 * Params:
1369 * iface: Pointer to the IWineD3DDevice interface
1370 * window: Window to setup
1372 *****************************************************************************/
1373 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1376 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1377 * switch, do nothing
1379 if (!This->style && !This->exStyle) return;
1381 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1382 This, window, This->style, This->exStyle);
1384 SetWindowLongW(window, GWL_STYLE, This->style);
1385 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1387 /* Delete the old values */
1388 This->style = 0;
1389 This->exStyle = 0;
1391 /* Inform the window about the update */
1392 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1393 0, 0, 0, 0, /* Pos, Size, ignored */
1394 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1397 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1398 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1399 IUnknown* parent,
1400 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1401 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1404 HDC hDc;
1405 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1406 HRESULT hr = WINED3D_OK;
1407 IUnknown *bufferParent;
1408 BOOL displaymode_set = FALSE;
1409 WINED3DDISPLAYMODE Mode;
1410 const StaticPixelFormatDesc *formatDesc;
1412 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1414 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1415 * does a device hold a reference to a swap chain giving them a lifetime of the device
1416 * or does the swap chain notify the device of its destruction.
1417 *******************************/
1419 /* Check the params */
1420 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1421 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1422 return WINED3DERR_INVALIDCALL;
1423 } else if (pPresentationParameters->BackBufferCount > 1) {
1424 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");
1427 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1429 /*********************
1430 * Lookup the window Handle and the relating X window handle
1431 ********************/
1433 /* Setup hwnd we are using, plus which display this equates to */
1434 object->win_handle = pPresentationParameters->hDeviceWindow;
1435 if (!object->win_handle) {
1436 object->win_handle = This->createParms.hFocusWindow;
1438 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1440 hDc = GetDC(object->win_handle);
1441 TRACE("Using hDc %p\n", hDc);
1443 if (NULL == hDc) {
1444 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1445 return WINED3DERR_NOTAVAILABLE;
1448 /* Get info on the current display setup */
1449 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1450 object->orig_width = Mode.Width;
1451 object->orig_height = Mode.Height;
1452 object->orig_fmt = Mode.Format;
1453 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1455 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1456 * then the corresponding dimension of the client area of the hDeviceWindow
1457 * (or the focus window, if hDeviceWindow is NULL) is taken.
1458 **********************/
1460 if (pPresentationParameters->Windowed &&
1461 ((pPresentationParameters->BackBufferWidth == 0) ||
1462 (pPresentationParameters->BackBufferHeight == 0) ||
1463 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1465 RECT Rect;
1466 GetClientRect(object->win_handle, &Rect);
1468 if (pPresentationParameters->BackBufferWidth == 0) {
1469 pPresentationParameters->BackBufferWidth = Rect.right;
1470 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1472 if (pPresentationParameters->BackBufferHeight == 0) {
1473 pPresentationParameters->BackBufferHeight = Rect.bottom;
1474 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1476 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1477 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1478 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1482 /* Put the correct figures in the presentation parameters */
1483 TRACE("Copying across presentation parameters\n");
1484 object->presentParms = *pPresentationParameters;
1486 TRACE("calling rendertarget CB\n");
1487 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1488 parent,
1489 object->presentParms.BackBufferWidth,
1490 object->presentParms.BackBufferHeight,
1491 object->presentParms.BackBufferFormat,
1492 object->presentParms.MultiSampleType,
1493 object->presentParms.MultiSampleQuality,
1494 TRUE /* Lockable */,
1495 &object->frontBuffer,
1496 NULL /* pShared (always null)*/);
1497 if (object->frontBuffer != NULL) {
1498 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1499 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1500 } else {
1501 ERR("Failed to create the front buffer\n");
1502 goto error;
1505 /*********************
1506 * Windowed / Fullscreen
1507 *******************/
1510 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1511 * so we should really check to see if there is a fullscreen swapchain already
1512 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1513 **************************************/
1515 if (!pPresentationParameters->Windowed) {
1516 WINED3DDISPLAYMODE mode;
1519 /* Change the display settings */
1520 mode.Width = pPresentationParameters->BackBufferWidth;
1521 mode.Height = pPresentationParameters->BackBufferHeight;
1522 mode.Format = pPresentationParameters->BackBufferFormat;
1523 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1525 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1526 displaymode_set = TRUE;
1527 IWineD3DDevice_SetFullscreen(iface, TRUE);
1531 * Create an opengl context for the display visual
1532 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1533 * use different properties after that point in time. FIXME: How to handle when requested format
1534 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1535 * it chooses is identical to the one already being used!
1536 **********************************/
1537 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1539 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1540 if(!object->context)
1541 return E_OUTOFMEMORY;
1542 object->num_contexts = 1;
1544 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1545 if (!object->context[0]) {
1546 ERR("Failed to create a new context\n");
1547 hr = WINED3DERR_NOTAVAILABLE;
1548 goto error;
1549 } else {
1550 TRACE("Context created (HWND=%p, glContext=%p)\n",
1551 object->win_handle, object->context[0]->glCtx);
1554 /*********************
1555 * Create the back, front and stencil buffers
1556 *******************/
1557 if(object->presentParms.BackBufferCount > 0) {
1558 int i;
1560 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1561 if(!object->backBuffer) {
1562 ERR("Out of memory\n");
1563 hr = E_OUTOFMEMORY;
1564 goto error;
1567 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1568 TRACE("calling rendertarget CB\n");
1569 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1570 parent,
1571 object->presentParms.BackBufferWidth,
1572 object->presentParms.BackBufferHeight,
1573 object->presentParms.BackBufferFormat,
1574 object->presentParms.MultiSampleType,
1575 object->presentParms.MultiSampleQuality,
1576 TRUE /* Lockable */,
1577 &object->backBuffer[i],
1578 NULL /* pShared (always null)*/);
1579 if(hr == WINED3D_OK && object->backBuffer[i]) {
1580 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1581 } else {
1582 ERR("Cannot create new back buffer\n");
1583 goto error;
1585 ENTER_GL();
1586 glDrawBuffer(GL_BACK);
1587 checkGLcall("glDrawBuffer(GL_BACK)");
1588 LEAVE_GL();
1590 } else {
1591 object->backBuffer = NULL;
1593 /* Single buffering - draw to front buffer */
1594 ENTER_GL();
1595 glDrawBuffer(GL_FRONT);
1596 checkGLcall("glDrawBuffer(GL_FRONT)");
1597 LEAVE_GL();
1600 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1601 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1602 TRACE("Creating depth stencil buffer\n");
1603 if (This->auto_depth_stencil_buffer == NULL ) {
1604 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1605 parent,
1606 object->presentParms.BackBufferWidth,
1607 object->presentParms.BackBufferHeight,
1608 object->presentParms.AutoDepthStencilFormat,
1609 object->presentParms.MultiSampleType,
1610 object->presentParms.MultiSampleQuality,
1611 FALSE /* FIXME: Discard */,
1612 &This->auto_depth_stencil_buffer,
1613 NULL /* pShared (always null)*/ );
1614 if (This->auto_depth_stencil_buffer != NULL)
1615 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1618 /** TODO: A check on width, height and multisample types
1619 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1620 ****************************/
1621 object->wantsDepthStencilBuffer = TRUE;
1622 } else {
1623 object->wantsDepthStencilBuffer = FALSE;
1626 TRACE("Created swapchain %p\n", object);
1627 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1628 return WINED3D_OK;
1630 error:
1631 if (displaymode_set) {
1632 DEVMODEW devmode;
1633 RECT clip_rc;
1635 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1636 ClipCursor(NULL);
1638 /* Change the display settings */
1639 memset(&devmode, 0, sizeof(devmode));
1640 devmode.dmSize = sizeof(devmode);
1641 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1642 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1643 devmode.dmPelsWidth = object->orig_width;
1644 devmode.dmPelsHeight = object->orig_height;
1645 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1648 if (object->backBuffer) {
1649 int i;
1650 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1651 if(object->backBuffer[i]) {
1652 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1653 IUnknown_Release(bufferParent); /* once for the get parent */
1654 if (IUnknown_Release(bufferParent) > 0) {
1655 FIXME("(%p) Something's still holding the back buffer\n",This);
1659 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1660 object->backBuffer = NULL;
1662 if(object->context[0])
1663 DestroyContext(This, object->context[0]);
1664 if(object->frontBuffer) {
1665 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1666 IUnknown_Release(bufferParent); /* once for the get parent */
1667 if (IUnknown_Release(bufferParent) > 0) {
1668 FIXME("(%p) Something's still holding the front buffer\n",This);
1671 HeapFree(GetProcessHeap(), 0, object);
1672 return hr;
1675 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1676 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1678 TRACE("(%p)\n", This);
1680 return This->NumberOfSwapChains;
1683 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1685 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1687 if(iSwapChain < This->NumberOfSwapChains) {
1688 *pSwapChain = This->swapchains[iSwapChain];
1689 IWineD3DSwapChain_AddRef(*pSwapChain);
1690 TRACE("(%p) returning %p\n", This, *pSwapChain);
1691 return WINED3D_OK;
1692 } else {
1693 TRACE("Swapchain out of range\n");
1694 *pSwapChain = NULL;
1695 return WINED3DERR_INVALIDCALL;
1699 /*****
1700 * Vertex Declaration
1701 *****/
1702 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1703 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1705 IWineD3DVertexDeclarationImpl *object = NULL;
1706 HRESULT hr = WINED3D_OK;
1708 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1709 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1711 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1713 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1714 if(FAILED(hr)) {
1715 *ppVertexDeclaration = NULL;
1716 HeapFree(GetProcessHeap(), 0, object);
1719 return hr;
1722 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1723 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1725 unsigned int idx, idx2;
1726 unsigned int offset;
1727 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1728 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1729 BOOL has_blend_idx = has_blend &&
1730 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1731 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1732 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1733 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1734 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1735 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1736 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1738 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1739 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1741 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1742 WINED3DVERTEXELEMENT *elements = NULL;
1744 unsigned int size;
1745 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1746 if (has_blend_idx) num_blends--;
1748 /* Compute declaration size */
1749 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1750 has_psize + has_diffuse + has_specular + num_textures + 1;
1752 /* convert the declaration */
1753 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1754 if (!elements)
1755 return 0;
1757 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1758 idx = 0;
1759 if (has_pos) {
1760 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1761 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1762 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1764 else {
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1766 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1768 elements[idx].UsageIndex = 0;
1769 idx++;
1771 if (has_blend && (num_blends > 0)) {
1772 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1773 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1774 else
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1776 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1777 elements[idx].UsageIndex = 0;
1778 idx++;
1780 if (has_blend_idx) {
1781 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1782 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1783 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1784 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1785 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1786 else
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1789 elements[idx].UsageIndex = 0;
1790 idx++;
1792 if (has_normal) {
1793 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1794 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1795 elements[idx].UsageIndex = 0;
1796 idx++;
1798 if (has_psize) {
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1800 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1801 elements[idx].UsageIndex = 0;
1802 idx++;
1804 if (has_diffuse) {
1805 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1806 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1807 elements[idx].UsageIndex = 0;
1808 idx++;
1810 if (has_specular) {
1811 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1812 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1813 elements[idx].UsageIndex = 1;
1814 idx++;
1816 for (idx2 = 0; idx2 < num_textures; idx2++) {
1817 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1818 switch (numcoords) {
1819 case WINED3DFVF_TEXTUREFORMAT1:
1820 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1821 break;
1822 case WINED3DFVF_TEXTUREFORMAT2:
1823 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1824 break;
1825 case WINED3DFVF_TEXTUREFORMAT3:
1826 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1827 break;
1828 case WINED3DFVF_TEXTUREFORMAT4:
1829 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1830 break;
1832 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1833 elements[idx].UsageIndex = idx2;
1834 idx++;
1837 /* Now compute offsets, and initialize the rest of the fields */
1838 for (idx = 0, offset = 0; idx < size-1; idx++) {
1839 elements[idx].Stream = 0;
1840 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1841 elements[idx].Offset = offset;
1842 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1845 *ppVertexElements = elements;
1846 return size;
1849 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1850 WINED3DVERTEXELEMENT* elements = NULL;
1851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1852 unsigned int size;
1853 DWORD hr;
1855 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1856 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1858 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1859 HeapFree(GetProcessHeap(), 0, elements);
1860 if (hr != S_OK) return hr;
1862 return WINED3D_OK;
1865 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1866 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1868 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1869 HRESULT hr = WINED3D_OK;
1870 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1871 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1873 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1875 if (vertex_declaration) {
1876 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1879 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1881 if (WINED3D_OK != hr) {
1882 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1883 IWineD3DVertexShader_Release(*ppVertexShader);
1884 return WINED3DERR_INVALIDCALL;
1886 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1888 return WINED3D_OK;
1891 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1892 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1893 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1894 HRESULT hr = WINED3D_OK;
1896 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1897 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1898 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1899 if (WINED3D_OK == hr) {
1900 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1901 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1902 } else {
1903 WARN("(%p) : Failed to create pixel shader\n", This);
1906 return hr;
1909 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1911 IWineD3DPaletteImpl *object;
1912 HRESULT hr;
1913 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1915 /* Create the new object */
1916 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1917 if(!object) {
1918 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1919 return E_OUTOFMEMORY;
1922 object->lpVtbl = &IWineD3DPalette_Vtbl;
1923 object->ref = 1;
1924 object->Flags = Flags;
1925 object->parent = Parent;
1926 object->wineD3DDevice = This;
1927 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1929 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1931 if(!object->hpal) {
1932 HeapFree( GetProcessHeap(), 0, object);
1933 return E_OUTOFMEMORY;
1936 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1937 if(FAILED(hr)) {
1938 IWineD3DPalette_Release((IWineD3DPalette *) object);
1939 return hr;
1942 *Palette = (IWineD3DPalette *) object;
1944 return WINED3D_OK;
1947 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1948 HBITMAP hbm;
1949 BITMAP bm;
1950 HRESULT hr;
1951 HDC dcb = NULL, dcs = NULL;
1952 WINEDDCOLORKEY colorkey;
1954 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1955 if(hbm)
1957 GetObjectA(hbm, sizeof(BITMAP), &bm);
1958 dcb = CreateCompatibleDC(NULL);
1959 if(!dcb) goto out;
1960 SelectObject(dcb, hbm);
1962 else
1964 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1965 * couldn't be loaded
1967 memset(&bm, 0, sizeof(bm));
1968 bm.bmWidth = 32;
1969 bm.bmHeight = 32;
1972 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1973 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1974 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1975 if(FAILED(hr)) {
1976 ERR("Wine logo requested, but failed to create surface\n");
1977 goto out;
1980 if(dcb) {
1981 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1982 if(FAILED(hr)) goto out;
1983 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1984 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1986 colorkey.dwColorSpaceLowValue = 0;
1987 colorkey.dwColorSpaceHighValue = 0;
1988 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1989 } else {
1990 /* Fill the surface with a white color to show that wined3d is there */
1991 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1994 out:
1995 if(dcb) {
1996 DeleteDC(dcb);
1998 if(hbm) {
1999 DeleteObject(hbm);
2001 return;
2004 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 IWineD3DSwapChainImpl *swapchain;
2007 HRESULT hr;
2008 DWORD state;
2010 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2011 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2013 /* TODO: Test if OpenGL is compiled in and loaded */
2015 TRACE("(%p) : Creating stateblock\n", This);
2016 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2017 hr = IWineD3DDevice_CreateStateBlock(iface,
2018 WINED3DSBT_INIT,
2019 (IWineD3DStateBlock **)&This->stateBlock,
2020 NULL);
2021 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2022 WARN("Failed to create stateblock\n");
2023 goto err_out;
2025 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2026 This->updateStateBlock = This->stateBlock;
2027 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2029 hr = allocate_shader_constants(This->updateStateBlock);
2030 if (WINED3D_OK != hr) {
2031 goto err_out;
2034 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2035 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2036 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2038 /* Initialize the texture unit mapping to a 1:1 mapping */
2039 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2040 if (state < GL_LIMITS(fragment_samplers)) {
2041 This->texUnitMap[state] = state;
2042 This->rev_tex_unit_map[state] = state;
2043 } else {
2044 This->texUnitMap[state] = -1;
2045 This->rev_tex_unit_map[state] = -1;
2049 /* Setup the implicit swapchain */
2050 TRACE("Creating implicit swapchain\n");
2051 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2052 if (FAILED(hr) || !swapchain) {
2053 WARN("Failed to create implicit swapchain\n");
2054 goto err_out;
2057 This->NumberOfSwapChains = 1;
2058 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2059 if(!This->swapchains) {
2060 ERR("Out of memory!\n");
2061 goto err_out;
2063 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2065 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2066 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2067 This->render_targets[0] = swapchain->backBuffer[0];
2068 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2070 else {
2071 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2072 This->render_targets[0] = swapchain->frontBuffer;
2073 This->lastActiveRenderTarget = swapchain->frontBuffer;
2075 IWineD3DSurface_AddRef(This->render_targets[0]);
2076 This->activeContext = swapchain->context[0];
2077 This->lastThread = GetCurrentThreadId();
2079 /* Depth Stencil support */
2080 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2081 if (NULL != This->stencilBufferTarget) {
2082 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2085 /* Set up some starting GL setup */
2086 ENTER_GL();
2088 /* Setup all the devices defaults */
2089 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2090 #if 0
2091 IWineD3DImpl_CheckGraphicsMemory();
2092 #endif
2094 { /* Set a default viewport */
2095 WINED3DVIEWPORT vp;
2096 vp.X = 0;
2097 vp.Y = 0;
2098 vp.Width = pPresentationParameters->BackBufferWidth;
2099 vp.Height = pPresentationParameters->BackBufferHeight;
2100 vp.MinZ = 0.0f;
2101 vp.MaxZ = 1.0f;
2102 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2105 /* Initialize the current view state */
2106 This->view_ident = 1;
2107 This->contexts[0]->last_was_rhw = 0;
2108 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2109 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2111 switch(wined3d_settings.offscreen_rendering_mode) {
2112 case ORM_FBO:
2113 case ORM_PBUFFER:
2114 This->offscreenBuffer = GL_BACK;
2115 break;
2117 case ORM_BACKBUFFER:
2119 if(GL_LIMITS(aux_buffers) > 0) {
2120 TRACE("Using auxilliary buffer for offscreen rendering\n");
2121 This->offscreenBuffer = GL_AUX0;
2122 } else {
2123 TRACE("Using back buffer for offscreen rendering\n");
2124 This->offscreenBuffer = GL_BACK;
2129 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2130 LEAVE_GL();
2132 /* Clear the screen */
2133 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2134 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2135 0x00, 1.0, 0);
2137 This->d3d_initialized = TRUE;
2139 if(wined3d_settings.logo) {
2140 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2142 return WINED3D_OK;
2144 err_out:
2145 HeapFree(GetProcessHeap(), 0, This->render_targets);
2146 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2147 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2148 HeapFree(GetProcessHeap(), 0, This->swapchains);
2149 This->NumberOfSwapChains = 0;
2150 if(swapchain) {
2151 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2153 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2154 if(This->stateBlock) {
2155 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2156 This->stateBlock = NULL;
2158 return hr;
2161 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2163 int sampler;
2164 UINT i;
2165 TRACE("(%p)\n", This);
2167 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2169 /* I don't think that the interface guarants that the device is destroyed from the same thread
2170 * it was created. Thus make sure a context is active for the glDelete* calls
2172 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2174 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2176 TRACE("Deleting high order patches\n");
2177 for(i = 0; i < PATCHMAP_SIZE; i++) {
2178 struct list *e1, *e2;
2179 struct WineD3DRectPatch *patch;
2180 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2181 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2182 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2186 /* Delete the palette conversion shader if it is around */
2187 if(This->paletteConversionShader) {
2188 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2189 This->paletteConversionShader = 0;
2192 /* Delete the pbuffer context if there is any */
2193 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2195 /* Delete the mouse cursor texture */
2196 if(This->cursorTexture) {
2197 ENTER_GL();
2198 glDeleteTextures(1, &This->cursorTexture);
2199 LEAVE_GL();
2200 This->cursorTexture = 0;
2203 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2204 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2206 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2207 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2210 /* Release the update stateblock */
2211 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2212 if(This->updateStateBlock != This->stateBlock)
2213 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2215 This->updateStateBlock = NULL;
2217 { /* because were not doing proper internal refcounts releasing the primary state block
2218 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2219 to set this->stateBlock = NULL; first */
2220 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2221 This->stateBlock = NULL;
2223 /* Release the stateblock */
2224 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2225 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2229 /* Release the buffers (with sanity checks)*/
2230 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2231 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2232 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2233 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2235 This->stencilBufferTarget = NULL;
2237 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2238 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2239 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2241 TRACE("Setting rendertarget to NULL\n");
2242 This->render_targets[0] = NULL;
2244 if (This->auto_depth_stencil_buffer) {
2245 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2246 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2248 This->auto_depth_stencil_buffer = NULL;
2251 for(i=0; i < This->NumberOfSwapChains; i++) {
2252 TRACE("Releasing the implicit swapchain %d\n", i);
2253 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2254 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2258 HeapFree(GetProcessHeap(), 0, This->swapchains);
2259 This->swapchains = NULL;
2260 This->NumberOfSwapChains = 0;
2262 HeapFree(GetProcessHeap(), 0, This->render_targets);
2263 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2264 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2265 This->render_targets = NULL;
2266 This->fbo_color_attachments = NULL;
2267 This->draw_buffers = NULL;
2270 This->d3d_initialized = FALSE;
2271 return WINED3D_OK;
2274 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2276 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2278 /* Setup the window for fullscreen mode */
2279 if(fullscreen && !This->ddraw_fullscreen) {
2280 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2281 } else if(!fullscreen && This->ddraw_fullscreen) {
2282 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2285 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2286 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2287 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2288 * separately.
2290 This->ddraw_fullscreen = fullscreen;
2293 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2294 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2295 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2297 * There is no way to deactivate thread safety once it is enabled.
2299 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2302 /*For now just store the flag(needed in case of ddraw) */
2303 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2305 return;
2308 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2309 DEVMODEW devmode;
2310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2311 LONG ret;
2312 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2313 RECT clip_rc;
2315 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2317 /* Resize the screen even without a window:
2318 * The app could have unset it with SetCooperativeLevel, but not called
2319 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2320 * but we don't have any hwnd
2323 memset(&devmode, 0, sizeof(devmode));
2324 devmode.dmSize = sizeof(devmode);
2325 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2326 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2327 devmode.dmPelsWidth = pMode->Width;
2328 devmode.dmPelsHeight = pMode->Height;
2330 devmode.dmDisplayFrequency = pMode->RefreshRate;
2331 if (pMode->RefreshRate != 0) {
2332 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2335 /* Only change the mode if necessary */
2336 if( (This->ddraw_width == pMode->Width) &&
2337 (This->ddraw_height == pMode->Height) &&
2338 (This->ddraw_format == pMode->Format) &&
2339 (pMode->RefreshRate == 0) ) {
2340 return WINED3D_OK;
2343 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2344 if (ret != DISP_CHANGE_SUCCESSFUL) {
2345 if(devmode.dmDisplayFrequency != 0) {
2346 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2347 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2348 devmode.dmDisplayFrequency = 0;
2349 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2351 if(ret != DISP_CHANGE_SUCCESSFUL) {
2352 return WINED3DERR_NOTAVAILABLE;
2356 /* Store the new values */
2357 This->ddraw_width = pMode->Width;
2358 This->ddraw_height = pMode->Height;
2359 This->ddraw_format = pMode->Format;
2361 /* Only do this with a window of course */
2362 if(This->ddraw_window)
2363 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2365 /* And finally clip mouse to our screen */
2366 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2367 ClipCursor(&clip_rc);
2369 return WINED3D_OK;
2372 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2374 *ppD3D= This->wineD3D;
2375 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2376 IWineD3D_AddRef(*ppD3D);
2377 return WINED3D_OK;
2380 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2383 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2384 (This->adapter->TextureRam/(1024*1024)),
2385 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2386 /* return simulated texture memory left */
2387 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2392 /*****
2393 * Get / Set FVF
2394 *****/
2395 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2398 /* Update the current state block */
2399 This->updateStateBlock->changed.fvf = TRUE;
2401 if(This->updateStateBlock->fvf == fvf) {
2402 TRACE("Application is setting the old fvf over, nothing to do\n");
2403 return WINED3D_OK;
2406 This->updateStateBlock->fvf = fvf;
2407 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2408 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2409 return WINED3D_OK;
2413 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2415 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2416 *pfvf = This->stateBlock->fvf;
2417 return WINED3D_OK;
2420 /*****
2421 * Get / Set Stream Source
2422 *****/
2423 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2425 IWineD3DVertexBuffer *oldSrc;
2427 if (StreamNumber >= MAX_STREAMS) {
2428 WARN("Stream out of range %d\n", StreamNumber);
2429 return WINED3DERR_INVALIDCALL;
2430 } else if(OffsetInBytes & 0x3) {
2431 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2432 return WINED3DERR_INVALIDCALL;
2435 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2436 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2438 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2440 if(oldSrc == pStreamData &&
2441 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2442 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2443 TRACE("Application is setting the old values over, nothing to do\n");
2444 return WINED3D_OK;
2447 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2448 if (pStreamData) {
2449 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2450 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2453 /* Handle recording of state blocks */
2454 if (This->isRecordingState) {
2455 TRACE("Recording... not performing anything\n");
2456 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2457 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2458 return WINED3D_OK;
2461 /* Need to do a getParent and pass the reffs up */
2462 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2463 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2464 so for now, just count internally */
2465 if (pStreamData != NULL) {
2466 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2467 InterlockedIncrement(&vbImpl->bindCount);
2468 IWineD3DVertexBuffer_AddRef(pStreamData);
2470 if (oldSrc != NULL) {
2471 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2472 IWineD3DVertexBuffer_Release(oldSrc);
2475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2477 return WINED3D_OK;
2480 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2484 This->stateBlock->streamSource[StreamNumber],
2485 This->stateBlock->streamOffset[StreamNumber],
2486 This->stateBlock->streamStride[StreamNumber]);
2488 if (StreamNumber >= MAX_STREAMS) {
2489 WARN("Stream out of range %d\n", StreamNumber);
2490 return WINED3DERR_INVALIDCALL;
2492 *pStream = This->stateBlock->streamSource[StreamNumber];
2493 *pStride = This->stateBlock->streamStride[StreamNumber];
2494 if (pOffset) {
2495 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2498 if (*pStream != NULL) {
2499 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2501 return WINED3D_OK;
2504 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2506 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2507 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2509 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2510 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2512 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2513 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2515 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2516 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2520 return WINED3D_OK;
2523 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2527 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2529 TRACE("(%p) : returning %d\n", This, *Divider);
2531 return WINED3D_OK;
2534 /*****
2535 * Get / Set & Multiply Transform
2536 *****/
2537 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2540 /* Most of this routine, comments included copied from ddraw tree initially: */
2541 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2543 /* Handle recording of state blocks */
2544 if (This->isRecordingState) {
2545 TRACE("Recording... not performing anything\n");
2546 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2547 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2548 return WINED3D_OK;
2552 * If the new matrix is the same as the current one,
2553 * we cut off any further processing. this seems to be a reasonable
2554 * optimization because as was noticed, some apps (warcraft3 for example)
2555 * tend towards setting the same matrix repeatedly for some reason.
2557 * From here on we assume that the new matrix is different, wherever it matters.
2559 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2560 TRACE("The app is setting the same matrix over again\n");
2561 return WINED3D_OK;
2562 } else {
2563 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2567 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2568 where ViewMat = Camera space, WorldMat = world space.
2570 In OpenGL, camera and world space is combined into GL_MODELVIEW
2571 matrix. The Projection matrix stay projection matrix.
2574 /* Capture the times we can just ignore the change for now */
2575 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2576 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2577 /* Handled by the state manager */
2580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2581 return WINED3D_OK;
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2586 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2587 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2588 return WINED3D_OK;
2591 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2592 WINED3DMATRIX *mat = NULL;
2593 WINED3DMATRIX temp;
2595 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2596 * below means it will be recorded in a state block change, but it
2597 * works regardless where it is recorded.
2598 * If this is found to be wrong, change to StateBlock.
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2601 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2603 if (State < HIGHEST_TRANSFORMSTATE)
2605 mat = &This->updateStateBlock->transforms[State];
2606 } else {
2607 FIXME("Unhandled transform state!!\n");
2610 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2612 /* Apply change via set transform - will reapply to eg. lights this way */
2613 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2616 /*****
2617 * Get / Set Light
2618 *****/
2619 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2620 you can reference any indexes you want as long as that number max are enabled at any
2621 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2622 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2623 but when recording, just build a chain pretty much of commands to be replayed. */
2625 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2626 float rho;
2627 PLIGHTINFOEL *object = NULL;
2628 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2629 struct list *e;
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2632 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2634 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2635 * the gl driver.
2637 if(!pLight) {
2638 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2639 return WINED3DERR_INVALIDCALL;
2642 switch(pLight->Type) {
2643 case WINED3DLIGHT_POINT:
2644 case WINED3DLIGHT_SPOT:
2645 case WINED3DLIGHT_PARALLELPOINT:
2646 case WINED3DLIGHT_GLSPOT:
2647 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2648 * most wanted
2650 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2651 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2652 return WINED3DERR_INVALIDCALL;
2654 break;
2656 case WINED3DLIGHT_DIRECTIONAL:
2657 /* Ignores attenuation */
2658 break;
2660 default:
2661 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL;
2665 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2666 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2667 if(object->OriginalIndex == Index) break;
2668 object = NULL;
2671 if(!object) {
2672 TRACE("Adding new light\n");
2673 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2674 if(!object) {
2675 ERR("Out of memory error when allocating a light\n");
2676 return E_OUTOFMEMORY;
2678 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2679 object->glIndex = -1;
2680 object->OriginalIndex = Index;
2681 object->changed = TRUE;
2684 /* Initialize the object */
2685 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,
2686 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2687 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2688 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2689 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2690 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2691 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2693 /* Save away the information */
2694 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2696 switch (pLight->Type) {
2697 case WINED3DLIGHT_POINT:
2698 /* Position */
2699 object->lightPosn[0] = pLight->Position.x;
2700 object->lightPosn[1] = pLight->Position.y;
2701 object->lightPosn[2] = pLight->Position.z;
2702 object->lightPosn[3] = 1.0f;
2703 object->cutoff = 180.0f;
2704 /* FIXME: Range */
2705 break;
2707 case WINED3DLIGHT_DIRECTIONAL:
2708 /* Direction */
2709 object->lightPosn[0] = -pLight->Direction.x;
2710 object->lightPosn[1] = -pLight->Direction.y;
2711 object->lightPosn[2] = -pLight->Direction.z;
2712 object->lightPosn[3] = 0.0;
2713 object->exponent = 0.0f;
2714 object->cutoff = 180.0f;
2715 break;
2717 case WINED3DLIGHT_SPOT:
2718 /* Position */
2719 object->lightPosn[0] = pLight->Position.x;
2720 object->lightPosn[1] = pLight->Position.y;
2721 object->lightPosn[2] = pLight->Position.z;
2722 object->lightPosn[3] = 1.0;
2724 /* Direction */
2725 object->lightDirn[0] = pLight->Direction.x;
2726 object->lightDirn[1] = pLight->Direction.y;
2727 object->lightDirn[2] = pLight->Direction.z;
2728 object->lightDirn[3] = 1.0;
2731 * opengl-ish and d3d-ish spot lights use too different models for the
2732 * light "intensity" as a function of the angle towards the main light direction,
2733 * so we only can approximate very roughly.
2734 * however spot lights are rather rarely used in games (if ever used at all).
2735 * furthermore if still used, probably nobody pays attention to such details.
2737 if (pLight->Falloff == 0) {
2738 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2739 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2740 * will always be 1.0 for both of them, and we don't have to care for the
2741 * rest of the rather complex calculation
2743 object->exponent = 0;
2744 } else {
2745 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2746 if (rho < 0.0001) rho = 0.0001f;
2747 object->exponent = -0.3/log(cos(rho/2));
2749 if (object->exponent > 128.0) {
2750 object->exponent = 128.0;
2752 object->cutoff = pLight->Phi*90/M_PI;
2754 /* FIXME: Range */
2755 break;
2757 default:
2758 FIXME("Unrecognized light type %d\n", pLight->Type);
2761 /* Update the live definitions if the light is currently assigned a glIndex */
2762 if (object->glIndex != -1 && !This->isRecordingState) {
2763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2765 return WINED3D_OK;
2768 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2769 PLIGHTINFOEL *lightInfo = NULL;
2770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2771 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2772 struct list *e;
2773 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2775 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2776 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2777 if(lightInfo->OriginalIndex == Index) break;
2778 lightInfo = NULL;
2781 if (lightInfo == NULL) {
2782 TRACE("Light information requested but light not defined\n");
2783 return WINED3DERR_INVALIDCALL;
2786 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2787 return WINED3D_OK;
2790 /*****
2791 * Get / Set Light Enable
2792 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2793 *****/
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2795 PLIGHTINFOEL *lightInfo = NULL;
2796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2797 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2798 struct list *e;
2799 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2801 /* Tests show true = 128...not clear why */
2802 Enable = Enable? 128: 0;
2804 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2805 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2806 if(lightInfo->OriginalIndex == Index) break;
2807 lightInfo = NULL;
2809 TRACE("Found light: %p\n", lightInfo);
2811 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2812 if (lightInfo == NULL) {
2814 TRACE("Light enabled requested but light not defined, so defining one!\n");
2815 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2817 /* Search for it again! Should be fairly quick as near head of list */
2818 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2819 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2820 if(lightInfo->OriginalIndex == Index) break;
2821 lightInfo = NULL;
2823 if (lightInfo == NULL) {
2824 FIXME("Adding default lights has failed dismally\n");
2825 return WINED3DERR_INVALIDCALL;
2829 lightInfo->enabledChanged = TRUE;
2830 if(!Enable) {
2831 if(lightInfo->glIndex != -1) {
2832 if(!This->isRecordingState) {
2833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2836 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2837 lightInfo->glIndex = -1;
2838 } else {
2839 TRACE("Light already disabled, nothing to do\n");
2841 lightInfo->enabled = FALSE;
2842 } else {
2843 lightInfo->enabled = TRUE;
2844 if (lightInfo->glIndex != -1) {
2845 /* nop */
2846 TRACE("Nothing to do as light was enabled\n");
2847 } else {
2848 int i;
2849 /* Find a free gl light */
2850 for(i = 0; i < This->maxConcurrentLights; i++) {
2851 if(This->stateBlock->activeLights[i] == NULL) {
2852 This->stateBlock->activeLights[i] = lightInfo;
2853 lightInfo->glIndex = i;
2854 break;
2857 if(lightInfo->glIndex == -1) {
2858 /* Our tests show that Windows returns D3D_OK in this situation, even with
2859 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2860 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2861 * as well for those lights.
2863 * TODO: Test how this affects rendering
2865 FIXME("Too many concurrently active lights\n");
2866 return WINED3D_OK;
2869 /* i == lightInfo->glIndex */
2870 if(!This->isRecordingState) {
2871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2876 return WINED3D_OK;
2879 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2881 PLIGHTINFOEL *lightInfo = NULL;
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2883 struct list *e;
2884 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2885 TRACE("(%p) : for idx(%d)\n", This, Index);
2887 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2888 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2889 if(lightInfo->OriginalIndex == Index) break;
2890 lightInfo = NULL;
2893 if (lightInfo == NULL) {
2894 TRACE("Light enabled state requested but light not defined\n");
2895 return WINED3DERR_INVALIDCALL;
2897 /* true is 128 according to SetLightEnable */
2898 *pEnable = lightInfo->enabled ? 128 : 0;
2899 return WINED3D_OK;
2902 /*****
2903 * Get / Set Clip Planes
2904 *****/
2905 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2907 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2909 /* Validate Index */
2910 if (Index >= GL_LIMITS(clipplanes)) {
2911 TRACE("Application has requested clipplane this device doesn't support\n");
2912 return WINED3DERR_INVALIDCALL;
2915 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2917 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2918 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2919 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2920 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2921 TRACE("Application is setting old values over, nothing to do\n");
2922 return WINED3D_OK;
2925 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2926 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2927 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2928 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2930 /* Handle recording of state blocks */
2931 if (This->isRecordingState) {
2932 TRACE("Recording... not performing anything\n");
2933 return WINED3D_OK;
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2938 return WINED3D_OK;
2941 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 TRACE("(%p) : for idx %d\n", This, Index);
2945 /* Validate Index */
2946 if (Index >= GL_LIMITS(clipplanes)) {
2947 TRACE("Application has requested clipplane this device doesn't support\n");
2948 return WINED3DERR_INVALIDCALL;
2951 pPlane[0] = This->stateBlock->clipplane[Index][0];
2952 pPlane[1] = This->stateBlock->clipplane[Index][1];
2953 pPlane[2] = This->stateBlock->clipplane[Index][2];
2954 pPlane[3] = This->stateBlock->clipplane[Index][3];
2955 return WINED3D_OK;
2958 /*****
2959 * Get / Set Clip Plane Status
2960 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2961 *****/
2962 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 FIXME("(%p) : stub\n", This);
2965 if (NULL == pClipStatus) {
2966 return WINED3DERR_INVALIDCALL;
2968 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2969 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2970 return WINED3D_OK;
2973 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2975 FIXME("(%p) : stub\n", This);
2976 if (NULL == pClipStatus) {
2977 return WINED3DERR_INVALIDCALL;
2979 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2980 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2981 return WINED3D_OK;
2984 /*****
2985 * Get / Set Material
2986 *****/
2987 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2990 This->updateStateBlock->changed.material = TRUE;
2991 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2993 /* Handle recording of state blocks */
2994 if (This->isRecordingState) {
2995 TRACE("Recording... not performing anything\n");
2996 return WINED3D_OK;
2999 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3000 return WINED3D_OK;
3003 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3005 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3006 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3007 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3008 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3009 pMaterial->Ambient.b, pMaterial->Ambient.a);
3010 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3011 pMaterial->Specular.b, pMaterial->Specular.a);
3012 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3013 pMaterial->Emissive.b, pMaterial->Emissive.a);
3014 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3016 return WINED3D_OK;
3019 /*****
3020 * Get / Set Indices
3021 *****/
3022 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3024 IWineD3DIndexBuffer *oldIdxs;
3026 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3027 oldIdxs = This->updateStateBlock->pIndexData;
3029 This->updateStateBlock->changed.indices = TRUE;
3030 This->updateStateBlock->pIndexData = pIndexData;
3032 /* Handle recording of state blocks */
3033 if (This->isRecordingState) {
3034 TRACE("Recording... not performing anything\n");
3035 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3036 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3037 return WINED3D_OK;
3040 if(oldIdxs != pIndexData) {
3041 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3042 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3043 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3045 return WINED3D_OK;
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 *ppIndexData = This->stateBlock->pIndexData;
3053 /* up ref count on ppindexdata */
3054 if (*ppIndexData) {
3055 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3056 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3057 }else{
3058 TRACE("(%p) No index data set\n", This);
3060 TRACE("Returning %p\n", *ppIndexData);
3062 return WINED3D_OK;
3065 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3066 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3068 TRACE("(%p)->(%d)\n", This, BaseIndex);
3070 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3071 TRACE("Application is setting the old value over, nothing to do\n");
3072 return WINED3D_OK;
3075 This->updateStateBlock->baseVertexIndex = BaseIndex;
3077 if (This->isRecordingState) {
3078 TRACE("Recording... not performing anything\n");
3079 return WINED3D_OK;
3081 /* The base vertex index affects the stream sources */
3082 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3083 return WINED3D_OK;
3086 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3088 TRACE("(%p) : base_index %p\n", This, base_index);
3090 *base_index = This->stateBlock->baseVertexIndex;
3092 TRACE("Returning %u\n", *base_index);
3094 return WINED3D_OK;
3097 /*****
3098 * Get / Set Viewports
3099 *****/
3100 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p)\n", This);
3104 This->updateStateBlock->changed.viewport = TRUE;
3105 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3107 /* Handle recording of state blocks */
3108 if (This->isRecordingState) {
3109 TRACE("Recording... not performing anything\n");
3110 return WINED3D_OK;
3113 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3114 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3117 return WINED3D_OK;
3121 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 TRACE("(%p)\n", This);
3124 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3125 return WINED3D_OK;
3128 /*****
3129 * Get / Set Render States
3130 * TODO: Verify against dx9 definitions
3131 *****/
3132 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 DWORD oldValue = This->stateBlock->renderState[State];
3137 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3139 This->updateStateBlock->changed.renderState[State] = TRUE;
3140 This->updateStateBlock->renderState[State] = Value;
3142 /* Handle recording of state blocks */
3143 if (This->isRecordingState) {
3144 TRACE("Recording... not performing anything\n");
3145 return WINED3D_OK;
3148 /* Compared here and not before the assignment to allow proper stateblock recording */
3149 if(Value == oldValue) {
3150 TRACE("Application is setting the old value over, nothing to do\n");
3151 } else {
3152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3155 return WINED3D_OK;
3158 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3161 *pValue = This->stateBlock->renderState[State];
3162 return WINED3D_OK;
3165 /*****
3166 * Get / Set Sampler States
3167 * TODO: Verify against dx9 definitions
3168 *****/
3170 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3172 DWORD oldValue;
3174 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3175 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3177 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3178 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3182 * SetSampler is designed to allow for more than the standard up to 8 textures
3183 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3184 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3186 * http://developer.nvidia.com/object/General_FAQ.html#t6
3188 * There are two new settings for GForce
3189 * the sampler one:
3190 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3191 * and the texture one:
3192 * GL_MAX_TEXTURE_COORDS_ARB.
3193 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3194 ******************/
3196 oldValue = This->stateBlock->samplerState[Sampler][Type];
3197 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3198 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3200 /* Handle recording of state blocks */
3201 if (This->isRecordingState) {
3202 TRACE("Recording... not performing anything\n");
3203 return WINED3D_OK;
3206 if(oldValue == Value) {
3207 TRACE("Application is setting the old value over, nothing to do\n");
3208 return WINED3D_OK;
3211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3213 return WINED3D_OK;
3216 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3219 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3220 This, Sampler, debug_d3dsamplerstate(Type), Type);
3222 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3223 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3226 *Value = This->stateBlock->samplerState[Sampler][Type];
3227 TRACE("(%p) : Returning %#x\n", This, *Value);
3229 return WINED3D_OK;
3232 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3235 This->updateStateBlock->changed.scissorRect = TRUE;
3236 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3237 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3238 return WINED3D_OK;
3240 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3242 if(This->isRecordingState) {
3243 TRACE("Recording... not performing anything\n");
3244 return WINED3D_OK;
3247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3249 return WINED3D_OK;
3252 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3256 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3257 return WINED3D_OK;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3262 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3264 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3266 This->updateStateBlock->vertexDecl = pDecl;
3267 This->updateStateBlock->changed.vertexDecl = TRUE;
3269 if (This->isRecordingState) {
3270 TRACE("Recording... not performing anything\n");
3271 return WINED3D_OK;
3272 } else if(pDecl == oldDecl) {
3273 /* Checked after the assignment to allow proper stateblock recording */
3274 TRACE("Application is setting the old declaration over, nothing to do\n");
3275 return WINED3D_OK;
3278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3279 return WINED3D_OK;
3282 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3285 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3287 *ppDecl = This->stateBlock->vertexDecl;
3288 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3289 return WINED3D_OK;
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3294 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3296 This->updateStateBlock->vertexShader = pShader;
3297 This->updateStateBlock->changed.vertexShader = TRUE;
3299 if (This->isRecordingState) {
3300 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3301 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3302 TRACE("Recording... not performing anything\n");
3303 return WINED3D_OK;
3304 } else if(oldShader == pShader) {
3305 /* Checked here to allow proper stateblock recording */
3306 TRACE("App is setting the old shader over, nothing to do\n");
3307 return WINED3D_OK;
3310 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3311 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3312 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3314 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3316 return WINED3D_OK;
3319 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 if (NULL == ppShader) {
3323 return WINED3DERR_INVALIDCALL;
3325 *ppShader = This->stateBlock->vertexShader;
3326 if( NULL != *ppShader)
3327 IWineD3DVertexShader_AddRef(*ppShader);
3329 TRACE("(%p) : returning %p\n", This, *ppShader);
3330 return WINED3D_OK;
3333 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3334 IWineD3DDevice *iface,
3335 UINT start,
3336 CONST BOOL *srcData,
3337 UINT count) {
3339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3340 int i, cnt = min(count, MAX_CONST_B - start);
3342 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3343 iface, srcData, start, count);
3345 if (srcData == NULL || cnt < 0)
3346 return WINED3DERR_INVALIDCALL;
3348 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3349 for (i = 0; i < cnt; i++)
3350 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3352 for (i = start; i < cnt + start; ++i) {
3353 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3358 return WINED3D_OK;
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3362 IWineD3DDevice *iface,
3363 UINT start,
3364 BOOL *dstData,
3365 UINT count) {
3367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3368 int cnt = min(count, MAX_CONST_B - start);
3370 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3371 iface, dstData, start, count);
3373 if (dstData == NULL || cnt < 0)
3374 return WINED3DERR_INVALIDCALL;
3376 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3377 return WINED3D_OK;
3380 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3381 IWineD3DDevice *iface,
3382 UINT start,
3383 CONST int *srcData,
3384 UINT count) {
3386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 int i, cnt = min(count, MAX_CONST_I - start);
3389 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3390 iface, srcData, start, count);
3392 if (srcData == NULL || cnt < 0)
3393 return WINED3DERR_INVALIDCALL;
3395 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3396 for (i = 0; i < cnt; i++)
3397 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3398 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3400 for (i = start; i < cnt + start; ++i) {
3401 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3406 return WINED3D_OK;
3409 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3410 IWineD3DDevice *iface,
3411 UINT start,
3412 int *dstData,
3413 UINT count) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 int cnt = min(count, MAX_CONST_I - start);
3418 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3419 iface, dstData, start, count);
3421 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3422 return WINED3DERR_INVALIDCALL;
3424 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3425 return WINED3D_OK;
3428 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3429 IWineD3DDevice *iface,
3430 UINT start,
3431 CONST float *srcData,
3432 UINT count) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 int i;
3437 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3438 iface, srcData, start, count);
3440 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3441 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3442 return WINED3DERR_INVALIDCALL;
3444 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3445 if(TRACE_ON(d3d)) {
3446 for (i = 0; i < count; i++)
3447 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3448 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3451 for (i = start; i < count + start; ++i) {
3452 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3453 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3454 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3455 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3456 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3458 ptr->idx[ptr->count++] = i;
3459 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3465 return WINED3D_OK;
3468 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3469 IWineD3DDevice *iface,
3470 UINT start,
3471 float *dstData,
3472 UINT count) {
3474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3475 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3477 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3478 iface, dstData, start, count);
3480 if (dstData == NULL || cnt < 0)
3481 return WINED3DERR_INVALIDCALL;
3483 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3484 return WINED3D_OK;
3487 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3488 DWORD i;
3489 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3490 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3494 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3495 int i = This->rev_tex_unit_map[unit];
3496 int j = This->texUnitMap[stage];
3498 This->texUnitMap[stage] = unit;
3499 if (i != -1 && i != stage) {
3500 This->texUnitMap[i] = -1;
3503 This->rev_tex_unit_map[unit] = stage;
3504 if (j != -1 && j != unit) {
3505 This->rev_tex_unit_map[j] = -1;
3509 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3510 int i;
3512 for (i = 0; i < MAX_TEXTURES; ++i) {
3513 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3514 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3515 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3516 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3517 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3518 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3519 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3520 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3522 if (color_op == WINED3DTOP_DISABLE) {
3523 /* Not used, and disable higher stages */
3524 while (i < MAX_TEXTURES) {
3525 This->fixed_function_usage_map[i] = FALSE;
3526 ++i;
3528 break;
3531 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3532 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3533 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3534 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3535 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3536 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3537 This->fixed_function_usage_map[i] = TRUE;
3538 } else {
3539 This->fixed_function_usage_map[i] = FALSE;
3542 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3543 This->fixed_function_usage_map[i+1] = TRUE;
3548 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3549 int i, tex;
3551 device_update_fixed_function_usage_map(This);
3553 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3554 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3555 if (!This->fixed_function_usage_map[i]) continue;
3557 if (This->texUnitMap[i] != i) {
3558 device_map_stage(This, i, i);
3559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3560 markTextureStagesDirty(This, i);
3563 return;
3566 /* Now work out the mapping */
3567 tex = 0;
3568 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3569 if (!This->fixed_function_usage_map[i]) continue;
3571 if (This->texUnitMap[i] != tex) {
3572 device_map_stage(This, i, tex);
3573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3574 markTextureStagesDirty(This, i);
3577 ++tex;
3581 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3582 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3583 int i;
3585 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3586 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3587 device_map_stage(This, i, i);
3588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3589 if (i < MAX_TEXTURES) {
3590 markTextureStagesDirty(This, i);
3596 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3597 int current_mapping = This->rev_tex_unit_map[unit];
3599 if (current_mapping == -1) {
3600 /* Not currently used */
3601 return TRUE;
3604 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3605 /* Used by a fragment sampler */
3607 if (!pshader_sampler_tokens) {
3608 /* No pixel shader, check fixed function */
3609 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3612 /* Pixel shader, check the shader's sampler map */
3613 return !pshader_sampler_tokens[current_mapping];
3616 /* Used by a vertex sampler */
3617 return !vshader_sampler_tokens[current_mapping];
3620 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3621 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3622 DWORD *pshader_sampler_tokens = NULL;
3623 int start = GL_LIMITS(combined_samplers) - 1;
3624 int i;
3626 if (ps) {
3627 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3629 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3630 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3631 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3634 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3635 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3636 if (vshader_sampler_tokens[i]) {
3637 if (This->texUnitMap[vsampler_idx] != -1) {
3638 /* Already mapped somewhere */
3639 continue;
3642 while (start >= 0) {
3643 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3644 device_map_stage(This, vsampler_idx, start);
3645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3647 --start;
3648 break;
3651 --start;
3657 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3658 BOOL vs = use_vs(This);
3659 BOOL ps = use_ps(This);
3661 * Rules are:
3662 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3663 * that would be really messy and require shader recompilation
3664 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3665 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3667 if (ps) {
3668 device_map_psamplers(This);
3669 } else {
3670 device_map_fixed_function_samplers(This);
3673 if (vs) {
3674 device_map_vsamplers(This, ps);
3678 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3680 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3681 This->updateStateBlock->pixelShader = pShader;
3682 This->updateStateBlock->changed.pixelShader = TRUE;
3684 /* Handle recording of state blocks */
3685 if (This->isRecordingState) {
3686 TRACE("Recording... not performing anything\n");
3689 if (This->isRecordingState) {
3690 TRACE("Recording... not performing anything\n");
3691 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3692 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3693 return WINED3D_OK;
3696 if(pShader == oldShader) {
3697 TRACE("App is setting the old pixel shader over, nothing to do\n");
3698 return WINED3D_OK;
3701 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3702 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3704 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3705 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3707 return WINED3D_OK;
3710 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3713 if (NULL == ppShader) {
3714 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3715 return WINED3DERR_INVALIDCALL;
3718 *ppShader = This->stateBlock->pixelShader;
3719 if (NULL != *ppShader) {
3720 IWineD3DPixelShader_AddRef(*ppShader);
3722 TRACE("(%p) : returning %p\n", This, *ppShader);
3723 return WINED3D_OK;
3726 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3727 IWineD3DDevice *iface,
3728 UINT start,
3729 CONST BOOL *srcData,
3730 UINT count) {
3732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3733 int i, cnt = min(count, MAX_CONST_B - start);
3735 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3736 iface, srcData, start, count);
3738 if (srcData == NULL || cnt < 0)
3739 return WINED3DERR_INVALIDCALL;
3741 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3742 for (i = 0; i < cnt; i++)
3743 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3745 for (i = start; i < cnt + start; ++i) {
3746 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3751 return WINED3D_OK;
3754 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3755 IWineD3DDevice *iface,
3756 UINT start,
3757 BOOL *dstData,
3758 UINT count) {
3760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3761 int cnt = min(count, MAX_CONST_B - start);
3763 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3764 iface, dstData, start, count);
3766 if (dstData == NULL || cnt < 0)
3767 return WINED3DERR_INVALIDCALL;
3769 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3770 return WINED3D_OK;
3773 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3774 IWineD3DDevice *iface,
3775 UINT start,
3776 CONST int *srcData,
3777 UINT count) {
3779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3780 int i, cnt = min(count, MAX_CONST_I - start);
3782 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3783 iface, srcData, start, count);
3785 if (srcData == NULL || cnt < 0)
3786 return WINED3DERR_INVALIDCALL;
3788 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3789 for (i = 0; i < cnt; i++)
3790 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3791 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3793 for (i = start; i < cnt + start; ++i) {
3794 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3799 return WINED3D_OK;
3802 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3803 IWineD3DDevice *iface,
3804 UINT start,
3805 int *dstData,
3806 UINT count) {
3808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3809 int cnt = min(count, MAX_CONST_I - start);
3811 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3812 iface, dstData, start, count);
3814 if (dstData == NULL || cnt < 0)
3815 return WINED3DERR_INVALIDCALL;
3817 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3818 return WINED3D_OK;
3821 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3822 IWineD3DDevice *iface,
3823 UINT start,
3824 CONST float *srcData,
3825 UINT count) {
3827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3828 int i;
3830 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3831 iface, srcData, start, count);
3833 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3834 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3835 return WINED3DERR_INVALIDCALL;
3837 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3838 if(TRACE_ON(d3d)) {
3839 for (i = 0; i < count; i++)
3840 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3841 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3844 for (i = start; i < count + start; ++i) {
3845 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3846 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3847 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3848 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3849 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3851 ptr->idx[ptr->count++] = i;
3852 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3858 return WINED3D_OK;
3861 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3862 IWineD3DDevice *iface,
3863 UINT start,
3864 float *dstData,
3865 UINT count) {
3867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3868 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3870 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3871 iface, dstData, start, count);
3873 if (dstData == NULL || cnt < 0)
3874 return WINED3DERR_INVALIDCALL;
3876 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3877 return WINED3D_OK;
3880 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3881 static HRESULT
3882 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3883 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3884 unsigned int i;
3885 DWORD DestFVF = dest->fvf;
3886 WINED3DVIEWPORT vp;
3887 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3888 BOOL doClip;
3889 int numTextures;
3891 if (lpStrideData->u.s.normal.lpData) {
3892 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3895 if (lpStrideData->u.s.position.lpData == NULL) {
3896 ERR("Source has no position mask\n");
3897 return WINED3DERR_INVALIDCALL;
3900 /* We might access VBOs from this code, so hold the lock */
3901 ENTER_GL();
3903 if (dest->resource.allocatedMemory == NULL) {
3904 /* This may happen if we do direct locking into a vbo. Unlikely,
3905 * but theoretically possible(ddraw processvertices test)
3907 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3908 if(!dest->resource.allocatedMemory) {
3909 LEAVE_GL();
3910 ERR("Out of memory\n");
3911 return E_OUTOFMEMORY;
3913 if(dest->vbo) {
3914 void *src;
3915 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3916 checkGLcall("glBindBufferARB");
3917 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3918 if(src) {
3919 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3921 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3922 checkGLcall("glUnmapBufferARB");
3926 /* Get a pointer into the destination vbo(create one if none exists) and
3927 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3929 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3930 CreateVBO(dest);
3933 if(dest->vbo) {
3934 unsigned char extrabytes = 0;
3935 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3936 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3937 * this may write 4 extra bytes beyond the area that should be written
3939 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3940 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3941 if(!dest_conv_addr) {
3942 ERR("Out of memory\n");
3943 /* Continue without storing converted vertices */
3945 dest_conv = dest_conv_addr;
3948 /* Should I clip?
3949 * a) WINED3DRS_CLIPPING is enabled
3950 * b) WINED3DVOP_CLIP is passed
3952 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3953 static BOOL warned = FALSE;
3955 * The clipping code is not quite correct. Some things need
3956 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3957 * so disable clipping for now.
3958 * (The graphics in Half-Life are broken, and my processvertices
3959 * test crashes with IDirect3DDevice3)
3960 doClip = TRUE;
3962 doClip = FALSE;
3963 if(!warned) {
3964 warned = TRUE;
3965 FIXME("Clipping is broken and disabled for now\n");
3967 } else doClip = FALSE;
3968 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3970 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3971 WINED3DTS_VIEW,
3972 &view_mat);
3973 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3974 WINED3DTS_PROJECTION,
3975 &proj_mat);
3976 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3977 WINED3DTS_WORLDMATRIX(0),
3978 &world_mat);
3980 TRACE("View mat:\n");
3981 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);
3982 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);
3983 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);
3984 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);
3986 TRACE("Proj mat:\n");
3987 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);
3988 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);
3989 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);
3990 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);
3992 TRACE("World mat:\n");
3993 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);
3994 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);
3995 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);
3996 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);
3998 /* Get the viewport */
3999 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4000 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4001 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4003 multiply_matrix(&mat,&view_mat,&world_mat);
4004 multiply_matrix(&mat,&proj_mat,&mat);
4006 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4008 for (i = 0; i < dwCount; i+= 1) {
4009 unsigned int tex_index;
4011 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4012 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4013 /* The position first */
4014 float *p =
4015 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4016 float x, y, z, rhw;
4017 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4019 /* Multiplication with world, view and projection matrix */
4020 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);
4021 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);
4022 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);
4023 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);
4025 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4027 /* WARNING: The following things are taken from d3d7 and were not yet checked
4028 * against d3d8 or d3d9!
4031 /* Clipping conditions: From
4032 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4034 * A vertex is clipped if it does not match the following requirements
4035 * -rhw < x <= rhw
4036 * -rhw < y <= rhw
4037 * 0 < z <= rhw
4038 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4040 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4041 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4045 if( !doClip ||
4046 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4047 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4048 ( rhw > eps ) ) ) {
4050 /* "Normal" viewport transformation (not clipped)
4051 * 1) The values are divided by rhw
4052 * 2) The y axis is negative, so multiply it with -1
4053 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4054 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4055 * 4) Multiply x with Width/2 and add Width/2
4056 * 5) The same for the height
4057 * 6) Add the viewpoint X and Y to the 2D coordinates and
4058 * The minimum Z value to z
4059 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4061 * Well, basically it's simply a linear transformation into viewport
4062 * coordinates
4065 x /= rhw;
4066 y /= rhw;
4067 z /= rhw;
4069 y *= -1;
4071 x *= vp.Width / 2;
4072 y *= vp.Height / 2;
4073 z *= vp.MaxZ - vp.MinZ;
4075 x += vp.Width / 2 + vp.X;
4076 y += vp.Height / 2 + vp.Y;
4077 z += vp.MinZ;
4079 rhw = 1 / rhw;
4080 } else {
4081 /* That vertex got clipped
4082 * Contrary to OpenGL it is not dropped completely, it just
4083 * undergoes a different calculation.
4085 TRACE("Vertex got clipped\n");
4086 x += rhw;
4087 y += rhw;
4089 x /= 2;
4090 y /= 2;
4092 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4093 * outside of the main vertex buffer memory. That needs some more
4094 * investigation...
4098 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4101 ( (float *) dest_ptr)[0] = x;
4102 ( (float *) dest_ptr)[1] = y;
4103 ( (float *) dest_ptr)[2] = z;
4104 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4106 dest_ptr += 3 * sizeof(float);
4108 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4109 dest_ptr += sizeof(float);
4112 if(dest_conv) {
4113 float w = 1 / rhw;
4114 ( (float *) dest_conv)[0] = x * w;
4115 ( (float *) dest_conv)[1] = y * w;
4116 ( (float *) dest_conv)[2] = z * w;
4117 ( (float *) dest_conv)[3] = w;
4119 dest_conv += 3 * sizeof(float);
4121 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4122 dest_conv += sizeof(float);
4126 if (DestFVF & WINED3DFVF_PSIZE) {
4127 dest_ptr += sizeof(DWORD);
4128 if(dest_conv) dest_conv += sizeof(DWORD);
4130 if (DestFVF & WINED3DFVF_NORMAL) {
4131 float *normal =
4132 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4133 /* AFAIK this should go into the lighting information */
4134 FIXME("Didn't expect the destination to have a normal\n");
4135 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4136 if(dest_conv) {
4137 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4141 if (DestFVF & WINED3DFVF_DIFFUSE) {
4142 DWORD *color_d =
4143 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4144 if(!color_d) {
4145 static BOOL warned = FALSE;
4147 if(!warned) {
4148 ERR("No diffuse color in source, but destination has one\n");
4149 warned = TRUE;
4152 *( (DWORD *) dest_ptr) = 0xffffffff;
4153 dest_ptr += sizeof(DWORD);
4155 if(dest_conv) {
4156 *( (DWORD *) dest_conv) = 0xffffffff;
4157 dest_conv += sizeof(DWORD);
4160 else {
4161 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4162 if(dest_conv) {
4163 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4164 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4165 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4166 dest_conv += sizeof(DWORD);
4171 if (DestFVF & WINED3DFVF_SPECULAR) {
4172 /* What's the color value in the feedback buffer? */
4173 DWORD *color_s =
4174 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4175 if(!color_s) {
4176 static BOOL warned = FALSE;
4178 if(!warned) {
4179 ERR("No specular color in source, but destination has one\n");
4180 warned = TRUE;
4183 *( (DWORD *) dest_ptr) = 0xFF000000;
4184 dest_ptr += sizeof(DWORD);
4186 if(dest_conv) {
4187 *( (DWORD *) dest_conv) = 0xFF000000;
4188 dest_conv += sizeof(DWORD);
4191 else {
4192 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4193 if(dest_conv) {
4194 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4195 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4196 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4197 dest_conv += sizeof(DWORD);
4202 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4203 float *tex_coord =
4204 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4205 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4206 if(!tex_coord) {
4207 ERR("No source texture, but destination requests one\n");
4208 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4209 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4211 else {
4212 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4213 if(dest_conv) {
4214 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4220 if(dest_conv) {
4221 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4222 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4223 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4224 dwCount * get_flexible_vertex_size(DestFVF),
4225 dest_conv_addr));
4226 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4227 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4230 LEAVE_GL();
4232 return WINED3D_OK;
4234 #undef copy_and_next
4236 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4238 WineDirect3DVertexStridedData strided;
4239 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4240 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4242 if(pVertexDecl) {
4243 ERR("Output vertex declaration not implemented yet\n");
4246 /* Need any context to write to the vbo. */
4247 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4249 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4250 * control the streamIsUP flag, thus restore it afterwards.
4252 This->stateBlock->streamIsUP = FALSE;
4253 memset(&strided, 0, sizeof(strided));
4254 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4255 This->stateBlock->streamIsUP = streamWasUP;
4257 if(vbo || SrcStartIndex) {
4258 unsigned int i;
4259 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4260 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4262 * Also get the start index in, but only loop over all elements if there's something to add at all.
4264 #define FIXSRC(type) \
4265 if(strided.u.s.type.VBO) { \
4266 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4267 strided.u.s.type.VBO = 0; \
4268 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4269 ENTER_GL(); \
4270 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4271 vb->vbo = 0; \
4272 LEAVE_GL(); \
4274 if(strided.u.s.type.lpData) { \
4275 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4277 FIXSRC(position);
4278 FIXSRC(blendWeights);
4279 FIXSRC(blendMatrixIndices);
4280 FIXSRC(normal);
4281 FIXSRC(pSize);
4282 FIXSRC(diffuse);
4283 FIXSRC(specular);
4284 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4285 FIXSRC(texCoords[i]);
4287 FIXSRC(position2);
4288 FIXSRC(normal2);
4289 FIXSRC(tangent);
4290 FIXSRC(binormal);
4291 FIXSRC(tessFactor);
4292 FIXSRC(fog);
4293 FIXSRC(depth);
4294 FIXSRC(sample);
4295 #undef FIXSRC
4298 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4301 /*****
4302 * Get / Set Texture Stage States
4303 * TODO: Verify against dx9 definitions
4304 *****/
4305 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4307 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4309 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4311 if (Stage >= MAX_TEXTURES) {
4312 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4313 return WINED3D_OK;
4316 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4317 This->updateStateBlock->textureState[Stage][Type] = Value;
4319 if (This->isRecordingState) {
4320 TRACE("Recording... not performing anything\n");
4321 return WINED3D_OK;
4324 /* Checked after the assignments to allow proper stateblock recording */
4325 if(oldValue == Value) {
4326 TRACE("App is setting the old value over, nothing to do\n");
4327 return WINED3D_OK;
4330 if(Stage > This->stateBlock->lowest_disabled_stage &&
4331 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4332 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4333 * Changes in other states are important on disabled stages too
4335 return WINED3D_OK;
4338 if(Type == WINED3DTSS_COLOROP) {
4339 int i;
4341 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4342 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4343 * they have to be disabled
4345 * The current stage is dirtified below.
4347 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4348 TRACE("Additionally dirtifying stage %d\n", i);
4349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4351 This->stateBlock->lowest_disabled_stage = Stage;
4352 TRACE("New lowest disabled: %d\n", Stage);
4353 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4354 /* Previously disabled stage enabled. Stages above it may need enabling
4355 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4356 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4358 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4361 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4362 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4363 break;
4365 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4368 This->stateBlock->lowest_disabled_stage = i;
4369 TRACE("New lowest disabled: %d\n", i);
4371 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4372 /* TODO: Built a stage -> texture unit mapping for register combiners */
4376 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4378 return WINED3D_OK;
4381 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4383 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4384 *pValue = This->updateStateBlock->textureState[Stage][Type];
4385 return WINED3D_OK;
4388 /*****
4389 * Get / Set Texture
4390 *****/
4391 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4393 IWineD3DBaseTexture *oldTexture;
4395 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4397 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4398 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4401 oldTexture = This->updateStateBlock->textures[Stage];
4403 if(pTexture != NULL) {
4404 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4406 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4407 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4408 return WINED3DERR_INVALIDCALL;
4410 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4413 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4414 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4416 This->updateStateBlock->changed.textures[Stage] = TRUE;
4417 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4418 This->updateStateBlock->textures[Stage] = pTexture;
4420 /* Handle recording of state blocks */
4421 if (This->isRecordingState) {
4422 TRACE("Recording... not performing anything\n");
4423 return WINED3D_OK;
4426 if(oldTexture == pTexture) {
4427 TRACE("App is setting the same texture again, nothing to do\n");
4428 return WINED3D_OK;
4431 /** NOTE: MSDN says that setTexture increases the reference count,
4432 * and that the application must set the texture back to null (or have a leaky application),
4433 * This means we should pass the refcount up to the parent
4434 *******************************/
4435 if (NULL != This->updateStateBlock->textures[Stage]) {
4436 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4437 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4439 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4440 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4441 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4442 * so the COLOROP and ALPHAOP have to be dirtified.
4444 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4447 if(bindCount == 1) {
4448 new->baseTexture.sampler = Stage;
4450 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4454 if (NULL != oldTexture) {
4455 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4456 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4458 IWineD3DBaseTexture_Release(oldTexture);
4459 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4464 if(bindCount && old->baseTexture.sampler == Stage) {
4465 int i;
4466 /* Have to do a search for the other sampler(s) where the texture is bound to
4467 * Shouldn't happen as long as apps bind a texture only to one stage
4469 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4470 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4471 if(This->updateStateBlock->textures[i] == oldTexture) {
4472 old->baseTexture.sampler = i;
4473 break;
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4481 return WINED3D_OK;
4484 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4487 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4489 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4490 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4493 *ppTexture=This->stateBlock->textures[Stage];
4494 if (*ppTexture)
4495 IWineD3DBaseTexture_AddRef(*ppTexture);
4497 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4499 return WINED3D_OK;
4502 /*****
4503 * Get Back Buffer
4504 *****/
4505 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4506 IWineD3DSurface **ppBackBuffer) {
4507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4508 IWineD3DSwapChain *swapChain;
4509 HRESULT hr;
4511 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4513 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4514 if (hr == WINED3D_OK) {
4515 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4516 IWineD3DSwapChain_Release(swapChain);
4517 } else {
4518 *ppBackBuffer = NULL;
4520 return hr;
4523 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4525 WARN("(%p) : stub, calling idirect3d for now\n", This);
4526 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4529 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4531 IWineD3DSwapChain *swapChain;
4532 HRESULT hr;
4534 if(iSwapChain > 0) {
4535 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4536 if (hr == WINED3D_OK) {
4537 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4538 IWineD3DSwapChain_Release(swapChain);
4539 } else {
4540 FIXME("(%p) Error getting display mode\n", This);
4542 } else {
4543 /* Don't read the real display mode,
4544 but return the stored mode instead. X11 can't change the color
4545 depth, and some apps are pretty angry if they SetDisplayMode from
4546 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4548 Also don't relay to the swapchain because with ddraw it's possible
4549 that there isn't a swapchain at all */
4550 pMode->Width = This->ddraw_width;
4551 pMode->Height = This->ddraw_height;
4552 pMode->Format = This->ddraw_format;
4553 pMode->RefreshRate = 0;
4554 hr = WINED3D_OK;
4557 return hr;
4560 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4562 TRACE("(%p)->(%p)\n", This, hWnd);
4564 if(This->ddraw_fullscreen) {
4565 if(This->ddraw_window && This->ddraw_window != hWnd) {
4566 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4568 if(hWnd && This->ddraw_window != hWnd) {
4569 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4573 This->ddraw_window = hWnd;
4574 return WINED3D_OK;
4577 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4579 TRACE("(%p)->(%p)\n", This, hWnd);
4581 *hWnd = This->ddraw_window;
4582 return WINED3D_OK;
4585 /*****
4586 * Stateblock related functions
4587 *****/
4589 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4591 IWineD3DStateBlockImpl *object;
4592 HRESULT temp_result;
4593 int i;
4595 TRACE("(%p)\n", This);
4597 if (This->isRecordingState) {
4598 return WINED3DERR_INVALIDCALL;
4601 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4602 if (NULL == object ) {
4603 FIXME("(%p)Error allocating memory for stateblock\n", This);
4604 return E_OUTOFMEMORY;
4606 TRACE("(%p) created object %p\n", This, object);
4607 object->wineD3DDevice= This;
4608 /** FIXME: object->parent = parent; **/
4609 object->parent = NULL;
4610 object->blockType = WINED3DSBT_RECORDED;
4611 object->ref = 1;
4612 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4614 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4615 list_init(&object->lightMap[i]);
4618 temp_result = allocate_shader_constants(object);
4619 if (WINED3D_OK != temp_result)
4620 return temp_result;
4622 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4623 This->updateStateBlock = object;
4624 This->isRecordingState = TRUE;
4626 TRACE("(%p) recording stateblock %p\n",This , object);
4627 return WINED3D_OK;
4630 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4632 unsigned int i, j;
4633 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4635 if (!This->isRecordingState) {
4636 FIXME("(%p) not recording! returning error\n", This);
4637 *ppStateBlock = NULL;
4638 return WINED3DERR_INVALIDCALL;
4641 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4642 if(object->changed.renderState[i]) {
4643 object->contained_render_states[object->num_contained_render_states] = i;
4644 object->num_contained_render_states++;
4647 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4648 if(object->changed.transform[i]) {
4649 object->contained_transform_states[object->num_contained_transform_states] = i;
4650 object->num_contained_transform_states++;
4653 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4654 if(object->changed.vertexShaderConstantsF[i]) {
4655 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4656 object->num_contained_vs_consts_f++;
4659 for(i = 0; i < MAX_CONST_I; i++) {
4660 if(object->changed.vertexShaderConstantsI[i]) {
4661 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4662 object->num_contained_vs_consts_i++;
4665 for(i = 0; i < MAX_CONST_B; i++) {
4666 if(object->changed.vertexShaderConstantsB[i]) {
4667 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4668 object->num_contained_vs_consts_b++;
4671 for(i = 0; i < MAX_CONST_I; i++) {
4672 if(object->changed.pixelShaderConstantsI[i]) {
4673 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4674 object->num_contained_ps_consts_i++;
4677 for(i = 0; i < MAX_CONST_B; i++) {
4678 if(object->changed.pixelShaderConstantsB[i]) {
4679 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4680 object->num_contained_ps_consts_b++;
4683 for(i = 0; i < MAX_TEXTURES; i++) {
4684 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4685 if(object->changed.textureState[i][j]) {
4686 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4687 object->contained_tss_states[object->num_contained_tss_states].state = j;
4688 object->num_contained_tss_states++;
4692 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4693 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4694 if(object->changed.samplerState[i][j]) {
4695 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4696 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4697 object->num_contained_sampler_states++;
4702 *ppStateBlock = (IWineD3DStateBlock*) object;
4703 This->isRecordingState = FALSE;
4704 This->updateStateBlock = This->stateBlock;
4705 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4706 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4707 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4708 return WINED3D_OK;
4711 /*****
4712 * Scene related functions
4713 *****/
4714 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4715 /* At the moment we have no need for any functionality at the beginning
4716 of a scene */
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 TRACE("(%p)\n", This);
4720 if(This->inScene) {
4721 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4722 return WINED3DERR_INVALIDCALL;
4724 This->inScene = TRUE;
4725 return WINED3D_OK;
4728 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4729 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4730 TRACE("(%p)\n", This);
4732 if(!This->inScene) {
4733 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4734 return WINED3DERR_INVALIDCALL;
4737 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4738 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4739 ENTER_GL();
4740 glFlush();
4741 checkGLcall("glFlush");
4742 LEAVE_GL();
4744 This->inScene = FALSE;
4745 return WINED3D_OK;
4748 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4749 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4750 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4752 IWineD3DSwapChain *swapChain = NULL;
4753 int i;
4754 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4756 TRACE("(%p) Presenting the frame\n", This);
4758 for(i = 0 ; i < swapchains ; i ++) {
4760 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4761 TRACE("presentinng chain %d, %p\n", i, swapChain);
4762 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4763 IWineD3DSwapChain_Release(swapChain);
4766 return WINED3D_OK;
4769 /* Not called from the VTable (internal subroutine) */
4770 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4771 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4772 float Z, DWORD Stencil) {
4773 GLbitfield glMask = 0;
4774 unsigned int i;
4775 WINED3DRECT curRect;
4776 RECT vp_rect;
4777 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4778 UINT drawable_width, drawable_height;
4780 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4781 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4782 * for the cleared parts, and the untouched parts.
4784 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4785 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4786 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4787 * checking all this if the dest surface is in the drawable anyway.
4789 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4790 while(1) {
4791 if(vp->X != 0 || vp->Y != 0 ||
4792 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4793 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4794 break;
4796 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4797 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4798 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4799 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4800 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4801 break;
4803 if(Count > 0 && pRects && (
4804 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4805 pRects[0].x2 < target->currentDesc.Width ||
4806 pRects[0].y2 < target->currentDesc.Height)) {
4807 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4808 break;
4810 break;
4814 target->get_drawable_size(target, &drawable_width, &drawable_height);
4816 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4817 ENTER_GL();
4819 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4820 apply_fbo_state((IWineD3DDevice *) This);
4823 /* Only set the values up once, as they are not changing */
4824 if (Flags & WINED3DCLEAR_STENCIL) {
4825 glClearStencil(Stencil);
4826 checkGLcall("glClearStencil");
4827 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4828 glStencilMask(0xFFFFFFFF);
4831 if (Flags & WINED3DCLEAR_ZBUFFER) {
4832 glDepthMask(GL_TRUE);
4833 glClearDepth(Z);
4834 checkGLcall("glClearDepth");
4835 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4836 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4839 if (Flags & WINED3DCLEAR_TARGET) {
4840 TRACE("Clearing screen with glClear to color %x\n", Color);
4841 glClearColor(D3DCOLOR_R(Color),
4842 D3DCOLOR_G(Color),
4843 D3DCOLOR_B(Color),
4844 D3DCOLOR_A(Color));
4845 checkGLcall("glClearColor");
4847 /* Clear ALL colors! */
4848 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4849 glMask = glMask | GL_COLOR_BUFFER_BIT;
4852 vp_rect.left = vp->X;
4853 vp_rect.top = vp->Y;
4854 vp_rect.right = vp->X + vp->Width;
4855 vp_rect.bottom = vp->Y + vp->Height;
4856 if (!(Count > 0 && pRects)) {
4857 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4858 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4860 if(This->render_offscreen) {
4861 glScissor(vp_rect.left, vp_rect.top,
4862 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4863 } else {
4864 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4865 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4867 checkGLcall("glScissor");
4868 glClear(glMask);
4869 checkGLcall("glClear");
4870 } else {
4871 /* Now process each rect in turn */
4872 for (i = 0; i < Count; i++) {
4873 /* Note gl uses lower left, width/height */
4874 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4875 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4876 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4878 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4879 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4880 curRect.x1, (target->currentDesc.Height - curRect.y2),
4881 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4883 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4884 * The rectangle is not cleared, no error is returned, but further rectanlges are
4885 * still cleared if they are valid
4887 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4888 TRACE("Rectangle with negative dimensions, ignoring\n");
4889 continue;
4892 if(This->render_offscreen) {
4893 glScissor(curRect.x1, curRect.y1,
4894 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4895 } else {
4896 glScissor(curRect.x1, drawable_height - curRect.y2,
4897 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4899 checkGLcall("glScissor");
4901 glClear(glMask);
4902 checkGLcall("glClear");
4906 /* Restore the old values (why..?) */
4907 if (Flags & WINED3DCLEAR_STENCIL) {
4908 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4910 if (Flags & WINED3DCLEAR_TARGET) {
4911 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4912 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4913 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4914 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4915 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4917 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4918 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4920 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4921 /* TODO: Move the fbo logic into ModifyLocation() */
4922 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4923 target->Flags |= SFLAG_INTEXTURE;
4926 LEAVE_GL();
4928 return WINED3D_OK;
4931 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4932 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4934 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4936 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4937 Count, pRects, Flags, Color, Z, Stencil);
4939 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4940 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4941 /* TODO: What about depth stencil buffers without stencil bits? */
4942 return WINED3DERR_INVALIDCALL;
4945 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4948 /*****
4949 * Drawing functions
4950 *****/
4951 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4952 UINT PrimitiveCount) {
4954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4956 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4957 debug_d3dprimitivetype(PrimitiveType),
4958 StartVertex, PrimitiveCount);
4960 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4961 if(This->stateBlock->streamIsUP) {
4962 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4963 This->stateBlock->streamIsUP = FALSE;
4966 if(This->stateBlock->loadBaseVertexIndex != 0) {
4967 This->stateBlock->loadBaseVertexIndex = 0;
4968 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4970 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4971 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4972 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4973 return WINED3D_OK;
4976 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4977 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4978 WINED3DPRIMITIVETYPE PrimitiveType,
4979 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4982 UINT idxStride = 2;
4983 IWineD3DIndexBuffer *pIB;
4984 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4985 GLuint vbo;
4987 pIB = This->stateBlock->pIndexData;
4988 if (!pIB) {
4989 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4990 * without an index buffer set. (The first time at least...)
4991 * D3D8 simply dies, but I doubt it can do much harm to return
4992 * D3DERR_INVALIDCALL there as well. */
4993 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4994 return WINED3DERR_INVALIDCALL;
4997 if(This->stateBlock->streamIsUP) {
4998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4999 This->stateBlock->streamIsUP = FALSE;
5001 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5003 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5004 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5005 minIndex, NumVertices, startIndex, primCount);
5007 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5008 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5009 idxStride = 2;
5010 } else {
5011 idxStride = 4;
5014 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5015 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5016 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5019 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5020 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5022 return WINED3D_OK;
5025 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5026 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5027 UINT VertexStreamZeroStride) {
5028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5029 IWineD3DVertexBuffer *vb;
5031 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5032 debug_d3dprimitivetype(PrimitiveType),
5033 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5035 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5036 vb = This->stateBlock->streamSource[0];
5037 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5038 if(vb) IWineD3DVertexBuffer_Release(vb);
5039 This->stateBlock->streamOffset[0] = 0;
5040 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5041 This->stateBlock->streamIsUP = TRUE;
5042 This->stateBlock->loadBaseVertexIndex = 0;
5044 /* TODO: Only mark dirty if drawing from a different UP address */
5045 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5047 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5048 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5050 /* MSDN specifies stream zero settings must be set to NULL */
5051 This->stateBlock->streamStride[0] = 0;
5052 This->stateBlock->streamSource[0] = NULL;
5054 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5055 * the new stream sources or use UP drawing again
5057 return WINED3D_OK;
5060 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5061 UINT MinVertexIndex, UINT NumVertices,
5062 UINT PrimitiveCount, CONST void* pIndexData,
5063 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5064 UINT VertexStreamZeroStride) {
5065 int idxStride;
5066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5067 IWineD3DVertexBuffer *vb;
5068 IWineD3DIndexBuffer *ib;
5070 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5071 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5072 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5073 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5075 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5076 idxStride = 2;
5077 } else {
5078 idxStride = 4;
5081 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5082 vb = This->stateBlock->streamSource[0];
5083 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5084 if(vb) IWineD3DVertexBuffer_Release(vb);
5085 This->stateBlock->streamIsUP = TRUE;
5086 This->stateBlock->streamOffset[0] = 0;
5087 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5089 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5090 This->stateBlock->baseVertexIndex = 0;
5091 This->stateBlock->loadBaseVertexIndex = 0;
5092 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5096 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5098 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5099 This->stateBlock->streamSource[0] = NULL;
5100 This->stateBlock->streamStride[0] = 0;
5101 ib = This->stateBlock->pIndexData;
5102 if(ib) {
5103 IWineD3DIndexBuffer_Release(ib);
5104 This->stateBlock->pIndexData = NULL;
5106 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5107 * SetStreamSource to specify a vertex buffer
5110 return WINED3D_OK;
5113 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5116 /* Mark the state dirty until we have nicer tracking
5117 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5118 * that value.
5120 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5122 This->stateBlock->baseVertexIndex = 0;
5123 This->up_strided = DrawPrimStrideData;
5124 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5125 This->up_strided = NULL;
5126 return WINED3D_OK;
5129 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5131 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5133 /* Mark the state dirty until we have nicer tracking
5134 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5135 * that value.
5137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5138 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5139 This->stateBlock->streamIsUP = TRUE;
5140 This->stateBlock->baseVertexIndex = 0;
5141 This->up_strided = DrawPrimStrideData;
5142 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5143 This->up_strided = NULL;
5144 return WINED3D_OK;
5147 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5148 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5149 * not callable by the app directly no parameter validation checks are needed here.
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5152 WINED3DLOCKED_BOX src;
5153 WINED3DLOCKED_BOX dst;
5154 HRESULT hr;
5155 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5157 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5158 * dirtification to improve loading performance.
5160 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5161 if(FAILED(hr)) return hr;
5162 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5163 if(FAILED(hr)) {
5164 IWineD3DVolume_UnlockBox(pSourceVolume);
5165 return hr;
5168 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5170 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5171 if(FAILED(hr)) {
5172 IWineD3DVolume_UnlockBox(pSourceVolume);
5173 } else {
5174 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5176 return hr;
5179 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5180 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5182 HRESULT hr = WINED3D_OK;
5183 WINED3DRESOURCETYPE sourceType;
5184 WINED3DRESOURCETYPE destinationType;
5185 int i ,levels;
5187 /* TODO: think about moving the code into IWineD3DBaseTexture */
5189 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5191 /* verify that the source and destination textures aren't NULL */
5192 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5193 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5194 This, pSourceTexture, pDestinationTexture);
5195 hr = WINED3DERR_INVALIDCALL;
5198 if (pSourceTexture == pDestinationTexture) {
5199 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5200 This, pSourceTexture, pDestinationTexture);
5201 hr = WINED3DERR_INVALIDCALL;
5203 /* Verify that the source and destination textures are the same type */
5204 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5205 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5207 if (sourceType != destinationType) {
5208 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5209 This);
5210 hr = WINED3DERR_INVALIDCALL;
5213 /* check that both textures have the identical numbers of levels */
5214 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5215 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5216 hr = WINED3DERR_INVALIDCALL;
5219 if (WINED3D_OK == hr) {
5221 /* Make sure that the destination texture is loaded */
5222 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5224 /* Update every surface level of the texture */
5225 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5227 switch (sourceType) {
5228 case WINED3DRTYPE_TEXTURE:
5230 IWineD3DSurface *srcSurface;
5231 IWineD3DSurface *destSurface;
5233 for (i = 0 ; i < levels ; ++i) {
5234 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5235 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5236 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5237 IWineD3DSurface_Release(srcSurface);
5238 IWineD3DSurface_Release(destSurface);
5239 if (WINED3D_OK != hr) {
5240 WARN("(%p) : Call to update surface failed\n", This);
5241 return hr;
5245 break;
5246 case WINED3DRTYPE_CUBETEXTURE:
5248 IWineD3DSurface *srcSurface;
5249 IWineD3DSurface *destSurface;
5250 WINED3DCUBEMAP_FACES faceType;
5252 for (i = 0 ; i < levels ; ++i) {
5253 /* Update each cube face */
5254 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5255 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5256 if (WINED3D_OK != hr) {
5257 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5258 } else {
5259 TRACE("Got srcSurface %p\n", srcSurface);
5261 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5262 if (WINED3D_OK != hr) {
5263 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5264 } else {
5265 TRACE("Got desrSurface %p\n", destSurface);
5267 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5268 IWineD3DSurface_Release(srcSurface);
5269 IWineD3DSurface_Release(destSurface);
5270 if (WINED3D_OK != hr) {
5271 WARN("(%p) : Call to update surface failed\n", This);
5272 return hr;
5277 break;
5279 case WINED3DRTYPE_VOLUMETEXTURE:
5281 IWineD3DVolume *srcVolume = NULL;
5282 IWineD3DVolume *destVolume = NULL;
5284 for (i = 0 ; i < levels ; ++i) {
5285 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5286 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5287 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5288 IWineD3DVolume_Release(srcVolume);
5289 IWineD3DVolume_Release(destVolume);
5290 if (WINED3D_OK != hr) {
5291 WARN("(%p) : Call to update volume failed\n", This);
5292 return hr;
5296 break;
5298 default:
5299 FIXME("(%p) : Unsupported source and destination type\n", This);
5300 hr = WINED3DERR_INVALIDCALL;
5304 return hr;
5307 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5308 IWineD3DSwapChain *swapChain;
5309 HRESULT hr;
5310 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5311 if(hr == WINED3D_OK) {
5312 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5313 IWineD3DSwapChain_Release(swapChain);
5315 return hr;
5318 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5320 /* return a sensible default */
5321 *pNumPasses = 1;
5322 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5323 FIXME("(%p) : stub\n", This);
5324 return WINED3D_OK;
5327 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329 int j;
5330 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5331 if (PaletteNumber >= MAX_PALETTES) {
5332 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5333 return WINED3DERR_INVALIDCALL;
5335 for (j = 0; j < 256; ++j) {
5336 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5337 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5338 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5339 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5341 TRACE("(%p) : returning\n", This);
5342 return WINED3D_OK;
5345 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5347 int j;
5348 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5349 if (PaletteNumber >= MAX_PALETTES) {
5350 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5351 return WINED3DERR_INVALIDCALL;
5353 for (j = 0; j < 256; ++j) {
5354 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5355 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5356 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5357 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5359 TRACE("(%p) : returning\n", This);
5360 return WINED3D_OK;
5363 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5365 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5366 if (PaletteNumber >= MAX_PALETTES) {
5367 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5368 return WINED3DERR_INVALIDCALL;
5370 /*TODO: stateblocks */
5371 This->currentPalette = PaletteNumber;
5372 TRACE("(%p) : returning\n", This);
5373 return WINED3D_OK;
5376 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5378 if (PaletteNumber == NULL) {
5379 WARN("(%p) : returning Invalid Call\n", This);
5380 return WINED3DERR_INVALIDCALL;
5382 /*TODO: stateblocks */
5383 *PaletteNumber = This->currentPalette;
5384 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5385 return WINED3D_OK;
5388 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5390 static BOOL showFixmes = TRUE;
5391 if (showFixmes) {
5392 FIXME("(%p) : stub\n", This);
5393 showFixmes = FALSE;
5396 This->softwareVertexProcessing = bSoftware;
5397 return WINED3D_OK;
5401 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5403 static BOOL showFixmes = TRUE;
5404 if (showFixmes) {
5405 FIXME("(%p) : stub\n", This);
5406 showFixmes = FALSE;
5408 return This->softwareVertexProcessing;
5412 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5414 IWineD3DSwapChain *swapChain;
5415 HRESULT hr;
5417 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5419 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5420 if(hr == WINED3D_OK){
5421 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5422 IWineD3DSwapChain_Release(swapChain);
5423 }else{
5424 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5426 return hr;
5430 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5432 static BOOL showfixmes = TRUE;
5433 if(nSegments != 0.0f) {
5434 if( showfixmes) {
5435 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5436 showfixmes = FALSE;
5439 return WINED3D_OK;
5442 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5444 static BOOL showfixmes = TRUE;
5445 if( showfixmes) {
5446 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5447 showfixmes = FALSE;
5449 return 0.0f;
5452 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5454 /** TODO: remove casts to IWineD3DSurfaceImpl
5455 * NOTE: move code to surface to accomplish this
5456 ****************************************/
5457 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5458 int srcWidth, srcHeight;
5459 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5460 WINED3DFORMAT destFormat, srcFormat;
5461 UINT destSize;
5462 int srcLeft, destLeft, destTop;
5463 WINED3DPOOL srcPool, destPool;
5464 int offset = 0;
5465 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5466 glDescriptor *glDescription = NULL;
5467 GLenum dummy;
5468 int bpp;
5469 CONVERT_TYPES convert = NO_CONVERSION;
5471 WINED3DSURFACE_DESC winedesc;
5473 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5474 memset(&winedesc, 0, sizeof(winedesc));
5475 winedesc.Width = &srcSurfaceWidth;
5476 winedesc.Height = &srcSurfaceHeight;
5477 winedesc.Pool = &srcPool;
5478 winedesc.Format = &srcFormat;
5480 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5482 winedesc.Width = &destSurfaceWidth;
5483 winedesc.Height = &destSurfaceHeight;
5484 winedesc.Pool = &destPool;
5485 winedesc.Format = &destFormat;
5486 winedesc.Size = &destSize;
5488 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5490 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5491 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5492 return WINED3DERR_INVALIDCALL;
5495 /* This call loads the opengl surface directly, instead of copying the surface to the
5496 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5497 * copy in sysmem and use regular surface loading.
5499 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5500 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5501 if(convert != NO_CONVERSION) {
5502 return IWineD3DSurface_BltFast(pDestinationSurface,
5503 pDestPoint ? pDestPoint->x : 0,
5504 pDestPoint ? pDestPoint->y : 0,
5505 pSourceSurface, (RECT *) pSourceRect, 0);
5508 if (destFormat == WINED3DFMT_UNKNOWN) {
5509 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5510 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5512 /* Get the update surface description */
5513 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5516 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5518 ENTER_GL();
5520 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5521 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5522 checkGLcall("glActiveTextureARB");
5525 /* Make sure the surface is loaded and up to date */
5526 IWineD3DSurface_PreLoad(pDestinationSurface);
5528 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5530 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5531 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5532 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5533 srcLeft = pSourceRect ? pSourceRect->left : 0;
5534 destLeft = pDestPoint ? pDestPoint->x : 0;
5535 destTop = pDestPoint ? pDestPoint->y : 0;
5538 /* This function doesn't support compressed textures
5539 the pitch is just bytesPerPixel * width */
5540 if(srcWidth != srcSurfaceWidth || srcLeft ){
5541 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5542 offset += srcLeft * pSrcSurface->bytesPerPixel;
5543 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5545 /* TODO DXT formats */
5547 if(pSourceRect != NULL && pSourceRect->top != 0){
5548 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5550 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5551 ,This
5552 ,glDescription->level
5553 ,destLeft
5554 ,destTop
5555 ,srcWidth
5556 ,srcHeight
5557 ,glDescription->glFormat
5558 ,glDescription->glType
5559 ,IWineD3DSurface_GetData(pSourceSurface)
5562 /* Sanity check */
5563 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5565 /* need to lock the surface to get the data */
5566 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5569 /* TODO: Cube and volume support */
5570 if(rowoffset != 0){
5571 /* not a whole row so we have to do it a line at a time */
5572 int j;
5574 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5575 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5577 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5579 glTexSubImage2D(glDescription->target
5580 ,glDescription->level
5581 ,destLeft
5583 ,srcWidth
5585 ,glDescription->glFormat
5586 ,glDescription->glType
5587 ,data /* could be quicker using */
5589 data += rowoffset;
5592 } else { /* Full width, so just write out the whole texture */
5594 if (WINED3DFMT_DXT1 == destFormat ||
5595 WINED3DFMT_DXT2 == destFormat ||
5596 WINED3DFMT_DXT3 == destFormat ||
5597 WINED3DFMT_DXT4 == destFormat ||
5598 WINED3DFMT_DXT5 == destFormat) {
5599 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5600 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5601 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5602 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5603 } if (destFormat != srcFormat) {
5604 FIXME("Updating mixed format compressed texture is not curretly support\n");
5605 } else {
5606 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5607 glDescription->level,
5608 glDescription->glFormatInternal,
5609 srcWidth,
5610 srcHeight,
5612 destSize,
5613 IWineD3DSurface_GetData(pSourceSurface));
5615 } else {
5616 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5620 } else {
5621 glTexSubImage2D(glDescription->target
5622 ,glDescription->level
5623 ,destLeft
5624 ,destTop
5625 ,srcWidth
5626 ,srcHeight
5627 ,glDescription->glFormat
5628 ,glDescription->glType
5629 ,IWineD3DSurface_GetData(pSourceSurface)
5633 checkGLcall("glTexSubImage2D");
5635 LEAVE_GL();
5637 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5640 return WINED3D_OK;
5643 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5645 struct WineD3DRectPatch *patch;
5646 unsigned int i;
5647 struct list *e;
5648 BOOL found;
5649 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5651 if(!(Handle || pRectPatchInfo)) {
5652 /* TODO: Write a test for the return value, thus the FIXME */
5653 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5654 return WINED3DERR_INVALIDCALL;
5657 if(Handle) {
5658 i = PATCHMAP_HASHFUNC(Handle);
5659 found = FALSE;
5660 LIST_FOR_EACH(e, &This->patches[i]) {
5661 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5662 if(patch->Handle == Handle) {
5663 found = TRUE;
5664 break;
5668 if(!found) {
5669 TRACE("Patch does not exist. Creating a new one\n");
5670 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5671 patch->Handle = Handle;
5672 list_add_head(&This->patches[i], &patch->entry);
5673 } else {
5674 TRACE("Found existing patch %p\n", patch);
5676 } else {
5677 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5678 * attributes we have to tesselate, read back, and draw. This needs a patch
5679 * management structure instance. Create one.
5681 * A possible improvement is to check if a vertex shader is used, and if not directly
5682 * draw the patch.
5684 FIXME("Drawing an uncached patch. This is slow\n");
5685 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5688 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5689 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5690 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5691 HRESULT hr;
5692 TRACE("Tesselation density or patch info changed, retesselating\n");
5694 if(pRectPatchInfo) {
5695 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5697 patch->numSegs[0] = pNumSegs[0];
5698 patch->numSegs[1] = pNumSegs[1];
5699 patch->numSegs[2] = pNumSegs[2];
5700 patch->numSegs[3] = pNumSegs[3];
5702 hr = tesselate_rectpatch(This, patch);
5703 if(FAILED(hr)) {
5704 WARN("Patch tesselation failed\n");
5706 /* Do not release the handle to store the params of the patch */
5707 if(!Handle) {
5708 HeapFree(GetProcessHeap(), 0, patch);
5710 return hr;
5714 This->currentPatch = patch;
5715 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5716 This->currentPatch = NULL;
5718 /* Destroy uncached patches */
5719 if(!Handle) {
5720 HeapFree(GetProcessHeap(), 0, patch->mem);
5721 HeapFree(GetProcessHeap(), 0, patch);
5723 return WINED3D_OK;
5726 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5727 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5729 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5730 FIXME("(%p) : Stub\n", This);
5731 return WINED3D_OK;
5734 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5736 int i;
5737 struct WineD3DRectPatch *patch;
5738 struct list *e;
5739 TRACE("(%p) Handle(%d)\n", This, Handle);
5741 i = PATCHMAP_HASHFUNC(Handle);
5742 LIST_FOR_EACH(e, &This->patches[i]) {
5743 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5744 if(patch->Handle == Handle) {
5745 TRACE("Deleting patch %p\n", patch);
5746 list_remove(&patch->entry);
5747 HeapFree(GetProcessHeap(), 0, patch->mem);
5748 HeapFree(GetProcessHeap(), 0, patch);
5749 return WINED3D_OK;
5753 /* TODO: Write a test for the return value */
5754 FIXME("Attempt to destroy nonexistent patch\n");
5755 return WINED3DERR_INVALIDCALL;
5758 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5759 HRESULT hr;
5760 IWineD3DSwapChain *swapchain;
5762 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5763 if (SUCCEEDED(hr)) {
5764 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5765 return swapchain;
5768 return NULL;
5771 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5774 if (!*fbo) {
5775 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5776 checkGLcall("glGenFramebuffersEXT()");
5778 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5779 checkGLcall("glBindFramebuffer()");
5782 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5783 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5784 IWineD3DBaseTextureImpl *texture_impl;
5785 GLenum texttarget, target;
5786 GLint old_binding;
5788 texttarget = surface_impl->glDescription.target;
5789 if(texttarget == GL_TEXTURE_2D) {
5790 target = GL_TEXTURE_2D;
5791 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5792 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5793 target = GL_TEXTURE_RECTANGLE_ARB;
5794 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5795 } else {
5796 target = GL_TEXTURE_CUBE_MAP_ARB;
5797 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5800 IWineD3DSurface_PreLoad(surface);
5802 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5803 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5804 glBindTexture(target, old_binding);
5806 /* Update base texture states array */
5807 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5808 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5809 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5810 if (texture_impl->baseTexture.bindCount) {
5811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5814 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5817 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5818 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5820 checkGLcall("attach_surface_fbo");
5823 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5825 IWineD3DSwapChain *swapchain;
5827 swapchain = get_swapchain(surface);
5828 if (swapchain) {
5829 GLenum buffer;
5831 TRACE("Surface %p is onscreen\n", surface);
5833 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5834 buffer = surface_get_gl_buffer(surface, swapchain);
5835 glDrawBuffer(buffer);
5836 checkGLcall("glDrawBuffer()");
5837 } else {
5838 TRACE("Surface %p is offscreen\n", surface);
5839 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5840 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5843 if (rect) {
5844 glEnable(GL_SCISSOR_TEST);
5845 if(!swapchain) {
5846 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5847 } else {
5848 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5849 rect->x2 - rect->x1, rect->y2 - rect->y1);
5851 checkGLcall("glScissor");
5852 } else {
5853 glDisable(GL_SCISSOR_TEST);
5855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5857 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5858 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5860 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5861 glClear(GL_COLOR_BUFFER_BIT);
5862 checkGLcall("glClear");
5864 if (This->render_offscreen) {
5865 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5866 } else {
5867 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5868 checkGLcall("glBindFramebuffer()");
5871 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5872 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5873 glDrawBuffer(GL_BACK);
5874 checkGLcall("glDrawBuffer()");
5878 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5879 unsigned int r, g, b, a;
5880 DWORD ret;
5882 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5883 destfmt == WINED3DFMT_R8G8B8)
5884 return color;
5886 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5888 a = (color & 0xff000000) >> 24;
5889 r = (color & 0x00ff0000) >> 16;
5890 g = (color & 0x0000ff00) >> 8;
5891 b = (color & 0x000000ff) >> 0;
5893 switch(destfmt)
5895 case WINED3DFMT_R5G6B5:
5896 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5897 r = (r * 32) / 256;
5898 g = (g * 64) / 256;
5899 b = (b * 32) / 256;
5900 ret = r << 11;
5901 ret |= g << 5;
5902 ret |= b;
5903 TRACE("Returning %08x\n", ret);
5904 return ret;
5906 case WINED3DFMT_X1R5G5B5:
5907 case WINED3DFMT_A1R5G5B5:
5908 a = (a * 2) / 256;
5909 r = (r * 32) / 256;
5910 g = (g * 32) / 256;
5911 b = (b * 32) / 256;
5912 ret = a << 15;
5913 ret |= r << 10;
5914 ret |= g << 5;
5915 ret |= b << 0;
5916 TRACE("Returning %08x\n", ret);
5917 return ret;
5919 case WINED3DFMT_A8:
5920 TRACE("Returning %08x\n", a);
5921 return a;
5923 case WINED3DFMT_X4R4G4B4:
5924 case WINED3DFMT_A4R4G4B4:
5925 a = (a * 16) / 256;
5926 r = (r * 16) / 256;
5927 g = (g * 16) / 256;
5928 b = (b * 16) / 256;
5929 ret = a << 12;
5930 ret |= r << 8;
5931 ret |= g << 4;
5932 ret |= b << 0;
5933 TRACE("Returning %08x\n", ret);
5934 return ret;
5936 case WINED3DFMT_R3G3B2:
5937 r = (r * 8) / 256;
5938 g = (g * 8) / 256;
5939 b = (b * 4) / 256;
5940 ret = r << 5;
5941 ret |= g << 2;
5942 ret |= b << 0;
5943 TRACE("Returning %08x\n", ret);
5944 return ret;
5946 case WINED3DFMT_X8B8G8R8:
5947 case WINED3DFMT_A8B8G8R8:
5948 ret = a << 24;
5949 ret |= b << 16;
5950 ret |= g << 8;
5951 ret |= r << 0;
5952 TRACE("Returning %08x\n", ret);
5953 return ret;
5955 case WINED3DFMT_A2R10G10B10:
5956 a = (a * 4) / 256;
5957 r = (r * 1024) / 256;
5958 g = (g * 1024) / 256;
5959 b = (b * 1024) / 256;
5960 ret = a << 30;
5961 ret |= r << 20;
5962 ret |= g << 10;
5963 ret |= b << 0;
5964 TRACE("Returning %08x\n", ret);
5965 return ret;
5967 case WINED3DFMT_A2B10G10R10:
5968 a = (a * 4) / 256;
5969 r = (r * 1024) / 256;
5970 g = (g * 1024) / 256;
5971 b = (b * 1024) / 256;
5972 ret = a << 30;
5973 ret |= b << 20;
5974 ret |= g << 10;
5975 ret |= r << 0;
5976 TRACE("Returning %08x\n", ret);
5977 return ret;
5979 default:
5980 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5981 return 0;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5987 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5988 WINEDDBLTFX BltFx;
5989 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5991 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5992 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5993 return WINED3DERR_INVALIDCALL;
5996 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5997 color_fill_fbo(iface, pSurface, pRect, color);
5998 return WINED3D_OK;
5999 } else {
6000 /* Just forward this to the DirectDraw blitting engine */
6001 memset(&BltFx, 0, sizeof(BltFx));
6002 BltFx.dwSize = sizeof(BltFx);
6003 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6004 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6008 /* rendertarget and deptth stencil functions */
6009 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6012 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6013 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6014 return WINED3DERR_INVALIDCALL;
6017 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6018 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6019 /* Note inc ref on returned surface */
6020 if(*ppRenderTarget != NULL)
6021 IWineD3DSurface_AddRef(*ppRenderTarget);
6022 return WINED3D_OK;
6025 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6027 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6028 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6029 IWineD3DSwapChainImpl *Swapchain;
6030 HRESULT hr;
6032 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6034 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6035 if(hr != WINED3D_OK) {
6036 ERR("Can't get the swapchain\n");
6037 return hr;
6040 /* Make sure to release the swapchain */
6041 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6043 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6044 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6045 return WINED3DERR_INVALIDCALL;
6047 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6048 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6049 return WINED3DERR_INVALIDCALL;
6052 if(Swapchain->frontBuffer != Front) {
6053 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6055 if(Swapchain->frontBuffer)
6056 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6057 Swapchain->frontBuffer = Front;
6059 if(Swapchain->frontBuffer) {
6060 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6064 if(Back && !Swapchain->backBuffer) {
6065 /* We need memory for the back buffer array - only one back buffer this way */
6066 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6067 if(!Swapchain->backBuffer) {
6068 ERR("Out of memory\n");
6069 return E_OUTOFMEMORY;
6073 if(Swapchain->backBuffer[0] != Back) {
6074 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6076 /* What to do about the context here in the case of multithreading? Not sure.
6077 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6079 ENTER_GL();
6080 if(!Swapchain->backBuffer[0]) {
6081 /* GL was told to draw to the front buffer at creation,
6082 * undo that
6084 glDrawBuffer(GL_BACK);
6085 checkGLcall("glDrawBuffer(GL_BACK)");
6086 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6087 Swapchain->presentParms.BackBufferCount = 1;
6088 } else if (!Back) {
6089 /* That makes problems - disable for now */
6090 /* glDrawBuffer(GL_FRONT); */
6091 checkGLcall("glDrawBuffer(GL_FRONT)");
6092 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6093 Swapchain->presentParms.BackBufferCount = 0;
6095 LEAVE_GL();
6097 if(Swapchain->backBuffer[0])
6098 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6099 Swapchain->backBuffer[0] = Back;
6101 if(Swapchain->backBuffer[0]) {
6102 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6103 } else {
6104 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6105 Swapchain->backBuffer = NULL;
6110 return WINED3D_OK;
6113 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6115 *ppZStencilSurface = This->stencilBufferTarget;
6116 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6118 if(*ppZStencilSurface != NULL) {
6119 /* Note inc ref on returned surface */
6120 IWineD3DSurface_AddRef(*ppZStencilSurface);
6121 return WINED3D_OK;
6122 } else {
6123 return WINED3DERR_NOTFOUND;
6127 /* TODO: Handle stencil attachments */
6128 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6130 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6132 TRACE("Set depth stencil to %p\n", depth_stencil);
6134 if (depth_stencil_impl) {
6135 if (depth_stencil_impl->current_renderbuffer) {
6136 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6137 checkGLcall("glFramebufferRenderbufferEXT()");
6138 } else {
6139 IWineD3DBaseTextureImpl *texture_impl;
6140 GLenum texttarget, target;
6141 GLint old_binding = 0;
6143 texttarget = depth_stencil_impl->glDescription.target;
6144 if(texttarget == GL_TEXTURE_2D) {
6145 target = GL_TEXTURE_2D;
6146 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6147 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6148 target = GL_TEXTURE_RECTANGLE_ARB;
6149 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6150 } else {
6151 target = GL_TEXTURE_CUBE_MAP_ARB;
6152 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6155 IWineD3DSurface_PreLoad(depth_stencil);
6157 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6158 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6159 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6160 glBindTexture(target, old_binding);
6162 /* Update base texture states array */
6163 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6164 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6165 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6166 if (texture_impl->baseTexture.bindCount) {
6167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6170 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6173 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6174 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6175 checkGLcall("glFramebufferTexture2DEXT()");
6177 } else {
6178 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6179 checkGLcall("glFramebufferTexture2DEXT()");
6183 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6185 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6187 TRACE("Set render target %u to %p\n", idx, render_target);
6189 if (rtimpl) {
6190 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6191 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6192 } else {
6193 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6194 checkGLcall("glFramebufferTexture2DEXT()");
6196 This->draw_buffers[idx] = GL_NONE;
6200 static void check_fbo_status(IWineD3DDevice *iface) {
6201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6202 GLenum status;
6204 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6205 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6206 TRACE("FBO complete\n");
6207 } else {
6208 IWineD3DSurfaceImpl *attachment;
6209 int i;
6210 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6212 /* Dump the FBO attachments */
6213 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6214 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6215 if (attachment) {
6216 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6217 attachment->pow2Width, attachment->pow2Height);
6220 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6221 if (attachment) {
6222 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6223 attachment->pow2Width, attachment->pow2Height);
6228 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6230 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6231 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6233 if (!ds_impl) return FALSE;
6235 if (ds_impl->current_renderbuffer) {
6236 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6237 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6240 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6241 rt_impl->pow2Height != ds_impl->pow2Height);
6244 void apply_fbo_state(IWineD3DDevice *iface) {
6245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6246 unsigned int i;
6248 if (This->render_offscreen) {
6249 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6251 /* Apply render targets */
6252 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6253 IWineD3DSurface *render_target = This->render_targets[i];
6254 if (This->fbo_color_attachments[i] != render_target) {
6255 set_render_target_fbo(iface, i, render_target);
6256 This->fbo_color_attachments[i] = render_target;
6260 /* Apply depth targets */
6261 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6262 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6263 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6265 if (This->stencilBufferTarget) {
6266 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6268 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6269 This->fbo_depth_attachment = This->stencilBufferTarget;
6272 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6273 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6274 checkGLcall("glDrawBuffers()");
6275 } else {
6276 glDrawBuffer(This->draw_buffers[0]);
6277 checkGLcall("glDrawBuffer()");
6279 } else {
6280 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6283 check_fbo_status(iface);
6286 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6287 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6289 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6290 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6291 GLenum gl_filter;
6293 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6294 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6295 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6296 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6298 switch (filter) {
6299 case WINED3DTEXF_LINEAR:
6300 gl_filter = GL_LINEAR;
6301 break;
6303 default:
6304 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6305 case WINED3DTEXF_NONE:
6306 case WINED3DTEXF_POINT:
6307 gl_filter = GL_NEAREST;
6308 break;
6311 /* Attach src surface to src fbo */
6312 src_swapchain = get_swapchain(src_surface);
6313 if (src_swapchain) {
6314 GLenum buffer;
6316 TRACE("Source surface %p is onscreen\n", src_surface);
6317 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6318 /* Make sure the drawable is up to date. In the offscreen case
6319 * attach_surface_fbo() implicitly takes care of this. */
6320 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6322 ENTER_GL();
6323 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6324 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6325 glReadBuffer(buffer);
6326 checkGLcall("glReadBuffer()");
6328 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6329 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6330 } else {
6331 TRACE("Source surface %p is offscreen\n", src_surface);
6332 ENTER_GL();
6333 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6334 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6335 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6336 checkGLcall("glReadBuffer()");
6338 LEAVE_GL();
6340 /* Attach dst surface to dst fbo */
6341 dst_swapchain = get_swapchain(dst_surface);
6342 if (dst_swapchain) {
6343 GLenum buffer;
6345 TRACE("Destination surface %p is onscreen\n", dst_surface);
6346 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6347 /* Make sure the drawable is up to date. In the offscreen case
6348 * attach_surface_fbo() implicitly takes care of this. */
6349 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6351 ENTER_GL();
6352 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6353 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6354 glDrawBuffer(buffer);
6355 checkGLcall("glDrawBuffer()");
6357 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6358 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6359 } else {
6360 TRACE("Destination surface %p is offscreen\n", dst_surface);
6362 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6363 if(!src_swapchain) {
6364 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6367 ENTER_GL();
6368 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6369 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6370 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6371 checkGLcall("glDrawBuffer()");
6373 glDisable(GL_SCISSOR_TEST);
6374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6376 if (flip) {
6377 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6378 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6379 checkGLcall("glBlitFramebuffer()");
6380 } else {
6381 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6382 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6383 checkGLcall("glBlitFramebuffer()");
6386 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6388 if (This->render_offscreen) {
6389 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6390 } else {
6391 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6392 checkGLcall("glBindFramebuffer()");
6395 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6396 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6397 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6398 glDrawBuffer(GL_BACK);
6399 checkGLcall("glDrawBuffer()");
6401 LEAVE_GL();
6404 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6406 WINED3DVIEWPORT viewport;
6408 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6410 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6411 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6412 This, RenderTargetIndex, GL_LIMITS(buffers));
6413 return WINED3DERR_INVALIDCALL;
6416 /* MSDN says that null disables the render target
6417 but a device must always be associated with a render target
6418 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6420 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6421 for more details
6423 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6424 FIXME("Trying to set render target 0 to NULL\n");
6425 return WINED3DERR_INVALIDCALL;
6427 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6428 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);
6429 return WINED3DERR_INVALIDCALL;
6432 /* If we are trying to set what we already have, don't bother */
6433 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6434 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6435 return WINED3D_OK;
6437 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6438 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6439 This->render_targets[RenderTargetIndex] = pRenderTarget;
6441 /* Render target 0 is special */
6442 if(RenderTargetIndex == 0) {
6443 /* Finally, reset the viewport as the MSDN states. */
6444 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6445 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6446 viewport.X = 0;
6447 viewport.Y = 0;
6448 viewport.MaxZ = 1.0f;
6449 viewport.MinZ = 0.0f;
6450 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6451 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6452 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6454 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6456 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6457 * ctx properly.
6458 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6459 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6461 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6463 return WINED3D_OK;
6466 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6468 HRESULT hr = WINED3D_OK;
6469 IWineD3DSurface *tmp;
6471 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6473 if (pNewZStencil == This->stencilBufferTarget) {
6474 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6475 } else {
6476 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6477 * depending on the renter target implementation being used.
6478 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6479 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6480 * stencil buffer and incure an extra memory overhead
6481 ******************************************************/
6483 tmp = This->stencilBufferTarget;
6484 This->stencilBufferTarget = pNewZStencil;
6485 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6486 /* should we be calling the parent or the wined3d surface? */
6487 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6488 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6489 hr = WINED3D_OK;
6491 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6492 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6499 return hr;
6502 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6503 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6505 /* TODO: the use of Impl is deprecated. */
6506 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6507 WINED3DLOCKED_RECT lockedRect;
6509 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6511 /* some basic validation checks */
6512 if(This->cursorTexture) {
6513 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6514 ENTER_GL();
6515 glDeleteTextures(1, &This->cursorTexture);
6516 LEAVE_GL();
6517 This->cursorTexture = 0;
6520 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6521 This->haveHardwareCursor = TRUE;
6522 else
6523 This->haveHardwareCursor = FALSE;
6525 if(pCursorBitmap) {
6526 WINED3DLOCKED_RECT rect;
6528 /* MSDN: Cursor must be A8R8G8B8 */
6529 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6530 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6531 return WINED3DERR_INVALIDCALL;
6534 /* MSDN: Cursor must be smaller than the display mode */
6535 if(pSur->currentDesc.Width > This->ddraw_width ||
6536 pSur->currentDesc.Height > This->ddraw_height) {
6537 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);
6538 return WINED3DERR_INVALIDCALL;
6541 if (!This->haveHardwareCursor) {
6542 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6544 /* Do not store the surface's pointer because the application may
6545 * release it after setting the cursor image. Windows doesn't
6546 * addref the set surface, so we can't do this either without
6547 * creating circular refcount dependencies. Copy out the gl texture
6548 * instead.
6550 This->cursorWidth = pSur->currentDesc.Width;
6551 This->cursorHeight = pSur->currentDesc.Height;
6552 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6554 const GlPixelFormatDesc *glDesc;
6555 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6556 char *mem, *bits = (char *)rect.pBits;
6557 GLint intfmt = glDesc->glInternal;
6558 GLint format = glDesc->glFormat;
6559 GLint type = glDesc->glType;
6560 INT height = This->cursorHeight;
6561 INT width = This->cursorWidth;
6562 INT bpp = tableEntry->bpp;
6563 INT i;
6565 /* Reformat the texture memory (pitch and width can be
6566 * different) */
6567 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6568 for(i = 0; i < height; i++)
6569 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6570 IWineD3DSurface_UnlockRect(pCursorBitmap);
6571 ENTER_GL();
6573 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6574 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6575 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6578 /* Make sure that a proper texture unit is selected */
6579 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6580 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6581 checkGLcall("glActiveTextureARB");
6583 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6584 /* Create a new cursor texture */
6585 glGenTextures(1, &This->cursorTexture);
6586 checkGLcall("glGenTextures");
6587 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6588 checkGLcall("glBindTexture");
6589 /* Copy the bitmap memory into the cursor texture */
6590 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6591 HeapFree(GetProcessHeap(), 0, mem);
6592 checkGLcall("glTexImage2D");
6594 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6595 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6596 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6599 LEAVE_GL();
6601 else
6603 FIXME("A cursor texture was not returned.\n");
6604 This->cursorTexture = 0;
6607 else
6609 /* Draw a hardware cursor */
6610 ICONINFO cursorInfo;
6611 HCURSOR cursor;
6612 /* Create and clear maskBits because it is not needed for
6613 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6614 * chunks. */
6615 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6616 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6617 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6618 WINED3DLOCK_NO_DIRTY_UPDATE |
6619 WINED3DLOCK_READONLY
6621 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6622 pSur->currentDesc.Height);
6624 cursorInfo.fIcon = FALSE;
6625 cursorInfo.xHotspot = XHotSpot;
6626 cursorInfo.yHotspot = YHotSpot;
6627 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6628 pSur->currentDesc.Height, 1,
6629 1, &maskBits);
6630 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6631 pSur->currentDesc.Height, 1,
6632 32, lockedRect.pBits);
6633 IWineD3DSurface_UnlockRect(pCursorBitmap);
6634 /* Create our cursor and clean up. */
6635 cursor = CreateIconIndirect(&cursorInfo);
6636 SetCursor(cursor);
6637 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6638 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6639 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6640 This->hardwareCursor = cursor;
6641 HeapFree(GetProcessHeap(), 0, maskBits);
6645 This->xHotSpot = XHotSpot;
6646 This->yHotSpot = YHotSpot;
6647 return WINED3D_OK;
6650 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6652 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6654 This->xScreenSpace = XScreenSpace;
6655 This->yScreenSpace = YScreenSpace;
6657 return;
6661 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6663 BOOL oldVisible = This->bCursorVisible;
6664 POINT pt;
6666 TRACE("(%p) : visible(%d)\n", This, bShow);
6669 * When ShowCursor is first called it should make the cursor appear at the OS's last
6670 * known cursor position. Because of this, some applications just repetitively call
6671 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6673 GetCursorPos(&pt);
6674 This->xScreenSpace = pt.x;
6675 This->yScreenSpace = pt.y;
6677 if (This->haveHardwareCursor) {
6678 This->bCursorVisible = bShow;
6679 if (bShow)
6680 SetCursor(This->hardwareCursor);
6681 else
6682 SetCursor(NULL);
6684 else
6686 if (This->cursorTexture)
6687 This->bCursorVisible = bShow;
6690 return oldVisible;
6693 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6695 IWineD3DResourceImpl *resource;
6696 TRACE("(%p) : state (%u)\n", This, This->state);
6698 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6699 switch (This->state) {
6700 case WINED3D_OK:
6701 return WINED3D_OK;
6702 case WINED3DERR_DEVICELOST:
6704 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6705 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6706 return WINED3DERR_DEVICENOTRESET;
6708 return WINED3DERR_DEVICELOST;
6710 case WINED3DERR_DRIVERINTERNALERROR:
6711 return WINED3DERR_DRIVERINTERNALERROR;
6714 /* Unknown state */
6715 return WINED3DERR_DRIVERINTERNALERROR;
6719 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6721 /** FIXME: Resource tracking needs to be done,
6722 * The closes we can do to this is set the priorities of all managed textures low
6723 * and then reset them.
6724 ***********************************************************/
6725 FIXME("(%p) : stub\n", This);
6726 return WINED3D_OK;
6729 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6730 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6732 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6733 if(surface->Flags & SFLAG_DIBSECTION) {
6734 /* Release the DC */
6735 SelectObject(surface->hDC, surface->dib.holdbitmap);
6736 DeleteDC(surface->hDC);
6737 /* Release the DIB section */
6738 DeleteObject(surface->dib.DIBsection);
6739 surface->dib.bitmap_data = NULL;
6740 surface->resource.allocatedMemory = NULL;
6741 surface->Flags &= ~SFLAG_DIBSECTION;
6743 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6744 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6745 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6746 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6747 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6748 } else {
6749 surface->pow2Width = surface->pow2Height = 1;
6750 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6751 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6753 if(surface->glDescription.textureName) {
6754 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6755 ENTER_GL();
6756 glDeleteTextures(1, &surface->glDescription.textureName);
6757 LEAVE_GL();
6758 surface->glDescription.textureName = 0;
6759 surface->Flags &= ~SFLAG_CLIENT;
6761 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6762 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6763 surface->Flags |= SFLAG_NONPOW2;
6764 } else {
6765 surface->Flags &= ~SFLAG_NONPOW2;
6767 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6768 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6771 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6772 TRACE("Unloading resource %p\n", resource);
6773 IWineD3DResource_UnLoad(resource);
6774 IWineD3DResource_Release(resource);
6775 return S_OK;
6778 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6780 IWineD3DSwapChainImpl *swapchain;
6781 HRESULT hr;
6782 BOOL DisplayModeChanged = FALSE;
6783 WINED3DDISPLAYMODE mode;
6784 TRACE("(%p)\n", This);
6786 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6787 if(FAILED(hr)) {
6788 ERR("Failed to get the first implicit swapchain\n");
6789 return hr;
6792 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6793 * on an existing gl context, so there's no real need for recreation.
6795 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6797 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6799 TRACE("New params:\n");
6800 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6801 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6802 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6803 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6804 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6805 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6806 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6807 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6808 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6809 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6810 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6811 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6812 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6814 /* No special treatment of these parameters. Just store them */
6815 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6816 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6817 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6818 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6820 /* What to do about these? */
6821 if(pPresentationParameters->BackBufferCount != 0 &&
6822 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6823 ERR("Cannot change the back buffer count yet\n");
6825 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6826 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6827 ERR("Cannot change the back buffer format yet\n");
6829 if(pPresentationParameters->hDeviceWindow != NULL &&
6830 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6831 ERR("Cannot change the device window yet\n");
6833 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6834 ERR("What do do about a changed auto depth stencil parameter?\n");
6837 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6839 if(pPresentationParameters->Windowed) {
6840 mode.Width = swapchain->orig_width;
6841 mode.Height = swapchain->orig_height;
6842 mode.RefreshRate = 0;
6843 mode.Format = swapchain->presentParms.BackBufferFormat;
6844 } else {
6845 mode.Width = pPresentationParameters->BackBufferWidth;
6846 mode.Height = pPresentationParameters->BackBufferHeight;
6847 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6848 mode.Format = swapchain->presentParms.BackBufferFormat;
6851 /* Should Width == 800 && Height == 0 set 800x600? */
6852 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6853 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6854 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6856 WINED3DVIEWPORT vp;
6857 int i;
6859 vp.X = 0;
6860 vp.Y = 0;
6861 vp.Width = pPresentationParameters->BackBufferWidth;
6862 vp.Height = pPresentationParameters->BackBufferHeight;
6863 vp.MinZ = 0;
6864 vp.MaxZ = 1;
6866 if(!pPresentationParameters->Windowed) {
6867 DisplayModeChanged = TRUE;
6869 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6870 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6872 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6873 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6874 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6877 /* Now set the new viewport */
6878 IWineD3DDevice_SetViewport(iface, &vp);
6881 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6882 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6883 DisplayModeChanged) {
6885 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6886 if(!pPresentationParameters->Windowed) {
6887 IWineD3DDevice_SetFullscreen(iface, TRUE);
6890 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6892 /* Switching out of fullscreen mode? First set the original res, then change the window */
6893 if(pPresentationParameters->Windowed) {
6894 IWineD3DDevice_SetFullscreen(iface, FALSE);
6896 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6899 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6900 return WINED3D_OK;
6903 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6905 /** FIXME: always true at the moment **/
6906 if(!bEnableDialogs) {
6907 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6909 return WINED3D_OK;
6913 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6915 TRACE("(%p) : pParameters %p\n", This, pParameters);
6917 *pParameters = This->createParms;
6918 return WINED3D_OK;
6921 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6922 IWineD3DSwapChain *swapchain;
6923 HRESULT hrc = WINED3D_OK;
6925 TRACE("Relaying to swapchain\n");
6927 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6928 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6929 IWineD3DSwapChain_Release(swapchain);
6931 return;
6934 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6935 IWineD3DSwapChain *swapchain;
6936 HRESULT hrc = WINED3D_OK;
6938 TRACE("Relaying to swapchain\n");
6940 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6941 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6942 IWineD3DSwapChain_Release(swapchain);
6944 return;
6948 /** ********************************************************
6949 * Notification functions
6950 ** ********************************************************/
6951 /** This function must be called in the release of a resource when ref == 0,
6952 * the contents of resource must still be correct,
6953 * any handels to other resource held by the caller must be closed
6954 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6955 *****************************************************/
6956 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6959 TRACE("(%p) : Adding Resource %p\n", This, resource);
6960 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6963 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6966 TRACE("(%p) : Removing resource %p\n", This, resource);
6968 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6972 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6974 int counter;
6976 TRACE("(%p) : resource %p\n", This, resource);
6977 switch(IWineD3DResource_GetType(resource)){
6978 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6979 case WINED3DRTYPE_SURFACE: {
6980 unsigned int i;
6982 /* Cleanup any FBO attachments if d3d is enabled */
6983 if(This->d3d_initialized) {
6984 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6985 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6987 TRACE("Last active render target destroyed\n");
6988 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6989 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6990 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6991 * and the lastActiveRenderTarget member shouldn't matter
6993 if(swapchain) {
6994 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6995 TRACE("Activating primary back buffer\n");
6996 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6997 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6998 /* Single buffering environment */
6999 TRACE("Activating primary front buffer\n");
7000 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7001 } else {
7002 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7003 /* Implicit render target destroyed, that means the device is being destroyed
7004 * whatever we set here, it shouldn't matter
7006 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7008 } else {
7009 /* May happen during ddraw uninitialization */
7010 TRACE("Render target set, but swapchain does not exist!\n");
7011 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7015 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7016 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7017 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7018 set_render_target_fbo(iface, i, NULL);
7019 This->fbo_color_attachments[i] = NULL;
7022 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7023 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7024 set_depth_stencil_fbo(iface, NULL);
7025 This->fbo_depth_attachment = NULL;
7029 break;
7031 case WINED3DRTYPE_TEXTURE:
7032 case WINED3DRTYPE_CUBETEXTURE:
7033 case WINED3DRTYPE_VOLUMETEXTURE:
7034 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7035 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7036 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7037 This->stateBlock->textures[counter] = NULL;
7039 if (This->updateStateBlock != This->stateBlock ){
7040 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7041 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7042 This->updateStateBlock->textures[counter] = NULL;
7046 break;
7047 case WINED3DRTYPE_VOLUME:
7048 /* TODO: nothing really? */
7049 break;
7050 case WINED3DRTYPE_VERTEXBUFFER:
7051 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7053 int streamNumber;
7054 TRACE("Cleaning up stream pointers\n");
7056 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7057 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7058 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7060 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7061 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7062 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7063 This->updateStateBlock->streamSource[streamNumber] = 0;
7064 /* Set changed flag? */
7067 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) */
7068 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7069 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7070 This->stateBlock->streamSource[streamNumber] = 0;
7073 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7074 else { /* This shouldn't happen */
7075 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7077 #endif
7081 break;
7082 case WINED3DRTYPE_INDEXBUFFER:
7083 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7084 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7085 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7086 This->updateStateBlock->pIndexData = NULL;
7089 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7090 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7091 This->stateBlock->pIndexData = NULL;
7095 break;
7096 default:
7097 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7098 break;
7102 /* Remove the resoruce from the resourceStore */
7103 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7105 TRACE("Resource released\n");
7109 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7111 IWineD3DResourceImpl *resource, *cursor;
7112 HRESULT ret;
7113 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7115 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7116 TRACE("enumerating resource %p\n", resource);
7117 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7118 ret = pCallback((IWineD3DResource *) resource, pData);
7119 if(ret == S_FALSE) {
7120 TRACE("Canceling enumeration\n");
7121 break;
7124 return WINED3D_OK;
7127 /**********************************************************
7128 * IWineD3DDevice VTbl follows
7129 **********************************************************/
7131 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7133 /*** IUnknown methods ***/
7134 IWineD3DDeviceImpl_QueryInterface,
7135 IWineD3DDeviceImpl_AddRef,
7136 IWineD3DDeviceImpl_Release,
7137 /*** IWineD3DDevice methods ***/
7138 IWineD3DDeviceImpl_GetParent,
7139 /*** Creation methods**/
7140 IWineD3DDeviceImpl_CreateVertexBuffer,
7141 IWineD3DDeviceImpl_CreateIndexBuffer,
7142 IWineD3DDeviceImpl_CreateStateBlock,
7143 IWineD3DDeviceImpl_CreateSurface,
7144 IWineD3DDeviceImpl_CreateTexture,
7145 IWineD3DDeviceImpl_CreateVolumeTexture,
7146 IWineD3DDeviceImpl_CreateVolume,
7147 IWineD3DDeviceImpl_CreateCubeTexture,
7148 IWineD3DDeviceImpl_CreateQuery,
7149 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7150 IWineD3DDeviceImpl_CreateVertexDeclaration,
7151 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7152 IWineD3DDeviceImpl_CreateVertexShader,
7153 IWineD3DDeviceImpl_CreatePixelShader,
7154 IWineD3DDeviceImpl_CreatePalette,
7155 /*** Odd functions **/
7156 IWineD3DDeviceImpl_Init3D,
7157 IWineD3DDeviceImpl_Uninit3D,
7158 IWineD3DDeviceImpl_SetFullscreen,
7159 IWineD3DDeviceImpl_SetMultithreaded,
7160 IWineD3DDeviceImpl_EvictManagedResources,
7161 IWineD3DDeviceImpl_GetAvailableTextureMem,
7162 IWineD3DDeviceImpl_GetBackBuffer,
7163 IWineD3DDeviceImpl_GetCreationParameters,
7164 IWineD3DDeviceImpl_GetDeviceCaps,
7165 IWineD3DDeviceImpl_GetDirect3D,
7166 IWineD3DDeviceImpl_GetDisplayMode,
7167 IWineD3DDeviceImpl_SetDisplayMode,
7168 IWineD3DDeviceImpl_GetHWND,
7169 IWineD3DDeviceImpl_SetHWND,
7170 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7171 IWineD3DDeviceImpl_GetRasterStatus,
7172 IWineD3DDeviceImpl_GetSwapChain,
7173 IWineD3DDeviceImpl_Reset,
7174 IWineD3DDeviceImpl_SetDialogBoxMode,
7175 IWineD3DDeviceImpl_SetCursorProperties,
7176 IWineD3DDeviceImpl_SetCursorPosition,
7177 IWineD3DDeviceImpl_ShowCursor,
7178 IWineD3DDeviceImpl_TestCooperativeLevel,
7179 /*** Getters and setters **/
7180 IWineD3DDeviceImpl_SetClipPlane,
7181 IWineD3DDeviceImpl_GetClipPlane,
7182 IWineD3DDeviceImpl_SetClipStatus,
7183 IWineD3DDeviceImpl_GetClipStatus,
7184 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7185 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7186 IWineD3DDeviceImpl_SetDepthStencilSurface,
7187 IWineD3DDeviceImpl_GetDepthStencilSurface,
7188 IWineD3DDeviceImpl_SetFVF,
7189 IWineD3DDeviceImpl_GetFVF,
7190 IWineD3DDeviceImpl_SetGammaRamp,
7191 IWineD3DDeviceImpl_GetGammaRamp,
7192 IWineD3DDeviceImpl_SetIndices,
7193 IWineD3DDeviceImpl_GetIndices,
7194 IWineD3DDeviceImpl_SetBaseVertexIndex,
7195 IWineD3DDeviceImpl_GetBaseVertexIndex,
7196 IWineD3DDeviceImpl_SetLight,
7197 IWineD3DDeviceImpl_GetLight,
7198 IWineD3DDeviceImpl_SetLightEnable,
7199 IWineD3DDeviceImpl_GetLightEnable,
7200 IWineD3DDeviceImpl_SetMaterial,
7201 IWineD3DDeviceImpl_GetMaterial,
7202 IWineD3DDeviceImpl_SetNPatchMode,
7203 IWineD3DDeviceImpl_GetNPatchMode,
7204 IWineD3DDeviceImpl_SetPaletteEntries,
7205 IWineD3DDeviceImpl_GetPaletteEntries,
7206 IWineD3DDeviceImpl_SetPixelShader,
7207 IWineD3DDeviceImpl_GetPixelShader,
7208 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7209 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7210 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7211 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7212 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7213 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7214 IWineD3DDeviceImpl_SetRenderState,
7215 IWineD3DDeviceImpl_GetRenderState,
7216 IWineD3DDeviceImpl_SetRenderTarget,
7217 IWineD3DDeviceImpl_GetRenderTarget,
7218 IWineD3DDeviceImpl_SetFrontBackBuffers,
7219 IWineD3DDeviceImpl_SetSamplerState,
7220 IWineD3DDeviceImpl_GetSamplerState,
7221 IWineD3DDeviceImpl_SetScissorRect,
7222 IWineD3DDeviceImpl_GetScissorRect,
7223 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7224 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7225 IWineD3DDeviceImpl_SetStreamSource,
7226 IWineD3DDeviceImpl_GetStreamSource,
7227 IWineD3DDeviceImpl_SetStreamSourceFreq,
7228 IWineD3DDeviceImpl_GetStreamSourceFreq,
7229 IWineD3DDeviceImpl_SetTexture,
7230 IWineD3DDeviceImpl_GetTexture,
7231 IWineD3DDeviceImpl_SetTextureStageState,
7232 IWineD3DDeviceImpl_GetTextureStageState,
7233 IWineD3DDeviceImpl_SetTransform,
7234 IWineD3DDeviceImpl_GetTransform,
7235 IWineD3DDeviceImpl_SetVertexDeclaration,
7236 IWineD3DDeviceImpl_GetVertexDeclaration,
7237 IWineD3DDeviceImpl_SetVertexShader,
7238 IWineD3DDeviceImpl_GetVertexShader,
7239 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7240 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7241 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7242 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7243 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7244 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7245 IWineD3DDeviceImpl_SetViewport,
7246 IWineD3DDeviceImpl_GetViewport,
7247 IWineD3DDeviceImpl_MultiplyTransform,
7248 IWineD3DDeviceImpl_ValidateDevice,
7249 IWineD3DDeviceImpl_ProcessVertices,
7250 /*** State block ***/
7251 IWineD3DDeviceImpl_BeginStateBlock,
7252 IWineD3DDeviceImpl_EndStateBlock,
7253 /*** Scene management ***/
7254 IWineD3DDeviceImpl_BeginScene,
7255 IWineD3DDeviceImpl_EndScene,
7256 IWineD3DDeviceImpl_Present,
7257 IWineD3DDeviceImpl_Clear,
7258 /*** Drawing ***/
7259 IWineD3DDeviceImpl_DrawPrimitive,
7260 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7261 IWineD3DDeviceImpl_DrawPrimitiveUP,
7262 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7263 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7264 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7265 IWineD3DDeviceImpl_DrawRectPatch,
7266 IWineD3DDeviceImpl_DrawTriPatch,
7267 IWineD3DDeviceImpl_DeletePatch,
7268 IWineD3DDeviceImpl_ColorFill,
7269 IWineD3DDeviceImpl_UpdateTexture,
7270 IWineD3DDeviceImpl_UpdateSurface,
7271 IWineD3DDeviceImpl_GetFrontBufferData,
7272 /*** object tracking ***/
7273 IWineD3DDeviceImpl_ResourceReleased,
7274 IWineD3DDeviceImpl_EnumResources
7278 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7279 WINED3DRS_ALPHABLENDENABLE ,
7280 WINED3DRS_ALPHAFUNC ,
7281 WINED3DRS_ALPHAREF ,
7282 WINED3DRS_ALPHATESTENABLE ,
7283 WINED3DRS_BLENDOP ,
7284 WINED3DRS_COLORWRITEENABLE ,
7285 WINED3DRS_DESTBLEND ,
7286 WINED3DRS_DITHERENABLE ,
7287 WINED3DRS_FILLMODE ,
7288 WINED3DRS_FOGDENSITY ,
7289 WINED3DRS_FOGEND ,
7290 WINED3DRS_FOGSTART ,
7291 WINED3DRS_LASTPIXEL ,
7292 WINED3DRS_SHADEMODE ,
7293 WINED3DRS_SRCBLEND ,
7294 WINED3DRS_STENCILENABLE ,
7295 WINED3DRS_STENCILFAIL ,
7296 WINED3DRS_STENCILFUNC ,
7297 WINED3DRS_STENCILMASK ,
7298 WINED3DRS_STENCILPASS ,
7299 WINED3DRS_STENCILREF ,
7300 WINED3DRS_STENCILWRITEMASK ,
7301 WINED3DRS_STENCILZFAIL ,
7302 WINED3DRS_TEXTUREFACTOR ,
7303 WINED3DRS_WRAP0 ,
7304 WINED3DRS_WRAP1 ,
7305 WINED3DRS_WRAP2 ,
7306 WINED3DRS_WRAP3 ,
7307 WINED3DRS_WRAP4 ,
7308 WINED3DRS_WRAP5 ,
7309 WINED3DRS_WRAP6 ,
7310 WINED3DRS_WRAP7 ,
7311 WINED3DRS_ZENABLE ,
7312 WINED3DRS_ZFUNC ,
7313 WINED3DRS_ZWRITEENABLE
7316 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7317 WINED3DTSS_ADDRESSW ,
7318 WINED3DTSS_ALPHAARG0 ,
7319 WINED3DTSS_ALPHAARG1 ,
7320 WINED3DTSS_ALPHAARG2 ,
7321 WINED3DTSS_ALPHAOP ,
7322 WINED3DTSS_BUMPENVLOFFSET ,
7323 WINED3DTSS_BUMPENVLSCALE ,
7324 WINED3DTSS_BUMPENVMAT00 ,
7325 WINED3DTSS_BUMPENVMAT01 ,
7326 WINED3DTSS_BUMPENVMAT10 ,
7327 WINED3DTSS_BUMPENVMAT11 ,
7328 WINED3DTSS_COLORARG0 ,
7329 WINED3DTSS_COLORARG1 ,
7330 WINED3DTSS_COLORARG2 ,
7331 WINED3DTSS_COLOROP ,
7332 WINED3DTSS_RESULTARG ,
7333 WINED3DTSS_TEXCOORDINDEX ,
7334 WINED3DTSS_TEXTURETRANSFORMFLAGS
7337 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7338 WINED3DSAMP_ADDRESSU ,
7339 WINED3DSAMP_ADDRESSV ,
7340 WINED3DSAMP_ADDRESSW ,
7341 WINED3DSAMP_BORDERCOLOR ,
7342 WINED3DSAMP_MAGFILTER ,
7343 WINED3DSAMP_MINFILTER ,
7344 WINED3DSAMP_MIPFILTER ,
7345 WINED3DSAMP_MIPMAPLODBIAS ,
7346 WINED3DSAMP_MAXMIPLEVEL ,
7347 WINED3DSAMP_MAXANISOTROPY ,
7348 WINED3DSAMP_SRGBTEXTURE ,
7349 WINED3DSAMP_ELEMENTINDEX
7352 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7353 WINED3DRS_AMBIENT ,
7354 WINED3DRS_AMBIENTMATERIALSOURCE ,
7355 WINED3DRS_CLIPPING ,
7356 WINED3DRS_CLIPPLANEENABLE ,
7357 WINED3DRS_COLORVERTEX ,
7358 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7359 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7360 WINED3DRS_FOGDENSITY ,
7361 WINED3DRS_FOGEND ,
7362 WINED3DRS_FOGSTART ,
7363 WINED3DRS_FOGTABLEMODE ,
7364 WINED3DRS_FOGVERTEXMODE ,
7365 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7366 WINED3DRS_LIGHTING ,
7367 WINED3DRS_LOCALVIEWER ,
7368 WINED3DRS_MULTISAMPLEANTIALIAS ,
7369 WINED3DRS_MULTISAMPLEMASK ,
7370 WINED3DRS_NORMALIZENORMALS ,
7371 WINED3DRS_PATCHEDGESTYLE ,
7372 WINED3DRS_POINTSCALE_A ,
7373 WINED3DRS_POINTSCALE_B ,
7374 WINED3DRS_POINTSCALE_C ,
7375 WINED3DRS_POINTSCALEENABLE ,
7376 WINED3DRS_POINTSIZE ,
7377 WINED3DRS_POINTSIZE_MAX ,
7378 WINED3DRS_POINTSIZE_MIN ,
7379 WINED3DRS_POINTSPRITEENABLE ,
7380 WINED3DRS_RANGEFOGENABLE ,
7381 WINED3DRS_SPECULARMATERIALSOURCE ,
7382 WINED3DRS_TWEENFACTOR ,
7383 WINED3DRS_VERTEXBLEND ,
7384 WINED3DRS_CULLMODE ,
7385 WINED3DRS_FOGCOLOR
7388 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7389 WINED3DTSS_TEXCOORDINDEX ,
7390 WINED3DTSS_TEXTURETRANSFORMFLAGS
7393 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7394 WINED3DSAMP_DMAPOFFSET
7397 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7398 DWORD rep = StateTable[state].representative;
7399 DWORD idx;
7400 BYTE shift;
7401 UINT i;
7402 WineD3DContext *context;
7404 if(!rep) return;
7405 for(i = 0; i < This->numContexts; i++) {
7406 context = This->contexts[i];
7407 if(isStateDirty(context, rep)) continue;
7409 context->dirtyArray[context->numDirtyEntries++] = rep;
7410 idx = rep >> 5;
7411 shift = rep & 0x1f;
7412 context->isStateDirty[idx] |= (1 << shift);
7416 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7417 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7418 /* The drawable size of a pbuffer render target is the current pbuffer size
7420 *width = dev->pbufferWidth;
7421 *height = dev->pbufferHeight;
7424 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7425 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7427 *width = This->pow2Width;
7428 *height = This->pow2Height;
7431 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7432 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7433 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7434 * current context's drawable, which is the size of the back buffer of the swapchain
7435 * the active context belongs to. The back buffer of the swapchain is stored as the
7436 * surface the context belongs to.
7438 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7439 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;