winealsa.drv: Don't return garbage if can't find active channel.
[wine/multimedia.git] / dlls / wined3d / device.c
blobb30333def72ce8913083b5c1f2eaf2821d394d8b
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;
1887 return WINED3D_OK;
1890 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1892 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1893 HRESULT hr = WINED3D_OK;
1895 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1896 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1897 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1898 if (WINED3D_OK == hr) {
1899 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1900 } else {
1901 WARN("(%p) : Failed to create pixel shader\n", This);
1904 return hr;
1907 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1909 IWineD3DPaletteImpl *object;
1910 HRESULT hr;
1911 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1913 /* Create the new object */
1914 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1915 if(!object) {
1916 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1917 return E_OUTOFMEMORY;
1920 object->lpVtbl = &IWineD3DPalette_Vtbl;
1921 object->ref = 1;
1922 object->Flags = Flags;
1923 object->parent = Parent;
1924 object->wineD3DDevice = This;
1925 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1927 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1929 if(!object->hpal) {
1930 HeapFree( GetProcessHeap(), 0, object);
1931 return E_OUTOFMEMORY;
1934 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1935 if(FAILED(hr)) {
1936 IWineD3DPalette_Release((IWineD3DPalette *) object);
1937 return hr;
1940 *Palette = (IWineD3DPalette *) object;
1942 return WINED3D_OK;
1945 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1946 HBITMAP hbm;
1947 BITMAP bm;
1948 HRESULT hr;
1949 HDC dcb = NULL, dcs = NULL;
1950 WINEDDCOLORKEY colorkey;
1952 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1953 if(hbm)
1955 GetObjectA(hbm, sizeof(BITMAP), &bm);
1956 dcb = CreateCompatibleDC(NULL);
1957 if(!dcb) goto out;
1958 SelectObject(dcb, hbm);
1960 else
1962 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1963 * couldn't be loaded
1965 memset(&bm, 0, sizeof(bm));
1966 bm.bmWidth = 32;
1967 bm.bmHeight = 32;
1970 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1971 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1972 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1973 if(FAILED(hr)) {
1974 ERR("Wine logo requested, but failed to create surface\n");
1975 goto out;
1978 if(dcb) {
1979 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1980 if(FAILED(hr)) goto out;
1981 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1982 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1984 colorkey.dwColorSpaceLowValue = 0;
1985 colorkey.dwColorSpaceHighValue = 0;
1986 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1987 } else {
1988 /* Fill the surface with a white color to show that wined3d is there */
1989 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1992 out:
1993 if(dcb) {
1994 DeleteDC(dcb);
1996 if(hbm) {
1997 DeleteObject(hbm);
1999 return;
2002 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2004 IWineD3DSwapChainImpl *swapchain;
2005 HRESULT hr;
2006 DWORD state;
2008 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2009 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2011 /* TODO: Test if OpenGL is compiled in and loaded */
2013 TRACE("(%p) : Creating stateblock\n", This);
2014 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2015 hr = IWineD3DDevice_CreateStateBlock(iface,
2016 WINED3DSBT_INIT,
2017 (IWineD3DStateBlock **)&This->stateBlock,
2018 NULL);
2019 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2020 WARN("Failed to create stateblock\n");
2021 goto err_out;
2023 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2024 This->updateStateBlock = This->stateBlock;
2025 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2027 hr = allocate_shader_constants(This->updateStateBlock);
2028 if (WINED3D_OK != hr) {
2029 goto err_out;
2032 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2033 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2034 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2036 /* Initialize the texture unit mapping to a 1:1 mapping */
2037 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2038 if (state < GL_LIMITS(fragment_samplers)) {
2039 This->texUnitMap[state] = state;
2040 This->rev_tex_unit_map[state] = state;
2041 } else {
2042 This->texUnitMap[state] = -1;
2043 This->rev_tex_unit_map[state] = -1;
2047 /* Setup the implicit swapchain */
2048 TRACE("Creating implicit swapchain\n");
2049 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2050 if (FAILED(hr) || !swapchain) {
2051 WARN("Failed to create implicit swapchain\n");
2052 goto err_out;
2055 This->NumberOfSwapChains = 1;
2056 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2057 if(!This->swapchains) {
2058 ERR("Out of memory!\n");
2059 goto err_out;
2061 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2063 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2064 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2065 This->render_targets[0] = swapchain->backBuffer[0];
2066 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2068 else {
2069 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2070 This->render_targets[0] = swapchain->frontBuffer;
2071 This->lastActiveRenderTarget = swapchain->frontBuffer;
2073 IWineD3DSurface_AddRef(This->render_targets[0]);
2074 This->activeContext = swapchain->context[0];
2075 This->lastThread = GetCurrentThreadId();
2077 /* Depth Stencil support */
2078 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2079 if (NULL != This->stencilBufferTarget) {
2080 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2083 /* Set up some starting GL setup */
2084 ENTER_GL();
2086 /* Setup all the devices defaults */
2087 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2088 #if 0
2089 IWineD3DImpl_CheckGraphicsMemory();
2090 #endif
2092 { /* Set a default viewport */
2093 WINED3DVIEWPORT vp;
2094 vp.X = 0;
2095 vp.Y = 0;
2096 vp.Width = pPresentationParameters->BackBufferWidth;
2097 vp.Height = pPresentationParameters->BackBufferHeight;
2098 vp.MinZ = 0.0f;
2099 vp.MaxZ = 1.0f;
2100 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2103 /* Initialize the current view state */
2104 This->view_ident = 1;
2105 This->contexts[0]->last_was_rhw = 0;
2106 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2107 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2109 switch(wined3d_settings.offscreen_rendering_mode) {
2110 case ORM_FBO:
2111 case ORM_PBUFFER:
2112 This->offscreenBuffer = GL_BACK;
2113 break;
2115 case ORM_BACKBUFFER:
2117 if(GL_LIMITS(aux_buffers) > 0) {
2118 TRACE("Using auxilliary buffer for offscreen rendering\n");
2119 This->offscreenBuffer = GL_AUX0;
2120 } else {
2121 TRACE("Using back buffer for offscreen rendering\n");
2122 This->offscreenBuffer = GL_BACK;
2127 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2128 LEAVE_GL();
2130 /* Clear the screen */
2131 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2132 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2133 0x00, 1.0, 0);
2135 This->d3d_initialized = TRUE;
2137 if(wined3d_settings.logo) {
2138 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2140 return WINED3D_OK;
2142 err_out:
2143 HeapFree(GetProcessHeap(), 0, This->render_targets);
2144 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2145 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2146 HeapFree(GetProcessHeap(), 0, This->swapchains);
2147 This->NumberOfSwapChains = 0;
2148 if(swapchain) {
2149 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2151 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2152 if(This->stateBlock) {
2153 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2154 This->stateBlock = NULL;
2156 return hr;
2159 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2161 int sampler;
2162 UINT i;
2163 TRACE("(%p)\n", This);
2165 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2167 /* I don't think that the interface guarants that the device is destroyed from the same thread
2168 * it was created. Thus make sure a context is active for the glDelete* calls
2170 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2172 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2174 TRACE("Deleting high order patches\n");
2175 for(i = 0; i < PATCHMAP_SIZE; i++) {
2176 struct list *e1, *e2;
2177 struct WineD3DRectPatch *patch;
2178 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2179 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2180 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2184 /* Delete the palette conversion shader if it is around */
2185 if(This->paletteConversionShader) {
2186 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2187 This->paletteConversionShader = 0;
2190 /* Delete the pbuffer context if there is any */
2191 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2193 /* Delete the mouse cursor texture */
2194 if(This->cursorTexture) {
2195 ENTER_GL();
2196 glDeleteTextures(1, &This->cursorTexture);
2197 LEAVE_GL();
2198 This->cursorTexture = 0;
2201 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2202 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2204 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2205 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2208 /* Release the update stateblock */
2209 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2210 if(This->updateStateBlock != This->stateBlock)
2211 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2213 This->updateStateBlock = NULL;
2215 { /* because were not doing proper internal refcounts releasing the primary state block
2216 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2217 to set this->stateBlock = NULL; first */
2218 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2219 This->stateBlock = NULL;
2221 /* Release the stateblock */
2222 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2223 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2227 /* Release the buffers (with sanity checks)*/
2228 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2229 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2230 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2231 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2233 This->stencilBufferTarget = NULL;
2235 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2236 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2237 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2239 TRACE("Setting rendertarget to NULL\n");
2240 This->render_targets[0] = NULL;
2242 if (This->auto_depth_stencil_buffer) {
2243 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2244 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2246 This->auto_depth_stencil_buffer = NULL;
2249 for(i=0; i < This->NumberOfSwapChains; i++) {
2250 TRACE("Releasing the implicit swapchain %d\n", i);
2251 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2252 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2256 HeapFree(GetProcessHeap(), 0, This->swapchains);
2257 This->swapchains = NULL;
2258 This->NumberOfSwapChains = 0;
2260 HeapFree(GetProcessHeap(), 0, This->render_targets);
2261 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2262 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2263 This->render_targets = NULL;
2264 This->fbo_color_attachments = NULL;
2265 This->draw_buffers = NULL;
2268 This->d3d_initialized = FALSE;
2269 return WINED3D_OK;
2272 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2274 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2276 /* Setup the window for fullscreen mode */
2277 if(fullscreen && !This->ddraw_fullscreen) {
2278 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2279 } else if(!fullscreen && This->ddraw_fullscreen) {
2280 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2283 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2284 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2285 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2286 * separately.
2288 This->ddraw_fullscreen = fullscreen;
2291 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2292 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2293 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2295 * There is no way to deactivate thread safety once it is enabled.
2297 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2300 /*For now just store the flag(needed in case of ddraw) */
2301 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2303 return;
2306 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2307 DEVMODEW devmode;
2308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2309 LONG ret;
2310 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2311 RECT clip_rc;
2313 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2315 /* Resize the screen even without a window:
2316 * The app could have unset it with SetCooperativeLevel, but not called
2317 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2318 * but we don't have any hwnd
2321 memset(&devmode, 0, sizeof(devmode));
2322 devmode.dmSize = sizeof(devmode);
2323 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2324 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2325 devmode.dmPelsWidth = pMode->Width;
2326 devmode.dmPelsHeight = pMode->Height;
2328 devmode.dmDisplayFrequency = pMode->RefreshRate;
2329 if (pMode->RefreshRate != 0) {
2330 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2333 /* Only change the mode if necessary */
2334 if( (This->ddraw_width == pMode->Width) &&
2335 (This->ddraw_height == pMode->Height) &&
2336 (This->ddraw_format == pMode->Format) &&
2337 (pMode->RefreshRate == 0) ) {
2338 return WINED3D_OK;
2341 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2342 if (ret != DISP_CHANGE_SUCCESSFUL) {
2343 if(devmode.dmDisplayFrequency != 0) {
2344 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2345 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2346 devmode.dmDisplayFrequency = 0;
2347 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2349 if(ret != DISP_CHANGE_SUCCESSFUL) {
2350 return WINED3DERR_NOTAVAILABLE;
2354 /* Store the new values */
2355 This->ddraw_width = pMode->Width;
2356 This->ddraw_height = pMode->Height;
2357 This->ddraw_format = pMode->Format;
2359 /* Only do this with a window of course */
2360 if(This->ddraw_window)
2361 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2363 /* And finally clip mouse to our screen */
2364 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2365 ClipCursor(&clip_rc);
2367 return WINED3D_OK;
2370 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2372 *ppD3D= This->wineD3D;
2373 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2374 IWineD3D_AddRef(*ppD3D);
2375 return WINED3D_OK;
2378 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2381 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2382 (This->adapter->TextureRam/(1024*1024)),
2383 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2384 /* return simulated texture memory left */
2385 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2390 /*****
2391 * Get / Set FVF
2392 *****/
2393 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2396 /* Update the current state block */
2397 This->updateStateBlock->changed.fvf = TRUE;
2399 if(This->updateStateBlock->fvf == fvf) {
2400 TRACE("Application is setting the old fvf over, nothing to do\n");
2401 return WINED3D_OK;
2404 This->updateStateBlock->fvf = fvf;
2405 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2407 return WINED3D_OK;
2411 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2413 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2414 *pfvf = This->stateBlock->fvf;
2415 return WINED3D_OK;
2418 /*****
2419 * Get / Set Stream Source
2420 *****/
2421 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2422 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2423 IWineD3DVertexBuffer *oldSrc;
2425 if (StreamNumber >= MAX_STREAMS) {
2426 WARN("Stream out of range %d\n", StreamNumber);
2427 return WINED3DERR_INVALIDCALL;
2428 } else if(OffsetInBytes & 0x3) {
2429 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2430 return WINED3DERR_INVALIDCALL;
2433 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2434 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2436 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2438 if(oldSrc == pStreamData &&
2439 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2440 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2441 TRACE("Application is setting the old values over, nothing to do\n");
2442 return WINED3D_OK;
2445 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2446 if (pStreamData) {
2447 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2448 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2451 /* Handle recording of state blocks */
2452 if (This->isRecordingState) {
2453 TRACE("Recording... not performing anything\n");
2454 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2455 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2456 return WINED3D_OK;
2459 /* Need to do a getParent and pass the reffs up */
2460 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2461 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2462 so for now, just count internally */
2463 if (pStreamData != NULL) {
2464 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2465 InterlockedIncrement(&vbImpl->bindCount);
2466 IWineD3DVertexBuffer_AddRef(pStreamData);
2468 if (oldSrc != NULL) {
2469 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2470 IWineD3DVertexBuffer_Release(oldSrc);
2473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2475 return WINED3D_OK;
2478 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2481 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2482 This->stateBlock->streamSource[StreamNumber],
2483 This->stateBlock->streamOffset[StreamNumber],
2484 This->stateBlock->streamStride[StreamNumber]);
2486 if (StreamNumber >= MAX_STREAMS) {
2487 WARN("Stream out of range %d\n", StreamNumber);
2488 return WINED3DERR_INVALIDCALL;
2490 *pStream = This->stateBlock->streamSource[StreamNumber];
2491 *pStride = This->stateBlock->streamStride[StreamNumber];
2492 if (pOffset) {
2493 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2496 if (*pStream != NULL) {
2497 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2499 return WINED3D_OK;
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2505 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2507 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2508 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2510 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2511 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2513 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2514 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2515 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2518 return WINED3D_OK;
2521 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2524 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2525 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2527 TRACE("(%p) : returning %d\n", This, *Divider);
2529 return WINED3D_OK;
2532 /*****
2533 * Get / Set & Multiply Transform
2534 *****/
2535 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2538 /* Most of this routine, comments included copied from ddraw tree initially: */
2539 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2541 /* Handle recording of state blocks */
2542 if (This->isRecordingState) {
2543 TRACE("Recording... not performing anything\n");
2544 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2545 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2546 return WINED3D_OK;
2550 * If the new matrix is the same as the current one,
2551 * we cut off any further processing. this seems to be a reasonable
2552 * optimization because as was noticed, some apps (warcraft3 for example)
2553 * tend towards setting the same matrix repeatedly for some reason.
2555 * From here on we assume that the new matrix is different, wherever it matters.
2557 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2558 TRACE("The app is setting the same matrix over again\n");
2559 return WINED3D_OK;
2560 } else {
2561 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2565 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2566 where ViewMat = Camera space, WorldMat = world space.
2568 In OpenGL, camera and world space is combined into GL_MODELVIEW
2569 matrix. The Projection matrix stay projection matrix.
2572 /* Capture the times we can just ignore the change for now */
2573 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2574 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2575 /* Handled by the state manager */
2578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2579 return WINED3D_OK;
2582 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2584 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2585 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2586 return WINED3D_OK;
2589 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2590 WINED3DMATRIX *mat = NULL;
2591 WINED3DMATRIX temp;
2593 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2594 * below means it will be recorded in a state block change, but it
2595 * works regardless where it is recorded.
2596 * If this is found to be wrong, change to StateBlock.
2598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2599 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2601 if (State < HIGHEST_TRANSFORMSTATE)
2603 mat = &This->updateStateBlock->transforms[State];
2604 } else {
2605 FIXME("Unhandled transform state!!\n");
2608 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2610 /* Apply change via set transform - will reapply to eg. lights this way */
2611 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2614 /*****
2615 * Get / Set Light
2616 *****/
2617 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2618 you can reference any indexes you want as long as that number max are enabled at any
2619 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2620 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2621 but when recording, just build a chain pretty much of commands to be replayed. */
2623 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2624 float rho;
2625 PLIGHTINFOEL *object = NULL;
2626 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2627 struct list *e;
2629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2630 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2632 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2633 * the gl driver.
2635 if(!pLight) {
2636 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2637 return WINED3DERR_INVALIDCALL;
2640 switch(pLight->Type) {
2641 case WINED3DLIGHT_POINT:
2642 case WINED3DLIGHT_SPOT:
2643 case WINED3DLIGHT_PARALLELPOINT:
2644 case WINED3DLIGHT_GLSPOT:
2645 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2646 * most wanted
2648 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2649 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2650 return WINED3DERR_INVALIDCALL;
2652 break;
2654 case WINED3DLIGHT_DIRECTIONAL:
2655 /* Ignores attenuation */
2656 break;
2658 default:
2659 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2660 return WINED3DERR_INVALIDCALL;
2663 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2664 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2665 if(object->OriginalIndex == Index) break;
2666 object = NULL;
2669 if(!object) {
2670 TRACE("Adding new light\n");
2671 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2672 if(!object) {
2673 ERR("Out of memory error when allocating a light\n");
2674 return E_OUTOFMEMORY;
2676 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2677 object->glIndex = -1;
2678 object->OriginalIndex = Index;
2679 object->changed = TRUE;
2682 /* Initialize the object */
2683 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,
2684 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2685 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2686 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2687 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2688 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2689 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2691 /* Save away the information */
2692 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2694 switch (pLight->Type) {
2695 case WINED3DLIGHT_POINT:
2696 /* Position */
2697 object->lightPosn[0] = pLight->Position.x;
2698 object->lightPosn[1] = pLight->Position.y;
2699 object->lightPosn[2] = pLight->Position.z;
2700 object->lightPosn[3] = 1.0f;
2701 object->cutoff = 180.0f;
2702 /* FIXME: Range */
2703 break;
2705 case WINED3DLIGHT_DIRECTIONAL:
2706 /* Direction */
2707 object->lightPosn[0] = -pLight->Direction.x;
2708 object->lightPosn[1] = -pLight->Direction.y;
2709 object->lightPosn[2] = -pLight->Direction.z;
2710 object->lightPosn[3] = 0.0;
2711 object->exponent = 0.0f;
2712 object->cutoff = 180.0f;
2713 break;
2715 case WINED3DLIGHT_SPOT:
2716 /* Position */
2717 object->lightPosn[0] = pLight->Position.x;
2718 object->lightPosn[1] = pLight->Position.y;
2719 object->lightPosn[2] = pLight->Position.z;
2720 object->lightPosn[3] = 1.0;
2722 /* Direction */
2723 object->lightDirn[0] = pLight->Direction.x;
2724 object->lightDirn[1] = pLight->Direction.y;
2725 object->lightDirn[2] = pLight->Direction.z;
2726 object->lightDirn[3] = 1.0;
2729 * opengl-ish and d3d-ish spot lights use too different models for the
2730 * light "intensity" as a function of the angle towards the main light direction,
2731 * so we only can approximate very roughly.
2732 * however spot lights are rather rarely used in games (if ever used at all).
2733 * furthermore if still used, probably nobody pays attention to such details.
2735 if (pLight->Falloff == 0) {
2736 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2737 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2738 * will always be 1.0 for both of them, and we don't have to care for the
2739 * rest of the rather complex calculation
2741 object->exponent = 0;
2742 } else {
2743 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2744 if (rho < 0.0001) rho = 0.0001f;
2745 object->exponent = -0.3/log(cos(rho/2));
2747 if (object->exponent > 128.0) {
2748 object->exponent = 128.0;
2750 object->cutoff = pLight->Phi*90/M_PI;
2752 /* FIXME: Range */
2753 break;
2755 default:
2756 FIXME("Unrecognized light type %d\n", pLight->Type);
2759 /* Update the live definitions if the light is currently assigned a glIndex */
2760 if (object->glIndex != -1 && !This->isRecordingState) {
2761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2763 return WINED3D_OK;
2766 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2767 PLIGHTINFOEL *lightInfo = NULL;
2768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2769 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2770 struct list *e;
2771 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2773 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2774 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2775 if(lightInfo->OriginalIndex == Index) break;
2776 lightInfo = NULL;
2779 if (lightInfo == NULL) {
2780 TRACE("Light information requested but light not defined\n");
2781 return WINED3DERR_INVALIDCALL;
2784 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2785 return WINED3D_OK;
2788 /*****
2789 * Get / Set Light Enable
2790 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2791 *****/
2792 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2793 PLIGHTINFOEL *lightInfo = NULL;
2794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2795 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2796 struct list *e;
2797 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2799 /* Tests show true = 128...not clear why */
2800 Enable = Enable? 128: 0;
2802 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2803 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2804 if(lightInfo->OriginalIndex == Index) break;
2805 lightInfo = NULL;
2807 TRACE("Found light: %p\n", lightInfo);
2809 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2810 if (lightInfo == NULL) {
2812 TRACE("Light enabled requested but light not defined, so defining one!\n");
2813 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2815 /* Search for it again! Should be fairly quick as near head of list */
2816 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2817 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2818 if(lightInfo->OriginalIndex == Index) break;
2819 lightInfo = NULL;
2821 if (lightInfo == NULL) {
2822 FIXME("Adding default lights has failed dismally\n");
2823 return WINED3DERR_INVALIDCALL;
2827 lightInfo->enabledChanged = TRUE;
2828 if(!Enable) {
2829 if(lightInfo->glIndex != -1) {
2830 if(!This->isRecordingState) {
2831 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2834 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2835 lightInfo->glIndex = -1;
2836 } else {
2837 TRACE("Light already disabled, nothing to do\n");
2839 lightInfo->enabled = FALSE;
2840 } else {
2841 lightInfo->enabled = TRUE;
2842 if (lightInfo->glIndex != -1) {
2843 /* nop */
2844 TRACE("Nothing to do as light was enabled\n");
2845 } else {
2846 int i;
2847 /* Find a free gl light */
2848 for(i = 0; i < This->maxConcurrentLights; i++) {
2849 if(This->stateBlock->activeLights[i] == NULL) {
2850 This->stateBlock->activeLights[i] = lightInfo;
2851 lightInfo->glIndex = i;
2852 break;
2855 if(lightInfo->glIndex == -1) {
2856 /* Our tests show that Windows returns D3D_OK in this situation, even with
2857 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2858 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2859 * as well for those lights.
2861 * TODO: Test how this affects rendering
2863 FIXME("Too many concurrently active lights\n");
2864 return WINED3D_OK;
2867 /* i == lightInfo->glIndex */
2868 if(!This->isRecordingState) {
2869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2874 return WINED3D_OK;
2877 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2879 PLIGHTINFOEL *lightInfo = NULL;
2880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2881 struct list *e;
2882 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2883 TRACE("(%p) : for idx(%d)\n", This, Index);
2885 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2886 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2887 if(lightInfo->OriginalIndex == Index) break;
2888 lightInfo = NULL;
2891 if (lightInfo == NULL) {
2892 TRACE("Light enabled state requested but light not defined\n");
2893 return WINED3DERR_INVALIDCALL;
2895 /* true is 128 according to SetLightEnable */
2896 *pEnable = lightInfo->enabled ? 128 : 0;
2897 return WINED3D_OK;
2900 /*****
2901 * Get / Set Clip Planes
2902 *****/
2903 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2905 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2907 /* Validate Index */
2908 if (Index >= GL_LIMITS(clipplanes)) {
2909 TRACE("Application has requested clipplane this device doesn't support\n");
2910 return WINED3DERR_INVALIDCALL;
2913 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2915 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2916 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2917 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2918 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2919 TRACE("Application is setting old values over, nothing to do\n");
2920 return WINED3D_OK;
2923 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2924 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2925 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2926 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2928 /* Handle recording of state blocks */
2929 if (This->isRecordingState) {
2930 TRACE("Recording... not performing anything\n");
2931 return WINED3D_OK;
2934 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2936 return WINED3D_OK;
2939 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2941 TRACE("(%p) : for idx %d\n", This, Index);
2943 /* Validate Index */
2944 if (Index >= GL_LIMITS(clipplanes)) {
2945 TRACE("Application has requested clipplane this device doesn't support\n");
2946 return WINED3DERR_INVALIDCALL;
2949 pPlane[0] = This->stateBlock->clipplane[Index][0];
2950 pPlane[1] = This->stateBlock->clipplane[Index][1];
2951 pPlane[2] = This->stateBlock->clipplane[Index][2];
2952 pPlane[3] = This->stateBlock->clipplane[Index][3];
2953 return WINED3D_OK;
2956 /*****
2957 * Get / Set Clip Plane Status
2958 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2959 *****/
2960 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2962 FIXME("(%p) : stub\n", This);
2963 if (NULL == pClipStatus) {
2964 return WINED3DERR_INVALIDCALL;
2966 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2967 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2973 FIXME("(%p) : stub\n", This);
2974 if (NULL == pClipStatus) {
2975 return WINED3DERR_INVALIDCALL;
2977 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2978 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2979 return WINED3D_OK;
2982 /*****
2983 * Get / Set Material
2984 *****/
2985 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2988 This->updateStateBlock->changed.material = TRUE;
2989 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2991 /* Handle recording of state blocks */
2992 if (This->isRecordingState) {
2993 TRACE("Recording... not performing anything\n");
2994 return WINED3D_OK;
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2998 return WINED3D_OK;
3001 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3003 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3004 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3005 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3006 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3007 pMaterial->Ambient.b, pMaterial->Ambient.a);
3008 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3009 pMaterial->Specular.b, pMaterial->Specular.a);
3010 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3011 pMaterial->Emissive.b, pMaterial->Emissive.a);
3012 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3014 return WINED3D_OK;
3017 /*****
3018 * Get / Set Indices
3019 *****/
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 IWineD3DIndexBuffer *oldIdxs;
3024 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3025 oldIdxs = This->updateStateBlock->pIndexData;
3027 This->updateStateBlock->changed.indices = TRUE;
3028 This->updateStateBlock->pIndexData = pIndexData;
3030 /* Handle recording of state blocks */
3031 if (This->isRecordingState) {
3032 TRACE("Recording... not performing anything\n");
3033 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3034 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3035 return WINED3D_OK;
3038 if(oldIdxs != pIndexData) {
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3040 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3041 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3043 return WINED3D_OK;
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 *ppIndexData = This->stateBlock->pIndexData;
3051 /* up ref count on ppindexdata */
3052 if (*ppIndexData) {
3053 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3054 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3055 }else{
3056 TRACE("(%p) No index data set\n", This);
3058 TRACE("Returning %p\n", *ppIndexData);
3060 return WINED3D_OK;
3063 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3064 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3066 TRACE("(%p)->(%d)\n", This, BaseIndex);
3068 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3069 TRACE("Application is setting the old value over, nothing to do\n");
3070 return WINED3D_OK;
3073 This->updateStateBlock->baseVertexIndex = BaseIndex;
3075 if (This->isRecordingState) {
3076 TRACE("Recording... not performing anything\n");
3077 return WINED3D_OK;
3079 /* The base vertex index affects the stream sources */
3080 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3081 return WINED3D_OK;
3084 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3086 TRACE("(%p) : base_index %p\n", This, base_index);
3088 *base_index = This->stateBlock->baseVertexIndex;
3090 TRACE("Returning %u\n", *base_index);
3092 return WINED3D_OK;
3095 /*****
3096 * Get / Set Viewports
3097 *****/
3098 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3101 TRACE("(%p)\n", This);
3102 This->updateStateBlock->changed.viewport = TRUE;
3103 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3105 /* Handle recording of state blocks */
3106 if (This->isRecordingState) {
3107 TRACE("Recording... not performing anything\n");
3108 return WINED3D_OK;
3111 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3112 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3115 return WINED3D_OK;
3119 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 TRACE("(%p)\n", This);
3122 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3123 return WINED3D_OK;
3126 /*****
3127 * Get / Set Render States
3128 * TODO: Verify against dx9 definitions
3129 *****/
3130 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 DWORD oldValue = This->stateBlock->renderState[State];
3135 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3137 This->updateStateBlock->changed.renderState[State] = TRUE;
3138 This->updateStateBlock->renderState[State] = Value;
3140 /* Handle recording of state blocks */
3141 if (This->isRecordingState) {
3142 TRACE("Recording... not performing anything\n");
3143 return WINED3D_OK;
3146 /* Compared here and not before the assignment to allow proper stateblock recording */
3147 if(Value == oldValue) {
3148 TRACE("Application is setting the old value over, nothing to do\n");
3149 } else {
3150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3153 return WINED3D_OK;
3156 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3158 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3159 *pValue = This->stateBlock->renderState[State];
3160 return WINED3D_OK;
3163 /*****
3164 * Get / Set Sampler States
3165 * TODO: Verify against dx9 definitions
3166 *****/
3168 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3170 DWORD oldValue;
3172 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3173 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3175 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3176 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3180 * SetSampler is designed to allow for more than the standard up to 8 textures
3181 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3182 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3184 * http://developer.nvidia.com/object/General_FAQ.html#t6
3186 * There are two new settings for GForce
3187 * the sampler one:
3188 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3189 * and the texture one:
3190 * GL_MAX_TEXTURE_COORDS_ARB.
3191 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3192 ******************/
3194 oldValue = This->stateBlock->samplerState[Sampler][Type];
3195 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3196 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3198 /* Handle recording of state blocks */
3199 if (This->isRecordingState) {
3200 TRACE("Recording... not performing anything\n");
3201 return WINED3D_OK;
3204 if(oldValue == Value) {
3205 TRACE("Application is setting the old value over, nothing to do\n");
3206 return WINED3D_OK;
3209 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3211 return WINED3D_OK;
3214 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3217 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3218 This, Sampler, debug_d3dsamplerstate(Type), Type);
3220 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3221 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3224 *Value = This->stateBlock->samplerState[Sampler][Type];
3225 TRACE("(%p) : Returning %#x\n", This, *Value);
3227 return WINED3D_OK;
3230 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 This->updateStateBlock->changed.scissorRect = TRUE;
3234 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3235 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3236 return WINED3D_OK;
3238 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3240 if(This->isRecordingState) {
3241 TRACE("Recording... not performing anything\n");
3242 return WINED3D_OK;
3245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3247 return WINED3D_OK;
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3253 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3254 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3255 return WINED3D_OK;
3258 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3260 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3262 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3264 This->updateStateBlock->vertexDecl = pDecl;
3265 This->updateStateBlock->changed.vertexDecl = TRUE;
3267 if (This->isRecordingState) {
3268 TRACE("Recording... not performing anything\n");
3269 return WINED3D_OK;
3270 } else if(pDecl == oldDecl) {
3271 /* Checked after the assignment to allow proper stateblock recording */
3272 TRACE("Application is setting the old declaration over, nothing to do\n");
3273 return WINED3D_OK;
3276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3277 return WINED3D_OK;
3280 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3285 *ppDecl = This->stateBlock->vertexDecl;
3286 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3287 return WINED3D_OK;
3290 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3294 This->updateStateBlock->vertexShader = pShader;
3295 This->updateStateBlock->changed.vertexShader = TRUE;
3297 if (This->isRecordingState) {
3298 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3299 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3300 TRACE("Recording... not performing anything\n");
3301 return WINED3D_OK;
3302 } else if(oldShader == pShader) {
3303 /* Checked here to allow proper stateblock recording */
3304 TRACE("App is setting the old shader over, nothing to do\n");
3305 return WINED3D_OK;
3308 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3309 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3310 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3314 return WINED3D_OK;
3317 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3320 if (NULL == ppShader) {
3321 return WINED3DERR_INVALIDCALL;
3323 *ppShader = This->stateBlock->vertexShader;
3324 if( NULL != *ppShader)
3325 IWineD3DVertexShader_AddRef(*ppShader);
3327 TRACE("(%p) : returning %p\n", This, *ppShader);
3328 return WINED3D_OK;
3331 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3332 IWineD3DDevice *iface,
3333 UINT start,
3334 CONST BOOL *srcData,
3335 UINT count) {
3337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 int i, cnt = min(count, MAX_CONST_B - start);
3340 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3341 iface, srcData, start, count);
3343 if (srcData == NULL || cnt < 0)
3344 return WINED3DERR_INVALIDCALL;
3346 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3347 for (i = 0; i < cnt; i++)
3348 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3350 for (i = start; i < cnt + start; ++i) {
3351 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3356 return WINED3D_OK;
3359 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3360 IWineD3DDevice *iface,
3361 UINT start,
3362 BOOL *dstData,
3363 UINT count) {
3365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3366 int cnt = min(count, MAX_CONST_B - start);
3368 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3369 iface, dstData, start, count);
3371 if (dstData == NULL || cnt < 0)
3372 return WINED3DERR_INVALIDCALL;
3374 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3375 return WINED3D_OK;
3378 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3379 IWineD3DDevice *iface,
3380 UINT start,
3381 CONST int *srcData,
3382 UINT count) {
3384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3385 int i, cnt = min(count, MAX_CONST_I - start);
3387 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3388 iface, srcData, start, count);
3390 if (srcData == NULL || cnt < 0)
3391 return WINED3DERR_INVALIDCALL;
3393 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3394 for (i = 0; i < cnt; i++)
3395 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3396 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3398 for (i = start; i < cnt + start; ++i) {
3399 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3404 return WINED3D_OK;
3407 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3408 IWineD3DDevice *iface,
3409 UINT start,
3410 int *dstData,
3411 UINT count) {
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3414 int cnt = min(count, MAX_CONST_I - start);
3416 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3417 iface, dstData, start, count);
3419 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3420 return WINED3DERR_INVALIDCALL;
3422 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3423 return WINED3D_OK;
3426 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3427 IWineD3DDevice *iface,
3428 UINT start,
3429 CONST float *srcData,
3430 UINT count) {
3432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3433 int i;
3435 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3436 iface, srcData, start, count);
3438 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3439 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3440 return WINED3DERR_INVALIDCALL;
3442 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3443 if(TRACE_ON(d3d)) {
3444 for (i = 0; i < count; i++)
3445 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3446 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3449 for (i = start; i < count + start; ++i) {
3450 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3451 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3452 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3453 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3454 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3456 ptr->idx[ptr->count++] = i;
3457 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3461 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3463 return WINED3D_OK;
3466 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3467 IWineD3DDevice *iface,
3468 UINT start,
3469 float *dstData,
3470 UINT count) {
3472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3473 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3475 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3476 iface, dstData, start, count);
3478 if (dstData == NULL || cnt < 0)
3479 return WINED3DERR_INVALIDCALL;
3481 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3482 return WINED3D_OK;
3485 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3486 DWORD i;
3487 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3492 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3493 int i = This->rev_tex_unit_map[unit];
3494 int j = This->texUnitMap[stage];
3496 This->texUnitMap[stage] = unit;
3497 if (i != -1 && i != stage) {
3498 This->texUnitMap[i] = -1;
3501 This->rev_tex_unit_map[unit] = stage;
3502 if (j != -1 && j != unit) {
3503 This->rev_tex_unit_map[j] = -1;
3507 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3508 int i;
3510 for (i = 0; i < MAX_TEXTURES; ++i) {
3511 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3512 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3513 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3514 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3515 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3516 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3517 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3518 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3520 if (color_op == WINED3DTOP_DISABLE) {
3521 /* Not used, and disable higher stages */
3522 while (i < MAX_TEXTURES) {
3523 This->fixed_function_usage_map[i] = FALSE;
3524 ++i;
3526 break;
3529 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3530 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3531 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3532 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3533 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3534 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3535 This->fixed_function_usage_map[i] = TRUE;
3536 } else {
3537 This->fixed_function_usage_map[i] = FALSE;
3540 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3541 This->fixed_function_usage_map[i+1] = TRUE;
3546 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3547 int i, tex;
3549 device_update_fixed_function_usage_map(This);
3551 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3552 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3553 if (!This->fixed_function_usage_map[i]) continue;
3555 if (This->texUnitMap[i] != i) {
3556 device_map_stage(This, i, i);
3557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3558 markTextureStagesDirty(This, i);
3561 return;
3564 /* Now work out the mapping */
3565 tex = 0;
3566 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3567 if (!This->fixed_function_usage_map[i]) continue;
3569 if (This->texUnitMap[i] != tex) {
3570 device_map_stage(This, i, tex);
3571 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3572 markTextureStagesDirty(This, i);
3575 ++tex;
3579 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3580 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3581 int i;
3583 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3584 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3585 device_map_stage(This, i, i);
3586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3587 if (i < MAX_TEXTURES) {
3588 markTextureStagesDirty(This, i);
3594 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3595 int current_mapping = This->rev_tex_unit_map[unit];
3597 if (current_mapping == -1) {
3598 /* Not currently used */
3599 return TRUE;
3602 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3603 /* Used by a fragment sampler */
3605 if (!pshader_sampler_tokens) {
3606 /* No pixel shader, check fixed function */
3607 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3610 /* Pixel shader, check the shader's sampler map */
3611 return !pshader_sampler_tokens[current_mapping];
3614 /* Used by a vertex sampler */
3615 return !vshader_sampler_tokens[current_mapping];
3618 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3619 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3620 DWORD *pshader_sampler_tokens = NULL;
3621 int start = GL_LIMITS(combined_samplers) - 1;
3622 int i;
3624 if (ps) {
3625 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3627 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3628 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3629 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3632 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3633 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3634 if (vshader_sampler_tokens[i]) {
3635 if (This->texUnitMap[vsampler_idx] != -1) {
3636 /* Already mapped somewhere */
3637 continue;
3640 while (start >= 0) {
3641 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3642 device_map_stage(This, vsampler_idx, start);
3643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3645 --start;
3646 break;
3649 --start;
3655 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3656 BOOL vs = use_vs(This);
3657 BOOL ps = use_ps(This);
3659 * Rules are:
3660 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3661 * that would be really messy and require shader recompilation
3662 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3663 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3665 if (ps) {
3666 device_map_psamplers(This);
3667 } else {
3668 device_map_fixed_function_samplers(This);
3671 if (vs) {
3672 device_map_vsamplers(This, ps);
3676 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3678 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3679 This->updateStateBlock->pixelShader = pShader;
3680 This->updateStateBlock->changed.pixelShader = TRUE;
3682 /* Handle recording of state blocks */
3683 if (This->isRecordingState) {
3684 TRACE("Recording... not performing anything\n");
3687 if (This->isRecordingState) {
3688 TRACE("Recording... not performing anything\n");
3689 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3690 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3691 return WINED3D_OK;
3694 if(pShader == oldShader) {
3695 TRACE("App is setting the old pixel shader over, nothing to do\n");
3696 return WINED3D_OK;
3699 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3700 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3702 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3705 return WINED3D_OK;
3708 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3711 if (NULL == ppShader) {
3712 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3713 return WINED3DERR_INVALIDCALL;
3716 *ppShader = This->stateBlock->pixelShader;
3717 if (NULL != *ppShader) {
3718 IWineD3DPixelShader_AddRef(*ppShader);
3720 TRACE("(%p) : returning %p\n", This, *ppShader);
3721 return WINED3D_OK;
3724 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3725 IWineD3DDevice *iface,
3726 UINT start,
3727 CONST BOOL *srcData,
3728 UINT count) {
3730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3731 int i, cnt = min(count, MAX_CONST_B - start);
3733 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3734 iface, srcData, start, count);
3736 if (srcData == NULL || cnt < 0)
3737 return WINED3DERR_INVALIDCALL;
3739 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3740 for (i = 0; i < cnt; i++)
3741 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3743 for (i = start; i < cnt + start; ++i) {
3744 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3749 return WINED3D_OK;
3752 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3753 IWineD3DDevice *iface,
3754 UINT start,
3755 BOOL *dstData,
3756 UINT count) {
3758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3759 int cnt = min(count, MAX_CONST_B - start);
3761 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3762 iface, dstData, start, count);
3764 if (dstData == NULL || cnt < 0)
3765 return WINED3DERR_INVALIDCALL;
3767 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3768 return WINED3D_OK;
3771 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3772 IWineD3DDevice *iface,
3773 UINT start,
3774 CONST int *srcData,
3775 UINT count) {
3777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3778 int i, cnt = min(count, MAX_CONST_I - start);
3780 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3781 iface, srcData, start, count);
3783 if (srcData == NULL || cnt < 0)
3784 return WINED3DERR_INVALIDCALL;
3786 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3787 for (i = 0; i < cnt; i++)
3788 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3789 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3791 for (i = start; i < cnt + start; ++i) {
3792 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3795 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3797 return WINED3D_OK;
3800 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3801 IWineD3DDevice *iface,
3802 UINT start,
3803 int *dstData,
3804 UINT count) {
3806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3807 int cnt = min(count, MAX_CONST_I - start);
3809 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3810 iface, dstData, start, count);
3812 if (dstData == NULL || cnt < 0)
3813 return WINED3DERR_INVALIDCALL;
3815 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3816 return WINED3D_OK;
3819 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3820 IWineD3DDevice *iface,
3821 UINT start,
3822 CONST float *srcData,
3823 UINT count) {
3825 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3826 int i;
3828 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3829 iface, srcData, start, count);
3831 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3832 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3833 return WINED3DERR_INVALIDCALL;
3835 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3836 if(TRACE_ON(d3d)) {
3837 for (i = 0; i < count; i++)
3838 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3839 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3842 for (i = start; i < count + start; ++i) {
3843 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3844 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3845 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3846 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3847 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3849 ptr->idx[ptr->count++] = i;
3850 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3856 return WINED3D_OK;
3859 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3860 IWineD3DDevice *iface,
3861 UINT start,
3862 float *dstData,
3863 UINT count) {
3865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3866 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3868 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3869 iface, dstData, start, count);
3871 if (dstData == NULL || cnt < 0)
3872 return WINED3DERR_INVALIDCALL;
3874 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3875 return WINED3D_OK;
3878 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3879 static HRESULT
3880 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3881 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3882 unsigned int i;
3883 DWORD DestFVF = dest->fvf;
3884 WINED3DVIEWPORT vp;
3885 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3886 BOOL doClip;
3887 int numTextures;
3889 if (lpStrideData->u.s.normal.lpData) {
3890 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3893 if (lpStrideData->u.s.position.lpData == NULL) {
3894 ERR("Source has no position mask\n");
3895 return WINED3DERR_INVALIDCALL;
3898 /* We might access VBOs from this code, so hold the lock */
3899 ENTER_GL();
3901 if (dest->resource.allocatedMemory == NULL) {
3902 /* This may happen if we do direct locking into a vbo. Unlikely,
3903 * but theoretically possible(ddraw processvertices test)
3905 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3906 if(!dest->resource.allocatedMemory) {
3907 LEAVE_GL();
3908 ERR("Out of memory\n");
3909 return E_OUTOFMEMORY;
3911 if(dest->vbo) {
3912 void *src;
3913 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3914 checkGLcall("glBindBufferARB");
3915 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3916 if(src) {
3917 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3919 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3920 checkGLcall("glUnmapBufferARB");
3924 /* Get a pointer into the destination vbo(create one if none exists) and
3925 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3927 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3928 CreateVBO(dest);
3931 if(dest->vbo) {
3932 unsigned char extrabytes = 0;
3933 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3934 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3935 * this may write 4 extra bytes beyond the area that should be written
3937 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3938 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3939 if(!dest_conv_addr) {
3940 ERR("Out of memory\n");
3941 /* Continue without storing converted vertices */
3943 dest_conv = dest_conv_addr;
3946 /* Should I clip?
3947 * a) WINED3DRS_CLIPPING is enabled
3948 * b) WINED3DVOP_CLIP is passed
3950 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3951 static BOOL warned = FALSE;
3953 * The clipping code is not quite correct. Some things need
3954 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3955 * so disable clipping for now.
3956 * (The graphics in Half-Life are broken, and my processvertices
3957 * test crashes with IDirect3DDevice3)
3958 doClip = TRUE;
3960 doClip = FALSE;
3961 if(!warned) {
3962 warned = TRUE;
3963 FIXME("Clipping is broken and disabled for now\n");
3965 } else doClip = FALSE;
3966 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3968 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3969 WINED3DTS_VIEW,
3970 &view_mat);
3971 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3972 WINED3DTS_PROJECTION,
3973 &proj_mat);
3974 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3975 WINED3DTS_WORLDMATRIX(0),
3976 &world_mat);
3978 TRACE("View mat:\n");
3979 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);
3980 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);
3981 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);
3982 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);
3984 TRACE("Proj mat:\n");
3985 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);
3986 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);
3987 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);
3988 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);
3990 TRACE("World mat:\n");
3991 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);
3992 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);
3993 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);
3994 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);
3996 /* Get the viewport */
3997 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3998 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3999 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4001 multiply_matrix(&mat,&view_mat,&world_mat);
4002 multiply_matrix(&mat,&proj_mat,&mat);
4004 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4006 for (i = 0; i < dwCount; i+= 1) {
4007 unsigned int tex_index;
4009 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4010 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4011 /* The position first */
4012 float *p =
4013 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4014 float x, y, z, rhw;
4015 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4017 /* Multiplication with world, view and projection matrix */
4018 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);
4019 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);
4020 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);
4021 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);
4023 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4025 /* WARNING: The following things are taken from d3d7 and were not yet checked
4026 * against d3d8 or d3d9!
4029 /* Clipping conditions: From
4030 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4032 * A vertex is clipped if it does not match the following requirements
4033 * -rhw < x <= rhw
4034 * -rhw < y <= rhw
4035 * 0 < z <= rhw
4036 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4038 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4039 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4043 if( !doClip ||
4044 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4045 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4046 ( rhw > eps ) ) ) {
4048 /* "Normal" viewport transformation (not clipped)
4049 * 1) The values are divided by rhw
4050 * 2) The y axis is negative, so multiply it with -1
4051 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4052 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4053 * 4) Multiply x with Width/2 and add Width/2
4054 * 5) The same for the height
4055 * 6) Add the viewpoint X and Y to the 2D coordinates and
4056 * The minimum Z value to z
4057 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4059 * Well, basically it's simply a linear transformation into viewport
4060 * coordinates
4063 x /= rhw;
4064 y /= rhw;
4065 z /= rhw;
4067 y *= -1;
4069 x *= vp.Width / 2;
4070 y *= vp.Height / 2;
4071 z *= vp.MaxZ - vp.MinZ;
4073 x += vp.Width / 2 + vp.X;
4074 y += vp.Height / 2 + vp.Y;
4075 z += vp.MinZ;
4077 rhw = 1 / rhw;
4078 } else {
4079 /* That vertex got clipped
4080 * Contrary to OpenGL it is not dropped completely, it just
4081 * undergoes a different calculation.
4083 TRACE("Vertex got clipped\n");
4084 x += rhw;
4085 y += rhw;
4087 x /= 2;
4088 y /= 2;
4090 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4091 * outside of the main vertex buffer memory. That needs some more
4092 * investigation...
4096 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4099 ( (float *) dest_ptr)[0] = x;
4100 ( (float *) dest_ptr)[1] = y;
4101 ( (float *) dest_ptr)[2] = z;
4102 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4104 dest_ptr += 3 * sizeof(float);
4106 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4107 dest_ptr += sizeof(float);
4110 if(dest_conv) {
4111 float w = 1 / rhw;
4112 ( (float *) dest_conv)[0] = x * w;
4113 ( (float *) dest_conv)[1] = y * w;
4114 ( (float *) dest_conv)[2] = z * w;
4115 ( (float *) dest_conv)[3] = w;
4117 dest_conv += 3 * sizeof(float);
4119 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4120 dest_conv += sizeof(float);
4124 if (DestFVF & WINED3DFVF_PSIZE) {
4125 dest_ptr += sizeof(DWORD);
4126 if(dest_conv) dest_conv += sizeof(DWORD);
4128 if (DestFVF & WINED3DFVF_NORMAL) {
4129 float *normal =
4130 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4131 /* AFAIK this should go into the lighting information */
4132 FIXME("Didn't expect the destination to have a normal\n");
4133 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4134 if(dest_conv) {
4135 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4139 if (DestFVF & WINED3DFVF_DIFFUSE) {
4140 DWORD *color_d =
4141 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4142 if(!color_d) {
4143 static BOOL warned = FALSE;
4145 if(!warned) {
4146 ERR("No diffuse color in source, but destination has one\n");
4147 warned = TRUE;
4150 *( (DWORD *) dest_ptr) = 0xffffffff;
4151 dest_ptr += sizeof(DWORD);
4153 if(dest_conv) {
4154 *( (DWORD *) dest_conv) = 0xffffffff;
4155 dest_conv += sizeof(DWORD);
4158 else {
4159 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4160 if(dest_conv) {
4161 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4162 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4163 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4164 dest_conv += sizeof(DWORD);
4169 if (DestFVF & WINED3DFVF_SPECULAR) {
4170 /* What's the color value in the feedback buffer? */
4171 DWORD *color_s =
4172 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4173 if(!color_s) {
4174 static BOOL warned = FALSE;
4176 if(!warned) {
4177 ERR("No specular color in source, but destination has one\n");
4178 warned = TRUE;
4181 *( (DWORD *) dest_ptr) = 0xFF000000;
4182 dest_ptr += sizeof(DWORD);
4184 if(dest_conv) {
4185 *( (DWORD *) dest_conv) = 0xFF000000;
4186 dest_conv += sizeof(DWORD);
4189 else {
4190 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4191 if(dest_conv) {
4192 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4193 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4194 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4195 dest_conv += sizeof(DWORD);
4200 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4201 float *tex_coord =
4202 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4203 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4204 if(!tex_coord) {
4205 ERR("No source texture, but destination requests one\n");
4206 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4207 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4209 else {
4210 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4211 if(dest_conv) {
4212 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4218 if(dest_conv) {
4219 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4220 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4221 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4222 dwCount * get_flexible_vertex_size(DestFVF),
4223 dest_conv_addr));
4224 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4225 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4228 LEAVE_GL();
4230 return WINED3D_OK;
4232 #undef copy_and_next
4234 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4236 WineDirect3DVertexStridedData strided;
4237 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4238 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4240 if(pVertexDecl) {
4241 ERR("Output vertex declaration not implemented yet\n");
4244 /* Need any context to write to the vbo. */
4245 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4247 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4248 * control the streamIsUP flag, thus restore it afterwards.
4250 This->stateBlock->streamIsUP = FALSE;
4251 memset(&strided, 0, sizeof(strided));
4252 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4253 This->stateBlock->streamIsUP = streamWasUP;
4255 if(vbo || SrcStartIndex) {
4256 unsigned int i;
4257 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4258 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4260 * Also get the start index in, but only loop over all elements if there's something to add at all.
4262 #define FIXSRC(type) \
4263 if(strided.u.s.type.VBO) { \
4264 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4265 strided.u.s.type.VBO = 0; \
4266 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4267 ENTER_GL(); \
4268 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4269 vb->vbo = 0; \
4270 LEAVE_GL(); \
4272 if(strided.u.s.type.lpData) { \
4273 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4275 FIXSRC(position);
4276 FIXSRC(blendWeights);
4277 FIXSRC(blendMatrixIndices);
4278 FIXSRC(normal);
4279 FIXSRC(pSize);
4280 FIXSRC(diffuse);
4281 FIXSRC(specular);
4282 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4283 FIXSRC(texCoords[i]);
4285 FIXSRC(position2);
4286 FIXSRC(normal2);
4287 FIXSRC(tangent);
4288 FIXSRC(binormal);
4289 FIXSRC(tessFactor);
4290 FIXSRC(fog);
4291 FIXSRC(depth);
4292 FIXSRC(sample);
4293 #undef FIXSRC
4296 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4299 /*****
4300 * Get / Set Texture Stage States
4301 * TODO: Verify against dx9 definitions
4302 *****/
4303 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4305 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4307 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4309 if (Stage >= MAX_TEXTURES) {
4310 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4311 return WINED3D_OK;
4314 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4315 This->updateStateBlock->textureState[Stage][Type] = Value;
4317 if (This->isRecordingState) {
4318 TRACE("Recording... not performing anything\n");
4319 return WINED3D_OK;
4322 /* Checked after the assignments to allow proper stateblock recording */
4323 if(oldValue == Value) {
4324 TRACE("App is setting the old value over, nothing to do\n");
4325 return WINED3D_OK;
4328 if(Stage > This->stateBlock->lowest_disabled_stage &&
4329 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4330 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4331 * Changes in other states are important on disabled stages too
4333 return WINED3D_OK;
4336 if(Type == WINED3DTSS_COLOROP) {
4337 int i;
4339 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4340 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4341 * they have to be disabled
4343 * The current stage is dirtified below.
4345 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4346 TRACE("Additionally dirtifying stage %d\n", i);
4347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4349 This->stateBlock->lowest_disabled_stage = Stage;
4350 TRACE("New lowest disabled: %d\n", Stage);
4351 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4352 /* Previously disabled stage enabled. Stages above it may need enabling
4353 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4354 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4356 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4359 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4360 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4361 break;
4363 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4364 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4366 This->stateBlock->lowest_disabled_stage = i;
4367 TRACE("New lowest disabled: %d\n", i);
4369 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4370 /* TODO: Built a stage -> texture unit mapping for register combiners */
4374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4376 return WINED3D_OK;
4379 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4381 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4382 *pValue = This->updateStateBlock->textureState[Stage][Type];
4383 return WINED3D_OK;
4386 /*****
4387 * Get / Set Texture
4388 *****/
4389 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4391 IWineD3DBaseTexture *oldTexture;
4393 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4395 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4396 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4399 oldTexture = This->updateStateBlock->textures[Stage];
4401 if(pTexture != NULL) {
4402 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4404 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4405 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4406 return WINED3DERR_INVALIDCALL;
4408 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4411 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4412 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4414 This->updateStateBlock->changed.textures[Stage] = TRUE;
4415 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4416 This->updateStateBlock->textures[Stage] = pTexture;
4418 /* Handle recording of state blocks */
4419 if (This->isRecordingState) {
4420 TRACE("Recording... not performing anything\n");
4421 return WINED3D_OK;
4424 if(oldTexture == pTexture) {
4425 TRACE("App is setting the same texture again, nothing to do\n");
4426 return WINED3D_OK;
4429 /** NOTE: MSDN says that setTexture increases the reference count,
4430 * and that the application must set the texture back to null (or have a leaky application),
4431 * This means we should pass the refcount up to the parent
4432 *******************************/
4433 if (NULL != This->updateStateBlock->textures[Stage]) {
4434 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4435 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4437 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4438 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4439 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4440 * so the COLOROP and ALPHAOP have to be dirtified.
4442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4445 if(bindCount == 1) {
4446 new->baseTexture.sampler = Stage;
4448 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4452 if (NULL != oldTexture) {
4453 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4454 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4456 IWineD3DBaseTexture_Release(oldTexture);
4457 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4462 if(bindCount && old->baseTexture.sampler == Stage) {
4463 int i;
4464 /* Have to do a search for the other sampler(s) where the texture is bound to
4465 * Shouldn't happen as long as apps bind a texture only to one stage
4467 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4468 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4469 if(This->updateStateBlock->textures[i] == oldTexture) {
4470 old->baseTexture.sampler = i;
4471 break;
4477 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4479 return WINED3D_OK;
4482 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4487 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4488 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4491 *ppTexture=This->stateBlock->textures[Stage];
4492 if (*ppTexture)
4493 IWineD3DBaseTexture_AddRef(*ppTexture);
4495 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4497 return WINED3D_OK;
4500 /*****
4501 * Get Back Buffer
4502 *****/
4503 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4504 IWineD3DSurface **ppBackBuffer) {
4505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 IWineD3DSwapChain *swapChain;
4507 HRESULT hr;
4509 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4511 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4512 if (hr == WINED3D_OK) {
4513 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4514 IWineD3DSwapChain_Release(swapChain);
4515 } else {
4516 *ppBackBuffer = NULL;
4518 return hr;
4521 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4523 WARN("(%p) : stub, calling idirect3d for now\n", This);
4524 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4527 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 IWineD3DSwapChain *swapChain;
4530 HRESULT hr;
4532 if(iSwapChain > 0) {
4533 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4534 if (hr == WINED3D_OK) {
4535 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4536 IWineD3DSwapChain_Release(swapChain);
4537 } else {
4538 FIXME("(%p) Error getting display mode\n", This);
4540 } else {
4541 /* Don't read the real display mode,
4542 but return the stored mode instead. X11 can't change the color
4543 depth, and some apps are pretty angry if they SetDisplayMode from
4544 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4546 Also don't relay to the swapchain because with ddraw it's possible
4547 that there isn't a swapchain at all */
4548 pMode->Width = This->ddraw_width;
4549 pMode->Height = This->ddraw_height;
4550 pMode->Format = This->ddraw_format;
4551 pMode->RefreshRate = 0;
4552 hr = WINED3D_OK;
4555 return hr;
4558 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4560 TRACE("(%p)->(%p)\n", This, hWnd);
4562 if(This->ddraw_fullscreen) {
4563 if(This->ddraw_window && This->ddraw_window != hWnd) {
4564 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4566 if(hWnd && This->ddraw_window != hWnd) {
4567 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4571 This->ddraw_window = hWnd;
4572 return WINED3D_OK;
4575 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4577 TRACE("(%p)->(%p)\n", This, hWnd);
4579 *hWnd = This->ddraw_window;
4580 return WINED3D_OK;
4583 /*****
4584 * Stateblock related functions
4585 *****/
4587 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4589 IWineD3DStateBlockImpl *object;
4590 HRESULT temp_result;
4591 int i;
4593 TRACE("(%p)\n", This);
4595 if (This->isRecordingState) {
4596 return WINED3DERR_INVALIDCALL;
4599 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4600 if (NULL == object ) {
4601 FIXME("(%p)Error allocating memory for stateblock\n", This);
4602 return E_OUTOFMEMORY;
4604 TRACE("(%p) created object %p\n", This, object);
4605 object->wineD3DDevice= This;
4606 /** FIXME: object->parent = parent; **/
4607 object->parent = NULL;
4608 object->blockType = WINED3DSBT_RECORDED;
4609 object->ref = 1;
4610 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4612 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4613 list_init(&object->lightMap[i]);
4616 temp_result = allocate_shader_constants(object);
4617 if (WINED3D_OK != temp_result)
4618 return temp_result;
4620 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4621 This->updateStateBlock = object;
4622 This->isRecordingState = TRUE;
4624 TRACE("(%p) recording stateblock %p\n",This , object);
4625 return WINED3D_OK;
4628 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 unsigned int i, j;
4631 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4633 if (!This->isRecordingState) {
4634 FIXME("(%p) not recording! returning error\n", This);
4635 *ppStateBlock = NULL;
4636 return WINED3DERR_INVALIDCALL;
4639 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4640 if(object->changed.renderState[i]) {
4641 object->contained_render_states[object->num_contained_render_states] = i;
4642 object->num_contained_render_states++;
4645 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4646 if(object->changed.transform[i]) {
4647 object->contained_transform_states[object->num_contained_transform_states] = i;
4648 object->num_contained_transform_states++;
4651 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4652 if(object->changed.vertexShaderConstantsF[i]) {
4653 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4654 object->num_contained_vs_consts_f++;
4657 for(i = 0; i < MAX_CONST_I; i++) {
4658 if(object->changed.vertexShaderConstantsI[i]) {
4659 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4660 object->num_contained_vs_consts_i++;
4663 for(i = 0; i < MAX_CONST_B; i++) {
4664 if(object->changed.vertexShaderConstantsB[i]) {
4665 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4666 object->num_contained_vs_consts_b++;
4669 for(i = 0; i < MAX_CONST_I; i++) {
4670 if(object->changed.pixelShaderConstantsI[i]) {
4671 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4672 object->num_contained_ps_consts_i++;
4675 for(i = 0; i < MAX_CONST_B; i++) {
4676 if(object->changed.pixelShaderConstantsB[i]) {
4677 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4678 object->num_contained_ps_consts_b++;
4681 for(i = 0; i < MAX_TEXTURES; i++) {
4682 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4683 if(object->changed.textureState[i][j]) {
4684 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4685 object->contained_tss_states[object->num_contained_tss_states].state = j;
4686 object->num_contained_tss_states++;
4690 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4691 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4692 if(object->changed.samplerState[i][j]) {
4693 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4694 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4695 object->num_contained_sampler_states++;
4700 *ppStateBlock = (IWineD3DStateBlock*) object;
4701 This->isRecordingState = FALSE;
4702 This->updateStateBlock = This->stateBlock;
4703 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4704 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4705 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4706 return WINED3D_OK;
4709 /*****
4710 * Scene related functions
4711 *****/
4712 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4713 /* At the moment we have no need for any functionality at the beginning
4714 of a scene */
4715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4716 TRACE("(%p)\n", This);
4718 if(This->inScene) {
4719 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4720 return WINED3DERR_INVALIDCALL;
4722 This->inScene = TRUE;
4723 return WINED3D_OK;
4726 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4728 TRACE("(%p)\n", This);
4730 if(!This->inScene) {
4731 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4732 return WINED3DERR_INVALIDCALL;
4735 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4736 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4737 ENTER_GL();
4738 glFlush();
4739 checkGLcall("glFlush");
4740 LEAVE_GL();
4742 This->inScene = FALSE;
4743 return WINED3D_OK;
4746 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4747 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4748 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4750 IWineD3DSwapChain *swapChain = NULL;
4751 int i;
4752 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4754 TRACE("(%p) Presenting the frame\n", This);
4756 for(i = 0 ; i < swapchains ; i ++) {
4758 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4759 TRACE("presentinng chain %d, %p\n", i, swapChain);
4760 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4761 IWineD3DSwapChain_Release(swapChain);
4764 return WINED3D_OK;
4767 /* Not called from the VTable (internal subroutine) */
4768 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4769 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4770 float Z, DWORD Stencil) {
4771 GLbitfield glMask = 0;
4772 unsigned int i;
4773 WINED3DRECT curRect;
4774 RECT vp_rect;
4775 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4776 UINT drawable_width, drawable_height;
4778 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4779 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4780 * for the cleared parts, and the untouched parts.
4782 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4783 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4784 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4785 * checking all this if the dest surface is in the drawable anyway.
4787 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4788 while(1) {
4789 if(vp->X != 0 || vp->Y != 0 ||
4790 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4791 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4792 break;
4794 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4795 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4796 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4797 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4798 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4799 break;
4801 if(Count > 0 && pRects && (
4802 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4803 pRects[0].x2 < target->currentDesc.Width ||
4804 pRects[0].y2 < target->currentDesc.Height)) {
4805 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4806 break;
4808 break;
4812 target->get_drawable_size(target, &drawable_width, &drawable_height);
4814 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4815 ENTER_GL();
4817 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4818 apply_fbo_state((IWineD3DDevice *) This);
4821 /* Only set the values up once, as they are not changing */
4822 if (Flags & WINED3DCLEAR_STENCIL) {
4823 glClearStencil(Stencil);
4824 checkGLcall("glClearStencil");
4825 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4826 glStencilMask(0xFFFFFFFF);
4829 if (Flags & WINED3DCLEAR_ZBUFFER) {
4830 glDepthMask(GL_TRUE);
4831 glClearDepth(Z);
4832 checkGLcall("glClearDepth");
4833 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4837 if (Flags & WINED3DCLEAR_TARGET) {
4838 TRACE("Clearing screen with glClear to color %x\n", Color);
4839 glClearColor(D3DCOLOR_R(Color),
4840 D3DCOLOR_G(Color),
4841 D3DCOLOR_B(Color),
4842 D3DCOLOR_A(Color));
4843 checkGLcall("glClearColor");
4845 /* Clear ALL colors! */
4846 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4847 glMask = glMask | GL_COLOR_BUFFER_BIT;
4850 vp_rect.left = vp->X;
4851 vp_rect.top = vp->Y;
4852 vp_rect.right = vp->X + vp->Width;
4853 vp_rect.bottom = vp->Y + vp->Height;
4854 if (!(Count > 0 && pRects)) {
4855 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4856 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4858 if(This->render_offscreen) {
4859 glScissor(vp_rect.left, vp_rect.top,
4860 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4861 } else {
4862 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4863 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4865 checkGLcall("glScissor");
4866 glClear(glMask);
4867 checkGLcall("glClear");
4868 } else {
4869 /* Now process each rect in turn */
4870 for (i = 0; i < Count; i++) {
4871 /* Note gl uses lower left, width/height */
4872 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4873 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4874 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4876 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4877 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4878 curRect.x1, (target->currentDesc.Height - curRect.y2),
4879 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4881 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4882 * The rectangle is not cleared, no error is returned, but further rectanlges are
4883 * still cleared if they are valid
4885 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4886 TRACE("Rectangle with negative dimensions, ignoring\n");
4887 continue;
4890 if(This->render_offscreen) {
4891 glScissor(curRect.x1, curRect.y1,
4892 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4893 } else {
4894 glScissor(curRect.x1, drawable_height - curRect.y2,
4895 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4897 checkGLcall("glScissor");
4899 glClear(glMask);
4900 checkGLcall("glClear");
4904 /* Restore the old values (why..?) */
4905 if (Flags & WINED3DCLEAR_STENCIL) {
4906 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4908 if (Flags & WINED3DCLEAR_TARGET) {
4909 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4910 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4911 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4912 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4913 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4915 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4916 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4918 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4919 /* TODO: Move the fbo logic into ModifyLocation() */
4920 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4921 target->Flags |= SFLAG_INTEXTURE;
4924 LEAVE_GL();
4926 return WINED3D_OK;
4929 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4930 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4932 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4934 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4935 Count, pRects, Flags, Color, Z, Stencil);
4937 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4938 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4939 /* TODO: What about depth stencil buffers without stencil bits? */
4940 return WINED3DERR_INVALIDCALL;
4943 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4946 /*****
4947 * Drawing functions
4948 *****/
4949 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4950 UINT PrimitiveCount) {
4952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4955 debug_d3dprimitivetype(PrimitiveType),
4956 StartVertex, PrimitiveCount);
4958 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4959 if(This->stateBlock->streamIsUP) {
4960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4961 This->stateBlock->streamIsUP = FALSE;
4964 if(This->stateBlock->loadBaseVertexIndex != 0) {
4965 This->stateBlock->loadBaseVertexIndex = 0;
4966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4968 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4969 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4970 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4971 return WINED3D_OK;
4974 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4975 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4976 WINED3DPRIMITIVETYPE PrimitiveType,
4977 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4980 UINT idxStride = 2;
4981 IWineD3DIndexBuffer *pIB;
4982 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4983 GLuint vbo;
4985 pIB = This->stateBlock->pIndexData;
4986 if (!pIB) {
4987 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4988 * without an index buffer set. (The first time at least...)
4989 * D3D8 simply dies, but I doubt it can do much harm to return
4990 * D3DERR_INVALIDCALL there as well. */
4991 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4992 return WINED3DERR_INVALIDCALL;
4995 if(This->stateBlock->streamIsUP) {
4996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4997 This->stateBlock->streamIsUP = FALSE;
4999 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5001 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5002 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5003 minIndex, NumVertices, startIndex, primCount);
5005 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5006 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5007 idxStride = 2;
5008 } else {
5009 idxStride = 4;
5012 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5013 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5017 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5018 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5020 return WINED3D_OK;
5023 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5024 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5025 UINT VertexStreamZeroStride) {
5026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5027 IWineD3DVertexBuffer *vb;
5029 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5030 debug_d3dprimitivetype(PrimitiveType),
5031 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5033 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5034 vb = This->stateBlock->streamSource[0];
5035 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5036 if(vb) IWineD3DVertexBuffer_Release(vb);
5037 This->stateBlock->streamOffset[0] = 0;
5038 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5039 This->stateBlock->streamIsUP = TRUE;
5040 This->stateBlock->loadBaseVertexIndex = 0;
5042 /* TODO: Only mark dirty if drawing from a different UP address */
5043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5045 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5046 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5048 /* MSDN specifies stream zero settings must be set to NULL */
5049 This->stateBlock->streamStride[0] = 0;
5050 This->stateBlock->streamSource[0] = NULL;
5052 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5053 * the new stream sources or use UP drawing again
5055 return WINED3D_OK;
5058 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5059 UINT MinVertexIndex, UINT NumVertices,
5060 UINT PrimitiveCount, CONST void* pIndexData,
5061 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5062 UINT VertexStreamZeroStride) {
5063 int idxStride;
5064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5065 IWineD3DVertexBuffer *vb;
5066 IWineD3DIndexBuffer *ib;
5068 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5069 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5070 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5071 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5073 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5074 idxStride = 2;
5075 } else {
5076 idxStride = 4;
5079 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5080 vb = This->stateBlock->streamSource[0];
5081 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5082 if(vb) IWineD3DVertexBuffer_Release(vb);
5083 This->stateBlock->streamIsUP = TRUE;
5084 This->stateBlock->streamOffset[0] = 0;
5085 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5087 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5088 This->stateBlock->baseVertexIndex = 0;
5089 This->stateBlock->loadBaseVertexIndex = 0;
5090 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5094 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5096 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5097 This->stateBlock->streamSource[0] = NULL;
5098 This->stateBlock->streamStride[0] = 0;
5099 ib = This->stateBlock->pIndexData;
5100 if(ib) {
5101 IWineD3DIndexBuffer_Release(ib);
5102 This->stateBlock->pIndexData = NULL;
5104 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5105 * SetStreamSource to specify a vertex buffer
5108 return WINED3D_OK;
5111 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5114 /* Mark the state dirty until we have nicer tracking
5115 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5116 * that value.
5118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5120 This->stateBlock->baseVertexIndex = 0;
5121 This->up_strided = DrawPrimStrideData;
5122 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5123 This->up_strided = NULL;
5124 return WINED3D_OK;
5127 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5129 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5131 /* Mark the state dirty until we have nicer tracking
5132 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5133 * that value.
5135 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5137 This->stateBlock->streamIsUP = TRUE;
5138 This->stateBlock->baseVertexIndex = 0;
5139 This->up_strided = DrawPrimStrideData;
5140 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5141 This->up_strided = NULL;
5142 return WINED3D_OK;
5145 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5146 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5147 * not callable by the app directly no parameter validation checks are needed here.
5149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5150 WINED3DLOCKED_BOX src;
5151 WINED3DLOCKED_BOX dst;
5152 HRESULT hr;
5153 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5155 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5156 * dirtification to improve loading performance.
5158 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5159 if(FAILED(hr)) return hr;
5160 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5161 if(FAILED(hr)) {
5162 IWineD3DVolume_UnlockBox(pSourceVolume);
5163 return hr;
5166 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5168 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5169 if(FAILED(hr)) {
5170 IWineD3DVolume_UnlockBox(pSourceVolume);
5171 } else {
5172 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5174 return hr;
5177 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5178 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5180 HRESULT hr = WINED3D_OK;
5181 WINED3DRESOURCETYPE sourceType;
5182 WINED3DRESOURCETYPE destinationType;
5183 int i ,levels;
5185 /* TODO: think about moving the code into IWineD3DBaseTexture */
5187 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5189 /* verify that the source and destination textures aren't NULL */
5190 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5191 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5192 This, pSourceTexture, pDestinationTexture);
5193 hr = WINED3DERR_INVALIDCALL;
5196 if (pSourceTexture == pDestinationTexture) {
5197 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5198 This, pSourceTexture, pDestinationTexture);
5199 hr = WINED3DERR_INVALIDCALL;
5201 /* Verify that the source and destination textures are the same type */
5202 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5203 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5205 if (sourceType != destinationType) {
5206 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5207 This);
5208 hr = WINED3DERR_INVALIDCALL;
5211 /* check that both textures have the identical numbers of levels */
5212 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5213 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5214 hr = WINED3DERR_INVALIDCALL;
5217 if (WINED3D_OK == hr) {
5219 /* Make sure that the destination texture is loaded */
5220 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5222 /* Update every surface level of the texture */
5223 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5225 switch (sourceType) {
5226 case WINED3DRTYPE_TEXTURE:
5228 IWineD3DSurface *srcSurface;
5229 IWineD3DSurface *destSurface;
5231 for (i = 0 ; i < levels ; ++i) {
5232 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5233 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5234 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5235 IWineD3DSurface_Release(srcSurface);
5236 IWineD3DSurface_Release(destSurface);
5237 if (WINED3D_OK != hr) {
5238 WARN("(%p) : Call to update surface failed\n", This);
5239 return hr;
5243 break;
5244 case WINED3DRTYPE_CUBETEXTURE:
5246 IWineD3DSurface *srcSurface;
5247 IWineD3DSurface *destSurface;
5248 WINED3DCUBEMAP_FACES faceType;
5250 for (i = 0 ; i < levels ; ++i) {
5251 /* Update each cube face */
5252 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5253 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5254 if (WINED3D_OK != hr) {
5255 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5256 } else {
5257 TRACE("Got srcSurface %p\n", srcSurface);
5259 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5260 if (WINED3D_OK != hr) {
5261 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5262 } else {
5263 TRACE("Got desrSurface %p\n", destSurface);
5265 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5266 IWineD3DSurface_Release(srcSurface);
5267 IWineD3DSurface_Release(destSurface);
5268 if (WINED3D_OK != hr) {
5269 WARN("(%p) : Call to update surface failed\n", This);
5270 return hr;
5275 break;
5277 case WINED3DRTYPE_VOLUMETEXTURE:
5279 IWineD3DVolume *srcVolume = NULL;
5280 IWineD3DVolume *destVolume = NULL;
5282 for (i = 0 ; i < levels ; ++i) {
5283 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5284 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5285 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5286 IWineD3DVolume_Release(srcVolume);
5287 IWineD3DVolume_Release(destVolume);
5288 if (WINED3D_OK != hr) {
5289 WARN("(%p) : Call to update volume failed\n", This);
5290 return hr;
5294 break;
5296 default:
5297 FIXME("(%p) : Unsupported source and destination type\n", This);
5298 hr = WINED3DERR_INVALIDCALL;
5302 return hr;
5305 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5306 IWineD3DSwapChain *swapChain;
5307 HRESULT hr;
5308 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5309 if(hr == WINED3D_OK) {
5310 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5311 IWineD3DSwapChain_Release(swapChain);
5313 return hr;
5316 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5318 /* return a sensible default */
5319 *pNumPasses = 1;
5320 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5321 FIXME("(%p) : stub\n", This);
5322 return WINED3D_OK;
5325 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5327 int j;
5328 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5329 if (PaletteNumber >= MAX_PALETTES) {
5330 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5331 return WINED3DERR_INVALIDCALL;
5333 for (j = 0; j < 256; ++j) {
5334 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5335 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5336 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5337 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5339 TRACE("(%p) : returning\n", This);
5340 return WINED3D_OK;
5343 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5345 int j;
5346 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5347 if (PaletteNumber >= MAX_PALETTES) {
5348 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5349 return WINED3DERR_INVALIDCALL;
5351 for (j = 0; j < 256; ++j) {
5352 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5353 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5354 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5355 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5357 TRACE("(%p) : returning\n", This);
5358 return WINED3D_OK;
5361 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5363 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5364 if (PaletteNumber >= MAX_PALETTES) {
5365 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5366 return WINED3DERR_INVALIDCALL;
5368 /*TODO: stateblocks */
5369 This->currentPalette = PaletteNumber;
5370 TRACE("(%p) : returning\n", This);
5371 return WINED3D_OK;
5374 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5376 if (PaletteNumber == NULL) {
5377 WARN("(%p) : returning Invalid Call\n", This);
5378 return WINED3DERR_INVALIDCALL;
5380 /*TODO: stateblocks */
5381 *PaletteNumber = This->currentPalette;
5382 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5383 return WINED3D_OK;
5386 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5388 static BOOL showFixmes = TRUE;
5389 if (showFixmes) {
5390 FIXME("(%p) : stub\n", This);
5391 showFixmes = FALSE;
5394 This->softwareVertexProcessing = bSoftware;
5395 return WINED3D_OK;
5399 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5401 static BOOL showFixmes = TRUE;
5402 if (showFixmes) {
5403 FIXME("(%p) : stub\n", This);
5404 showFixmes = FALSE;
5406 return This->softwareVertexProcessing;
5410 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5412 IWineD3DSwapChain *swapChain;
5413 HRESULT hr;
5415 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5417 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5418 if(hr == WINED3D_OK){
5419 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5420 IWineD3DSwapChain_Release(swapChain);
5421 }else{
5422 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5424 return hr;
5428 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5430 static BOOL showfixmes = TRUE;
5431 if(nSegments != 0.0f) {
5432 if( showfixmes) {
5433 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5434 showfixmes = FALSE;
5437 return WINED3D_OK;
5440 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5442 static BOOL showfixmes = TRUE;
5443 if( showfixmes) {
5444 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5445 showfixmes = FALSE;
5447 return 0.0f;
5450 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5452 /** TODO: remove casts to IWineD3DSurfaceImpl
5453 * NOTE: move code to surface to accomplish this
5454 ****************************************/
5455 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5456 int srcWidth, srcHeight;
5457 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5458 WINED3DFORMAT destFormat, srcFormat;
5459 UINT destSize;
5460 int srcLeft, destLeft, destTop;
5461 WINED3DPOOL srcPool, destPool;
5462 int offset = 0;
5463 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5464 glDescriptor *glDescription = NULL;
5465 GLenum dummy;
5466 int bpp;
5467 CONVERT_TYPES convert = NO_CONVERSION;
5469 WINED3DSURFACE_DESC winedesc;
5471 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5472 memset(&winedesc, 0, sizeof(winedesc));
5473 winedesc.Width = &srcSurfaceWidth;
5474 winedesc.Height = &srcSurfaceHeight;
5475 winedesc.Pool = &srcPool;
5476 winedesc.Format = &srcFormat;
5478 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5480 winedesc.Width = &destSurfaceWidth;
5481 winedesc.Height = &destSurfaceHeight;
5482 winedesc.Pool = &destPool;
5483 winedesc.Format = &destFormat;
5484 winedesc.Size = &destSize;
5486 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5488 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5489 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5490 return WINED3DERR_INVALIDCALL;
5493 /* This call loads the opengl surface directly, instead of copying the surface to the
5494 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5495 * copy in sysmem and use regular surface loading.
5497 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5498 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5499 if(convert != NO_CONVERSION) {
5500 return IWineD3DSurface_BltFast(pDestinationSurface,
5501 pDestPoint ? pDestPoint->x : 0,
5502 pDestPoint ? pDestPoint->y : 0,
5503 pSourceSurface, (RECT *) pSourceRect, 0);
5506 if (destFormat == WINED3DFMT_UNKNOWN) {
5507 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5508 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5510 /* Get the update surface description */
5511 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5514 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5516 ENTER_GL();
5518 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5519 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5520 checkGLcall("glActiveTextureARB");
5523 /* Make sure the surface is loaded and up to date */
5524 IWineD3DSurface_PreLoad(pDestinationSurface);
5526 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5528 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5529 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5530 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5531 srcLeft = pSourceRect ? pSourceRect->left : 0;
5532 destLeft = pDestPoint ? pDestPoint->x : 0;
5533 destTop = pDestPoint ? pDestPoint->y : 0;
5536 /* This function doesn't support compressed textures
5537 the pitch is just bytesPerPixel * width */
5538 if(srcWidth != srcSurfaceWidth || srcLeft ){
5539 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5540 offset += srcLeft * pSrcSurface->bytesPerPixel;
5541 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5543 /* TODO DXT formats */
5545 if(pSourceRect != NULL && pSourceRect->top != 0){
5546 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5548 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5549 ,This
5550 ,glDescription->level
5551 ,destLeft
5552 ,destTop
5553 ,srcWidth
5554 ,srcHeight
5555 ,glDescription->glFormat
5556 ,glDescription->glType
5557 ,IWineD3DSurface_GetData(pSourceSurface)
5560 /* Sanity check */
5561 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5563 /* need to lock the surface to get the data */
5564 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5567 /* TODO: Cube and volume support */
5568 if(rowoffset != 0){
5569 /* not a whole row so we have to do it a line at a time */
5570 int j;
5572 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5573 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5575 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5577 glTexSubImage2D(glDescription->target
5578 ,glDescription->level
5579 ,destLeft
5581 ,srcWidth
5583 ,glDescription->glFormat
5584 ,glDescription->glType
5585 ,data /* could be quicker using */
5587 data += rowoffset;
5590 } else { /* Full width, so just write out the whole texture */
5592 if (WINED3DFMT_DXT1 == destFormat ||
5593 WINED3DFMT_DXT2 == destFormat ||
5594 WINED3DFMT_DXT3 == destFormat ||
5595 WINED3DFMT_DXT4 == destFormat ||
5596 WINED3DFMT_DXT5 == destFormat) {
5597 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5598 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5599 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5600 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5601 } if (destFormat != srcFormat) {
5602 FIXME("Updating mixed format compressed texture is not curretly support\n");
5603 } else {
5604 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5605 glDescription->level,
5606 glDescription->glFormatInternal,
5607 srcWidth,
5608 srcHeight,
5610 destSize,
5611 IWineD3DSurface_GetData(pSourceSurface));
5613 } else {
5614 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5618 } else {
5619 glTexSubImage2D(glDescription->target
5620 ,glDescription->level
5621 ,destLeft
5622 ,destTop
5623 ,srcWidth
5624 ,srcHeight
5625 ,glDescription->glFormat
5626 ,glDescription->glType
5627 ,IWineD3DSurface_GetData(pSourceSurface)
5631 checkGLcall("glTexSubImage2D");
5633 LEAVE_GL();
5635 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5638 return WINED3D_OK;
5641 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5643 struct WineD3DRectPatch *patch;
5644 unsigned int i;
5645 struct list *e;
5646 BOOL found;
5647 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5649 if(!(Handle || pRectPatchInfo)) {
5650 /* TODO: Write a test for the return value, thus the FIXME */
5651 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5652 return WINED3DERR_INVALIDCALL;
5655 if(Handle) {
5656 i = PATCHMAP_HASHFUNC(Handle);
5657 found = FALSE;
5658 LIST_FOR_EACH(e, &This->patches[i]) {
5659 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5660 if(patch->Handle == Handle) {
5661 found = TRUE;
5662 break;
5666 if(!found) {
5667 TRACE("Patch does not exist. Creating a new one\n");
5668 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5669 patch->Handle = Handle;
5670 list_add_head(&This->patches[i], &patch->entry);
5671 } else {
5672 TRACE("Found existing patch %p\n", patch);
5674 } else {
5675 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5676 * attributes we have to tesselate, read back, and draw. This needs a patch
5677 * management structure instance. Create one.
5679 * A possible improvement is to check if a vertex shader is used, and if not directly
5680 * draw the patch.
5682 FIXME("Drawing an uncached patch. This is slow\n");
5683 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5686 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5687 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5688 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5689 HRESULT hr;
5690 TRACE("Tesselation density or patch info changed, retesselating\n");
5692 if(pRectPatchInfo) {
5693 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5695 patch->numSegs[0] = pNumSegs[0];
5696 patch->numSegs[1] = pNumSegs[1];
5697 patch->numSegs[2] = pNumSegs[2];
5698 patch->numSegs[3] = pNumSegs[3];
5700 hr = tesselate_rectpatch(This, patch);
5701 if(FAILED(hr)) {
5702 WARN("Patch tesselation failed\n");
5704 /* Do not release the handle to store the params of the patch */
5705 if(!Handle) {
5706 HeapFree(GetProcessHeap(), 0, patch);
5708 return hr;
5712 This->currentPatch = patch;
5713 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5714 This->currentPatch = NULL;
5716 /* Destroy uncached patches */
5717 if(!Handle) {
5718 HeapFree(GetProcessHeap(), 0, patch->mem);
5719 HeapFree(GetProcessHeap(), 0, patch);
5721 return WINED3D_OK;
5724 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5725 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5727 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5728 FIXME("(%p) : Stub\n", This);
5729 return WINED3D_OK;
5732 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5734 int i;
5735 struct WineD3DRectPatch *patch;
5736 struct list *e;
5737 TRACE("(%p) Handle(%d)\n", This, Handle);
5739 i = PATCHMAP_HASHFUNC(Handle);
5740 LIST_FOR_EACH(e, &This->patches[i]) {
5741 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5742 if(patch->Handle == Handle) {
5743 TRACE("Deleting patch %p\n", patch);
5744 list_remove(&patch->entry);
5745 HeapFree(GetProcessHeap(), 0, patch->mem);
5746 HeapFree(GetProcessHeap(), 0, patch);
5747 return WINED3D_OK;
5751 /* TODO: Write a test for the return value */
5752 FIXME("Attempt to destroy nonexistent patch\n");
5753 return WINED3DERR_INVALIDCALL;
5756 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5757 HRESULT hr;
5758 IWineD3DSwapChain *swapchain;
5760 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5761 if (SUCCEEDED(hr)) {
5762 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5763 return swapchain;
5766 return NULL;
5769 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5772 if (!*fbo) {
5773 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5774 checkGLcall("glGenFramebuffersEXT()");
5776 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5777 checkGLcall("glBindFramebuffer()");
5780 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5781 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5782 IWineD3DBaseTextureImpl *texture_impl;
5783 GLenum texttarget, target;
5784 GLint old_binding;
5786 texttarget = surface_impl->glDescription.target;
5787 if(texttarget == GL_TEXTURE_2D) {
5788 target = GL_TEXTURE_2D;
5789 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5790 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5791 target = GL_TEXTURE_RECTANGLE_ARB;
5792 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5793 } else {
5794 target = GL_TEXTURE_CUBE_MAP_ARB;
5795 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5798 IWineD3DSurface_PreLoad(surface);
5800 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5801 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5802 glBindTexture(target, old_binding);
5804 /* Update base texture states array */
5805 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5806 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5807 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5808 if (texture_impl->baseTexture.bindCount) {
5809 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5812 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5815 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5816 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5818 checkGLcall("attach_surface_fbo");
5821 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5823 IWineD3DSwapChain *swapchain;
5825 swapchain = get_swapchain(surface);
5826 if (swapchain) {
5827 GLenum buffer;
5829 TRACE("Surface %p is onscreen\n", surface);
5831 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5832 buffer = surface_get_gl_buffer(surface, swapchain);
5833 glDrawBuffer(buffer);
5834 checkGLcall("glDrawBuffer()");
5835 } else {
5836 TRACE("Surface %p is offscreen\n", surface);
5837 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5838 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5841 if (rect) {
5842 glEnable(GL_SCISSOR_TEST);
5843 if(!swapchain) {
5844 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5845 } else {
5846 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5847 rect->x2 - rect->x1, rect->y2 - rect->y1);
5849 checkGLcall("glScissor");
5850 } else {
5851 glDisable(GL_SCISSOR_TEST);
5853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5855 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5858 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5859 glClear(GL_COLOR_BUFFER_BIT);
5860 checkGLcall("glClear");
5862 if (This->render_offscreen) {
5863 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5864 } else {
5865 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5866 checkGLcall("glBindFramebuffer()");
5869 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5870 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5871 glDrawBuffer(GL_BACK);
5872 checkGLcall("glDrawBuffer()");
5876 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5877 unsigned int r, g, b, a;
5878 DWORD ret;
5880 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5881 destfmt == WINED3DFMT_R8G8B8)
5882 return color;
5884 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5886 a = (color & 0xff000000) >> 24;
5887 r = (color & 0x00ff0000) >> 16;
5888 g = (color & 0x0000ff00) >> 8;
5889 b = (color & 0x000000ff) >> 0;
5891 switch(destfmt)
5893 case WINED3DFMT_R5G6B5:
5894 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5895 r = (r * 32) / 256;
5896 g = (g * 64) / 256;
5897 b = (b * 32) / 256;
5898 ret = r << 11;
5899 ret |= g << 5;
5900 ret |= b;
5901 TRACE("Returning %08x\n", ret);
5902 return ret;
5904 case WINED3DFMT_X1R5G5B5:
5905 case WINED3DFMT_A1R5G5B5:
5906 a = (a * 2) / 256;
5907 r = (r * 32) / 256;
5908 g = (g * 32) / 256;
5909 b = (b * 32) / 256;
5910 ret = a << 15;
5911 ret |= r << 10;
5912 ret |= g << 5;
5913 ret |= b << 0;
5914 TRACE("Returning %08x\n", ret);
5915 return ret;
5917 case WINED3DFMT_A8:
5918 TRACE("Returning %08x\n", a);
5919 return a;
5921 case WINED3DFMT_X4R4G4B4:
5922 case WINED3DFMT_A4R4G4B4:
5923 a = (a * 16) / 256;
5924 r = (r * 16) / 256;
5925 g = (g * 16) / 256;
5926 b = (b * 16) / 256;
5927 ret = a << 12;
5928 ret |= r << 8;
5929 ret |= g << 4;
5930 ret |= b << 0;
5931 TRACE("Returning %08x\n", ret);
5932 return ret;
5934 case WINED3DFMT_R3G3B2:
5935 r = (r * 8) / 256;
5936 g = (g * 8) / 256;
5937 b = (b * 4) / 256;
5938 ret = r << 5;
5939 ret |= g << 2;
5940 ret |= b << 0;
5941 TRACE("Returning %08x\n", ret);
5942 return ret;
5944 case WINED3DFMT_X8B8G8R8:
5945 case WINED3DFMT_A8B8G8R8:
5946 ret = a << 24;
5947 ret |= b << 16;
5948 ret |= g << 8;
5949 ret |= r << 0;
5950 TRACE("Returning %08x\n", ret);
5951 return ret;
5953 case WINED3DFMT_A2R10G10B10:
5954 a = (a * 4) / 256;
5955 r = (r * 1024) / 256;
5956 g = (g * 1024) / 256;
5957 b = (b * 1024) / 256;
5958 ret = a << 30;
5959 ret |= r << 20;
5960 ret |= g << 10;
5961 ret |= b << 0;
5962 TRACE("Returning %08x\n", ret);
5963 return ret;
5965 case WINED3DFMT_A2B10G10R10:
5966 a = (a * 4) / 256;
5967 r = (r * 1024) / 256;
5968 g = (g * 1024) / 256;
5969 b = (b * 1024) / 256;
5970 ret = a << 30;
5971 ret |= b << 20;
5972 ret |= g << 10;
5973 ret |= r << 0;
5974 TRACE("Returning %08x\n", ret);
5975 return ret;
5977 default:
5978 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5979 return 0;
5983 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5984 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5985 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5986 WINEDDBLTFX BltFx;
5987 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5989 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5990 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5991 return WINED3DERR_INVALIDCALL;
5994 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5995 color_fill_fbo(iface, pSurface, pRect, color);
5996 return WINED3D_OK;
5997 } else {
5998 /* Just forward this to the DirectDraw blitting engine */
5999 memset(&BltFx, 0, sizeof(BltFx));
6000 BltFx.dwSize = sizeof(BltFx);
6001 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6002 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6006 /* rendertarget and deptth stencil functions */
6007 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6010 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6011 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6012 return WINED3DERR_INVALIDCALL;
6015 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6016 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6017 /* Note inc ref on returned surface */
6018 if(*ppRenderTarget != NULL)
6019 IWineD3DSurface_AddRef(*ppRenderTarget);
6020 return WINED3D_OK;
6023 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6025 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6026 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6027 IWineD3DSwapChainImpl *Swapchain;
6028 HRESULT hr;
6030 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6032 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6033 if(hr != WINED3D_OK) {
6034 ERR("Can't get the swapchain\n");
6035 return hr;
6038 /* Make sure to release the swapchain */
6039 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6041 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6042 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6043 return WINED3DERR_INVALIDCALL;
6045 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6046 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6047 return WINED3DERR_INVALIDCALL;
6050 if(Swapchain->frontBuffer != Front) {
6051 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6053 if(Swapchain->frontBuffer)
6054 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6055 Swapchain->frontBuffer = Front;
6057 if(Swapchain->frontBuffer) {
6058 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6062 if(Back && !Swapchain->backBuffer) {
6063 /* We need memory for the back buffer array - only one back buffer this way */
6064 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6065 if(!Swapchain->backBuffer) {
6066 ERR("Out of memory\n");
6067 return E_OUTOFMEMORY;
6071 if(Swapchain->backBuffer[0] != Back) {
6072 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6074 /* What to do about the context here in the case of multithreading? Not sure.
6075 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6077 ENTER_GL();
6078 if(!Swapchain->backBuffer[0]) {
6079 /* GL was told to draw to the front buffer at creation,
6080 * undo that
6082 glDrawBuffer(GL_BACK);
6083 checkGLcall("glDrawBuffer(GL_BACK)");
6084 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6085 Swapchain->presentParms.BackBufferCount = 1;
6086 } else if (!Back) {
6087 /* That makes problems - disable for now */
6088 /* glDrawBuffer(GL_FRONT); */
6089 checkGLcall("glDrawBuffer(GL_FRONT)");
6090 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6091 Swapchain->presentParms.BackBufferCount = 0;
6093 LEAVE_GL();
6095 if(Swapchain->backBuffer[0])
6096 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6097 Swapchain->backBuffer[0] = Back;
6099 if(Swapchain->backBuffer[0]) {
6100 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6101 } else {
6102 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6103 Swapchain->backBuffer = NULL;
6108 return WINED3D_OK;
6111 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6113 *ppZStencilSurface = This->stencilBufferTarget;
6114 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6116 if(*ppZStencilSurface != NULL) {
6117 /* Note inc ref on returned surface */
6118 IWineD3DSurface_AddRef(*ppZStencilSurface);
6119 return WINED3D_OK;
6120 } else {
6121 return WINED3DERR_NOTFOUND;
6125 /* TODO: Handle stencil attachments */
6126 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6128 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6130 TRACE("Set depth stencil to %p\n", depth_stencil);
6132 if (depth_stencil_impl) {
6133 if (depth_stencil_impl->current_renderbuffer) {
6134 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6135 checkGLcall("glFramebufferRenderbufferEXT()");
6136 } else {
6137 IWineD3DBaseTextureImpl *texture_impl;
6138 GLenum texttarget, target;
6139 GLint old_binding = 0;
6141 texttarget = depth_stencil_impl->glDescription.target;
6142 if(texttarget == GL_TEXTURE_2D) {
6143 target = GL_TEXTURE_2D;
6144 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6145 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6146 target = GL_TEXTURE_RECTANGLE_ARB;
6147 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6148 } else {
6149 target = GL_TEXTURE_CUBE_MAP_ARB;
6150 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6153 IWineD3DSurface_PreLoad(depth_stencil);
6155 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6156 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6157 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6158 glBindTexture(target, old_binding);
6160 /* Update base texture states array */
6161 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6162 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6163 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6164 if (texture_impl->baseTexture.bindCount) {
6165 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6168 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6171 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6172 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6173 checkGLcall("glFramebufferTexture2DEXT()");
6175 } else {
6176 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6177 checkGLcall("glFramebufferTexture2DEXT()");
6181 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6183 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6185 TRACE("Set render target %u to %p\n", idx, render_target);
6187 if (rtimpl) {
6188 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6189 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6190 } else {
6191 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6192 checkGLcall("glFramebufferTexture2DEXT()");
6194 This->draw_buffers[idx] = GL_NONE;
6198 static void check_fbo_status(IWineD3DDevice *iface) {
6199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6200 GLenum status;
6202 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6203 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6204 TRACE("FBO complete\n");
6205 } else {
6206 IWineD3DSurfaceImpl *attachment;
6207 int i;
6208 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6210 /* Dump the FBO attachments */
6211 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6212 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6213 if (attachment) {
6214 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6215 attachment->pow2Width, attachment->pow2Height);
6218 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6219 if (attachment) {
6220 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6221 attachment->pow2Width, attachment->pow2Height);
6226 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6228 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6229 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6231 if (!ds_impl) return FALSE;
6233 if (ds_impl->current_renderbuffer) {
6234 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6235 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6238 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6239 rt_impl->pow2Height != ds_impl->pow2Height);
6242 void apply_fbo_state(IWineD3DDevice *iface) {
6243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6244 unsigned int i;
6246 if (This->render_offscreen) {
6247 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6249 /* Apply render targets */
6250 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6251 IWineD3DSurface *render_target = This->render_targets[i];
6252 if (This->fbo_color_attachments[i] != render_target) {
6253 set_render_target_fbo(iface, i, render_target);
6254 This->fbo_color_attachments[i] = render_target;
6258 /* Apply depth targets */
6259 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6260 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6261 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6263 if (This->stencilBufferTarget) {
6264 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6266 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6267 This->fbo_depth_attachment = This->stencilBufferTarget;
6270 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6271 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6272 checkGLcall("glDrawBuffers()");
6273 } else {
6274 glDrawBuffer(This->draw_buffers[0]);
6275 checkGLcall("glDrawBuffer()");
6277 } else {
6278 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6281 check_fbo_status(iface);
6284 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6285 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6287 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6288 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6289 GLenum gl_filter;
6291 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6292 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6293 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6294 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6296 switch (filter) {
6297 case WINED3DTEXF_LINEAR:
6298 gl_filter = GL_LINEAR;
6299 break;
6301 default:
6302 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6303 case WINED3DTEXF_NONE:
6304 case WINED3DTEXF_POINT:
6305 gl_filter = GL_NEAREST;
6306 break;
6309 /* Attach src surface to src fbo */
6310 src_swapchain = get_swapchain(src_surface);
6311 if (src_swapchain) {
6312 GLenum buffer;
6314 TRACE("Source surface %p is onscreen\n", src_surface);
6315 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6316 /* Make sure the drawable is up to date. In the offscreen case
6317 * attach_surface_fbo() implicitly takes care of this. */
6318 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6320 ENTER_GL();
6321 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6322 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6323 glReadBuffer(buffer);
6324 checkGLcall("glReadBuffer()");
6326 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6327 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6328 } else {
6329 TRACE("Source surface %p is offscreen\n", src_surface);
6330 ENTER_GL();
6331 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6332 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6333 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6334 checkGLcall("glReadBuffer()");
6336 LEAVE_GL();
6338 /* Attach dst surface to dst fbo */
6339 dst_swapchain = get_swapchain(dst_surface);
6340 if (dst_swapchain) {
6341 GLenum buffer;
6343 TRACE("Destination surface %p is onscreen\n", dst_surface);
6344 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6345 /* Make sure the drawable is up to date. In the offscreen case
6346 * attach_surface_fbo() implicitly takes care of this. */
6347 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6349 ENTER_GL();
6350 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6351 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6352 glDrawBuffer(buffer);
6353 checkGLcall("glDrawBuffer()");
6355 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6356 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6357 } else {
6358 TRACE("Destination surface %p is offscreen\n", dst_surface);
6360 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6361 if(!src_swapchain) {
6362 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6365 ENTER_GL();
6366 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6367 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6368 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6369 checkGLcall("glDrawBuffer()");
6371 glDisable(GL_SCISSOR_TEST);
6372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6374 if (flip) {
6375 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6376 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6377 checkGLcall("glBlitFramebuffer()");
6378 } else {
6379 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6380 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6381 checkGLcall("glBlitFramebuffer()");
6384 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6386 if (This->render_offscreen) {
6387 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6388 } else {
6389 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6390 checkGLcall("glBindFramebuffer()");
6393 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6394 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6395 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6396 glDrawBuffer(GL_BACK);
6397 checkGLcall("glDrawBuffer()");
6399 LEAVE_GL();
6402 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6404 WINED3DVIEWPORT viewport;
6406 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6408 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6409 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6410 This, RenderTargetIndex, GL_LIMITS(buffers));
6411 return WINED3DERR_INVALIDCALL;
6414 /* MSDN says that null disables the render target
6415 but a device must always be associated with a render target
6416 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6418 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6419 for more details
6421 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6422 FIXME("Trying to set render target 0 to NULL\n");
6423 return WINED3DERR_INVALIDCALL;
6425 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6426 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);
6427 return WINED3DERR_INVALIDCALL;
6430 /* If we are trying to set what we already have, don't bother */
6431 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6432 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6433 return WINED3D_OK;
6435 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6436 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6437 This->render_targets[RenderTargetIndex] = pRenderTarget;
6439 /* Render target 0 is special */
6440 if(RenderTargetIndex == 0) {
6441 /* Finally, reset the viewport as the MSDN states. */
6442 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6443 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6444 viewport.X = 0;
6445 viewport.Y = 0;
6446 viewport.MaxZ = 1.0f;
6447 viewport.MinZ = 0.0f;
6448 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6449 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6450 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6452 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6454 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6455 * ctx properly.
6456 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6457 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6459 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6461 return WINED3D_OK;
6464 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6466 HRESULT hr = WINED3D_OK;
6467 IWineD3DSurface *tmp;
6469 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6471 if (pNewZStencil == This->stencilBufferTarget) {
6472 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6473 } else {
6474 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6475 * depending on the renter target implementation being used.
6476 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6477 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6478 * stencil buffer and incure an extra memory overhead
6479 ******************************************************/
6481 tmp = This->stencilBufferTarget;
6482 This->stencilBufferTarget = pNewZStencil;
6483 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6484 /* should we be calling the parent or the wined3d surface? */
6485 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6486 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6487 hr = WINED3D_OK;
6489 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6490 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6492 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6497 return hr;
6500 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6501 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6503 /* TODO: the use of Impl is deprecated. */
6504 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6505 WINED3DLOCKED_RECT lockedRect;
6507 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6509 /* some basic validation checks */
6510 if(This->cursorTexture) {
6511 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6512 ENTER_GL();
6513 glDeleteTextures(1, &This->cursorTexture);
6514 LEAVE_GL();
6515 This->cursorTexture = 0;
6518 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6519 This->haveHardwareCursor = TRUE;
6520 else
6521 This->haveHardwareCursor = FALSE;
6523 if(pCursorBitmap) {
6524 WINED3DLOCKED_RECT rect;
6526 /* MSDN: Cursor must be A8R8G8B8 */
6527 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6528 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6529 return WINED3DERR_INVALIDCALL;
6532 /* MSDN: Cursor must be smaller than the display mode */
6533 if(pSur->currentDesc.Width > This->ddraw_width ||
6534 pSur->currentDesc.Height > This->ddraw_height) {
6535 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);
6536 return WINED3DERR_INVALIDCALL;
6539 if (!This->haveHardwareCursor) {
6540 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6542 /* Do not store the surface's pointer because the application may
6543 * release it after setting the cursor image. Windows doesn't
6544 * addref the set surface, so we can't do this either without
6545 * creating circular refcount dependencies. Copy out the gl texture
6546 * instead.
6548 This->cursorWidth = pSur->currentDesc.Width;
6549 This->cursorHeight = pSur->currentDesc.Height;
6550 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6552 const GlPixelFormatDesc *glDesc;
6553 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6554 char *mem, *bits = (char *)rect.pBits;
6555 GLint intfmt = glDesc->glInternal;
6556 GLint format = glDesc->glFormat;
6557 GLint type = glDesc->glType;
6558 INT height = This->cursorHeight;
6559 INT width = This->cursorWidth;
6560 INT bpp = tableEntry->bpp;
6561 INT i;
6563 /* Reformat the texture memory (pitch and width can be
6564 * different) */
6565 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6566 for(i = 0; i < height; i++)
6567 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6568 IWineD3DSurface_UnlockRect(pCursorBitmap);
6569 ENTER_GL();
6571 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6572 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6573 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6576 /* Make sure that a proper texture unit is selected */
6577 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6578 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6579 checkGLcall("glActiveTextureARB");
6581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6582 /* Create a new cursor texture */
6583 glGenTextures(1, &This->cursorTexture);
6584 checkGLcall("glGenTextures");
6585 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6586 checkGLcall("glBindTexture");
6587 /* Copy the bitmap memory into the cursor texture */
6588 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6589 HeapFree(GetProcessHeap(), 0, mem);
6590 checkGLcall("glTexImage2D");
6592 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6593 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6594 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6597 LEAVE_GL();
6599 else
6601 FIXME("A cursor texture was not returned.\n");
6602 This->cursorTexture = 0;
6605 else
6607 /* Draw a hardware cursor */
6608 ICONINFO cursorInfo;
6609 HCURSOR cursor;
6610 /* Create and clear maskBits because it is not needed for
6611 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6612 * chunks. */
6613 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6614 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6615 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6616 WINED3DLOCK_NO_DIRTY_UPDATE |
6617 WINED3DLOCK_READONLY
6619 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6620 pSur->currentDesc.Height);
6622 cursorInfo.fIcon = FALSE;
6623 cursorInfo.xHotspot = XHotSpot;
6624 cursorInfo.yHotspot = YHotSpot;
6625 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6626 pSur->currentDesc.Height, 1,
6627 1, &maskBits);
6628 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6629 pSur->currentDesc.Height, 1,
6630 32, lockedRect.pBits);
6631 IWineD3DSurface_UnlockRect(pCursorBitmap);
6632 /* Create our cursor and clean up. */
6633 cursor = CreateIconIndirect(&cursorInfo);
6634 SetCursor(cursor);
6635 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6636 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6637 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6638 This->hardwareCursor = cursor;
6639 HeapFree(GetProcessHeap(), 0, maskBits);
6643 This->xHotSpot = XHotSpot;
6644 This->yHotSpot = YHotSpot;
6645 return WINED3D_OK;
6648 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6650 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6652 This->xScreenSpace = XScreenSpace;
6653 This->yScreenSpace = YScreenSpace;
6655 return;
6659 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6661 BOOL oldVisible = This->bCursorVisible;
6662 POINT pt;
6664 TRACE("(%p) : visible(%d)\n", This, bShow);
6667 * When ShowCursor is first called it should make the cursor appear at the OS's last
6668 * known cursor position. Because of this, some applications just repetitively call
6669 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6671 GetCursorPos(&pt);
6672 This->xScreenSpace = pt.x;
6673 This->yScreenSpace = pt.y;
6675 if (This->haveHardwareCursor) {
6676 This->bCursorVisible = bShow;
6677 if (bShow)
6678 SetCursor(This->hardwareCursor);
6679 else
6680 SetCursor(NULL);
6682 else
6684 if (This->cursorTexture)
6685 This->bCursorVisible = bShow;
6688 return oldVisible;
6691 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6693 IWineD3DResourceImpl *resource;
6694 TRACE("(%p) : state (%u)\n", This, This->state);
6696 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6697 switch (This->state) {
6698 case WINED3D_OK:
6699 return WINED3D_OK;
6700 case WINED3DERR_DEVICELOST:
6702 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6703 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6704 return WINED3DERR_DEVICENOTRESET;
6706 return WINED3DERR_DEVICELOST;
6708 case WINED3DERR_DRIVERINTERNALERROR:
6709 return WINED3DERR_DRIVERINTERNALERROR;
6712 /* Unknown state */
6713 return WINED3DERR_DRIVERINTERNALERROR;
6717 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6719 /** FIXME: Resource tracking needs to be done,
6720 * The closes we can do to this is set the priorities of all managed textures low
6721 * and then reset them.
6722 ***********************************************************/
6723 FIXME("(%p) : stub\n", This);
6724 return WINED3D_OK;
6727 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6728 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6730 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6731 if(surface->Flags & SFLAG_DIBSECTION) {
6732 /* Release the DC */
6733 SelectObject(surface->hDC, surface->dib.holdbitmap);
6734 DeleteDC(surface->hDC);
6735 /* Release the DIB section */
6736 DeleteObject(surface->dib.DIBsection);
6737 surface->dib.bitmap_data = NULL;
6738 surface->resource.allocatedMemory = NULL;
6739 surface->Flags &= ~SFLAG_DIBSECTION;
6741 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6742 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6743 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6744 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6745 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6746 } else {
6747 surface->pow2Width = surface->pow2Height = 1;
6748 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6749 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6751 if(surface->glDescription.textureName) {
6752 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6753 ENTER_GL();
6754 glDeleteTextures(1, &surface->glDescription.textureName);
6755 LEAVE_GL();
6756 surface->glDescription.textureName = 0;
6757 surface->Flags &= ~SFLAG_CLIENT;
6759 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6760 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6761 surface->Flags |= SFLAG_NONPOW2;
6762 } else {
6763 surface->Flags &= ~SFLAG_NONPOW2;
6765 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6766 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6769 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6771 IWineD3DSwapChainImpl *swapchain;
6772 HRESULT hr;
6773 BOOL DisplayModeChanged = FALSE;
6774 WINED3DDISPLAYMODE mode;
6775 TRACE("(%p)\n", This);
6777 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6778 if(FAILED(hr)) {
6779 ERR("Failed to get the first implicit swapchain\n");
6780 return hr;
6783 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6784 * on an existing gl context, so there's no real need for recreation.
6786 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6788 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6790 TRACE("New params:\n");
6791 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6792 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6793 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6794 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6795 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6796 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6797 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6798 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6799 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6800 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6801 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6802 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6803 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6805 /* No special treatment of these parameters. Just store them */
6806 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6807 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6808 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6809 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6811 /* What to do about these? */
6812 if(pPresentationParameters->BackBufferCount != 0 &&
6813 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6814 ERR("Cannot change the back buffer count yet\n");
6816 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6817 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6818 ERR("Cannot change the back buffer format yet\n");
6820 if(pPresentationParameters->hDeviceWindow != NULL &&
6821 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6822 ERR("Cannot change the device window yet\n");
6824 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6825 ERR("What do do about a changed auto depth stencil parameter?\n");
6828 if(pPresentationParameters->Windowed) {
6829 mode.Width = swapchain->orig_width;
6830 mode.Height = swapchain->orig_height;
6831 mode.RefreshRate = 0;
6832 mode.Format = swapchain->presentParms.BackBufferFormat;
6833 } else {
6834 mode.Width = pPresentationParameters->BackBufferWidth;
6835 mode.Height = pPresentationParameters->BackBufferHeight;
6836 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6837 mode.Format = swapchain->presentParms.BackBufferFormat;
6840 /* Should Width == 800 && Height == 0 set 800x600? */
6841 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6842 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6843 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6845 WINED3DVIEWPORT vp;
6846 int i;
6848 vp.X = 0;
6849 vp.Y = 0;
6850 vp.Width = pPresentationParameters->BackBufferWidth;
6851 vp.Height = pPresentationParameters->BackBufferHeight;
6852 vp.MinZ = 0;
6853 vp.MaxZ = 1;
6855 if(!pPresentationParameters->Windowed) {
6856 DisplayModeChanged = TRUE;
6858 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6859 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6861 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6862 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6863 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6866 /* Now set the new viewport */
6867 IWineD3DDevice_SetViewport(iface, &vp);
6870 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6871 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6872 DisplayModeChanged) {
6874 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6875 if(!pPresentationParameters->Windowed) {
6876 IWineD3DDevice_SetFullscreen(iface, TRUE);
6879 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6881 /* Switching out of fullscreen mode? First set the original res, then change the window */
6882 if(pPresentationParameters->Windowed) {
6883 IWineD3DDevice_SetFullscreen(iface, FALSE);
6885 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6888 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6889 return WINED3D_OK;
6892 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6894 /** FIXME: always true at the moment **/
6895 if(!bEnableDialogs) {
6896 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6898 return WINED3D_OK;
6902 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6904 TRACE("(%p) : pParameters %p\n", This, pParameters);
6906 *pParameters = This->createParms;
6907 return WINED3D_OK;
6910 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6911 IWineD3DSwapChain *swapchain;
6912 HRESULT hrc = WINED3D_OK;
6914 TRACE("Relaying to swapchain\n");
6916 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6917 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6918 IWineD3DSwapChain_Release(swapchain);
6920 return;
6923 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6924 IWineD3DSwapChain *swapchain;
6925 HRESULT hrc = WINED3D_OK;
6927 TRACE("Relaying to swapchain\n");
6929 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6930 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6931 IWineD3DSwapChain_Release(swapchain);
6933 return;
6937 /** ********************************************************
6938 * Notification functions
6939 ** ********************************************************/
6940 /** This function must be called in the release of a resource when ref == 0,
6941 * the contents of resource must still be correct,
6942 * any handels to other resource held by the caller must be closed
6943 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6944 *****************************************************/
6945 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6948 TRACE("(%p) : Adding Resource %p\n", This, resource);
6949 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6952 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6955 TRACE("(%p) : Removing resource %p\n", This, resource);
6957 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6961 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6963 int counter;
6965 TRACE("(%p) : resource %p\n", This, resource);
6966 switch(IWineD3DResource_GetType(resource)){
6967 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6968 case WINED3DRTYPE_SURFACE: {
6969 unsigned int i;
6971 /* Cleanup any FBO attachments if d3d is enabled */
6972 if(This->d3d_initialized) {
6973 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
6974 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
6976 TRACE("Last active render target destroyed\n");
6977 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
6978 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
6979 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
6980 * and the lastActiveRenderTarget member shouldn't matter
6982 if(swapchain) {
6983 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
6984 TRACE("Activating primary back buffer\n");
6985 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
6986 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
6987 /* Single buffering environment */
6988 TRACE("Activating primary front buffer\n");
6989 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
6990 } else {
6991 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
6992 /* Implicit render target destroyed, that means the device is being destroyed
6993 * whatever we set here, it shouldn't matter
6995 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
6997 } else {
6998 /* May happen during ddraw uninitialization */
6999 TRACE("Render target set, but swapchain does not exist!\n");
7000 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7004 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7005 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7006 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7007 set_render_target_fbo(iface, i, NULL);
7008 This->fbo_color_attachments[i] = NULL;
7011 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7012 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7013 set_depth_stencil_fbo(iface, NULL);
7014 This->fbo_depth_attachment = NULL;
7018 break;
7020 case WINED3DRTYPE_TEXTURE:
7021 case WINED3DRTYPE_CUBETEXTURE:
7022 case WINED3DRTYPE_VOLUMETEXTURE:
7023 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7024 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7025 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7026 This->stateBlock->textures[counter] = NULL;
7028 if (This->updateStateBlock != This->stateBlock ){
7029 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7030 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7031 This->updateStateBlock->textures[counter] = NULL;
7035 break;
7036 case WINED3DRTYPE_VOLUME:
7037 /* TODO: nothing really? */
7038 break;
7039 case WINED3DRTYPE_VERTEXBUFFER:
7040 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7042 int streamNumber;
7043 TRACE("Cleaning up stream pointers\n");
7045 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7046 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7047 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7049 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7050 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7051 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7052 This->updateStateBlock->streamSource[streamNumber] = 0;
7053 /* Set changed flag? */
7056 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) */
7057 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7058 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7059 This->stateBlock->streamSource[streamNumber] = 0;
7062 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7063 else { /* This shouldn't happen */
7064 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7066 #endif
7070 break;
7071 case WINED3DRTYPE_INDEXBUFFER:
7072 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7073 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7074 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7075 This->updateStateBlock->pIndexData = NULL;
7078 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7079 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7080 This->stateBlock->pIndexData = NULL;
7084 break;
7085 default:
7086 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7087 break;
7091 /* Remove the resoruce from the resourceStore */
7092 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7094 TRACE("Resource released\n");
7098 /**********************************************************
7099 * IWineD3DDevice VTbl follows
7100 **********************************************************/
7102 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7104 /*** IUnknown methods ***/
7105 IWineD3DDeviceImpl_QueryInterface,
7106 IWineD3DDeviceImpl_AddRef,
7107 IWineD3DDeviceImpl_Release,
7108 /*** IWineD3DDevice methods ***/
7109 IWineD3DDeviceImpl_GetParent,
7110 /*** Creation methods**/
7111 IWineD3DDeviceImpl_CreateVertexBuffer,
7112 IWineD3DDeviceImpl_CreateIndexBuffer,
7113 IWineD3DDeviceImpl_CreateStateBlock,
7114 IWineD3DDeviceImpl_CreateSurface,
7115 IWineD3DDeviceImpl_CreateTexture,
7116 IWineD3DDeviceImpl_CreateVolumeTexture,
7117 IWineD3DDeviceImpl_CreateVolume,
7118 IWineD3DDeviceImpl_CreateCubeTexture,
7119 IWineD3DDeviceImpl_CreateQuery,
7120 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7121 IWineD3DDeviceImpl_CreateVertexDeclaration,
7122 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7123 IWineD3DDeviceImpl_CreateVertexShader,
7124 IWineD3DDeviceImpl_CreatePixelShader,
7125 IWineD3DDeviceImpl_CreatePalette,
7126 /*** Odd functions **/
7127 IWineD3DDeviceImpl_Init3D,
7128 IWineD3DDeviceImpl_Uninit3D,
7129 IWineD3DDeviceImpl_SetFullscreen,
7130 IWineD3DDeviceImpl_SetMultithreaded,
7131 IWineD3DDeviceImpl_EvictManagedResources,
7132 IWineD3DDeviceImpl_GetAvailableTextureMem,
7133 IWineD3DDeviceImpl_GetBackBuffer,
7134 IWineD3DDeviceImpl_GetCreationParameters,
7135 IWineD3DDeviceImpl_GetDeviceCaps,
7136 IWineD3DDeviceImpl_GetDirect3D,
7137 IWineD3DDeviceImpl_GetDisplayMode,
7138 IWineD3DDeviceImpl_SetDisplayMode,
7139 IWineD3DDeviceImpl_GetHWND,
7140 IWineD3DDeviceImpl_SetHWND,
7141 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7142 IWineD3DDeviceImpl_GetRasterStatus,
7143 IWineD3DDeviceImpl_GetSwapChain,
7144 IWineD3DDeviceImpl_Reset,
7145 IWineD3DDeviceImpl_SetDialogBoxMode,
7146 IWineD3DDeviceImpl_SetCursorProperties,
7147 IWineD3DDeviceImpl_SetCursorPosition,
7148 IWineD3DDeviceImpl_ShowCursor,
7149 IWineD3DDeviceImpl_TestCooperativeLevel,
7150 /*** Getters and setters **/
7151 IWineD3DDeviceImpl_SetClipPlane,
7152 IWineD3DDeviceImpl_GetClipPlane,
7153 IWineD3DDeviceImpl_SetClipStatus,
7154 IWineD3DDeviceImpl_GetClipStatus,
7155 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7156 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7157 IWineD3DDeviceImpl_SetDepthStencilSurface,
7158 IWineD3DDeviceImpl_GetDepthStencilSurface,
7159 IWineD3DDeviceImpl_SetFVF,
7160 IWineD3DDeviceImpl_GetFVF,
7161 IWineD3DDeviceImpl_SetGammaRamp,
7162 IWineD3DDeviceImpl_GetGammaRamp,
7163 IWineD3DDeviceImpl_SetIndices,
7164 IWineD3DDeviceImpl_GetIndices,
7165 IWineD3DDeviceImpl_SetBaseVertexIndex,
7166 IWineD3DDeviceImpl_GetBaseVertexIndex,
7167 IWineD3DDeviceImpl_SetLight,
7168 IWineD3DDeviceImpl_GetLight,
7169 IWineD3DDeviceImpl_SetLightEnable,
7170 IWineD3DDeviceImpl_GetLightEnable,
7171 IWineD3DDeviceImpl_SetMaterial,
7172 IWineD3DDeviceImpl_GetMaterial,
7173 IWineD3DDeviceImpl_SetNPatchMode,
7174 IWineD3DDeviceImpl_GetNPatchMode,
7175 IWineD3DDeviceImpl_SetPaletteEntries,
7176 IWineD3DDeviceImpl_GetPaletteEntries,
7177 IWineD3DDeviceImpl_SetPixelShader,
7178 IWineD3DDeviceImpl_GetPixelShader,
7179 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7180 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7181 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7182 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7183 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7184 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7185 IWineD3DDeviceImpl_SetRenderState,
7186 IWineD3DDeviceImpl_GetRenderState,
7187 IWineD3DDeviceImpl_SetRenderTarget,
7188 IWineD3DDeviceImpl_GetRenderTarget,
7189 IWineD3DDeviceImpl_SetFrontBackBuffers,
7190 IWineD3DDeviceImpl_SetSamplerState,
7191 IWineD3DDeviceImpl_GetSamplerState,
7192 IWineD3DDeviceImpl_SetScissorRect,
7193 IWineD3DDeviceImpl_GetScissorRect,
7194 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7195 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7196 IWineD3DDeviceImpl_SetStreamSource,
7197 IWineD3DDeviceImpl_GetStreamSource,
7198 IWineD3DDeviceImpl_SetStreamSourceFreq,
7199 IWineD3DDeviceImpl_GetStreamSourceFreq,
7200 IWineD3DDeviceImpl_SetTexture,
7201 IWineD3DDeviceImpl_GetTexture,
7202 IWineD3DDeviceImpl_SetTextureStageState,
7203 IWineD3DDeviceImpl_GetTextureStageState,
7204 IWineD3DDeviceImpl_SetTransform,
7205 IWineD3DDeviceImpl_GetTransform,
7206 IWineD3DDeviceImpl_SetVertexDeclaration,
7207 IWineD3DDeviceImpl_GetVertexDeclaration,
7208 IWineD3DDeviceImpl_SetVertexShader,
7209 IWineD3DDeviceImpl_GetVertexShader,
7210 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7211 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7212 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7213 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7214 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7215 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7216 IWineD3DDeviceImpl_SetViewport,
7217 IWineD3DDeviceImpl_GetViewport,
7218 IWineD3DDeviceImpl_MultiplyTransform,
7219 IWineD3DDeviceImpl_ValidateDevice,
7220 IWineD3DDeviceImpl_ProcessVertices,
7221 /*** State block ***/
7222 IWineD3DDeviceImpl_BeginStateBlock,
7223 IWineD3DDeviceImpl_EndStateBlock,
7224 /*** Scene management ***/
7225 IWineD3DDeviceImpl_BeginScene,
7226 IWineD3DDeviceImpl_EndScene,
7227 IWineD3DDeviceImpl_Present,
7228 IWineD3DDeviceImpl_Clear,
7229 /*** Drawing ***/
7230 IWineD3DDeviceImpl_DrawPrimitive,
7231 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7232 IWineD3DDeviceImpl_DrawPrimitiveUP,
7233 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7234 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7235 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7236 IWineD3DDeviceImpl_DrawRectPatch,
7237 IWineD3DDeviceImpl_DrawTriPatch,
7238 IWineD3DDeviceImpl_DeletePatch,
7239 IWineD3DDeviceImpl_ColorFill,
7240 IWineD3DDeviceImpl_UpdateTexture,
7241 IWineD3DDeviceImpl_UpdateSurface,
7242 IWineD3DDeviceImpl_GetFrontBufferData,
7243 /*** object tracking ***/
7244 IWineD3DDeviceImpl_ResourceReleased
7248 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7249 WINED3DRS_ALPHABLENDENABLE ,
7250 WINED3DRS_ALPHAFUNC ,
7251 WINED3DRS_ALPHAREF ,
7252 WINED3DRS_ALPHATESTENABLE ,
7253 WINED3DRS_BLENDOP ,
7254 WINED3DRS_COLORWRITEENABLE ,
7255 WINED3DRS_DESTBLEND ,
7256 WINED3DRS_DITHERENABLE ,
7257 WINED3DRS_FILLMODE ,
7258 WINED3DRS_FOGDENSITY ,
7259 WINED3DRS_FOGEND ,
7260 WINED3DRS_FOGSTART ,
7261 WINED3DRS_LASTPIXEL ,
7262 WINED3DRS_SHADEMODE ,
7263 WINED3DRS_SRCBLEND ,
7264 WINED3DRS_STENCILENABLE ,
7265 WINED3DRS_STENCILFAIL ,
7266 WINED3DRS_STENCILFUNC ,
7267 WINED3DRS_STENCILMASK ,
7268 WINED3DRS_STENCILPASS ,
7269 WINED3DRS_STENCILREF ,
7270 WINED3DRS_STENCILWRITEMASK ,
7271 WINED3DRS_STENCILZFAIL ,
7272 WINED3DRS_TEXTUREFACTOR ,
7273 WINED3DRS_WRAP0 ,
7274 WINED3DRS_WRAP1 ,
7275 WINED3DRS_WRAP2 ,
7276 WINED3DRS_WRAP3 ,
7277 WINED3DRS_WRAP4 ,
7278 WINED3DRS_WRAP5 ,
7279 WINED3DRS_WRAP6 ,
7280 WINED3DRS_WRAP7 ,
7281 WINED3DRS_ZENABLE ,
7282 WINED3DRS_ZFUNC ,
7283 WINED3DRS_ZWRITEENABLE
7286 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7287 WINED3DTSS_ADDRESSW ,
7288 WINED3DTSS_ALPHAARG0 ,
7289 WINED3DTSS_ALPHAARG1 ,
7290 WINED3DTSS_ALPHAARG2 ,
7291 WINED3DTSS_ALPHAOP ,
7292 WINED3DTSS_BUMPENVLOFFSET ,
7293 WINED3DTSS_BUMPENVLSCALE ,
7294 WINED3DTSS_BUMPENVMAT00 ,
7295 WINED3DTSS_BUMPENVMAT01 ,
7296 WINED3DTSS_BUMPENVMAT10 ,
7297 WINED3DTSS_BUMPENVMAT11 ,
7298 WINED3DTSS_COLORARG0 ,
7299 WINED3DTSS_COLORARG1 ,
7300 WINED3DTSS_COLORARG2 ,
7301 WINED3DTSS_COLOROP ,
7302 WINED3DTSS_RESULTARG ,
7303 WINED3DTSS_TEXCOORDINDEX ,
7304 WINED3DTSS_TEXTURETRANSFORMFLAGS
7307 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7308 WINED3DSAMP_ADDRESSU ,
7309 WINED3DSAMP_ADDRESSV ,
7310 WINED3DSAMP_ADDRESSW ,
7311 WINED3DSAMP_BORDERCOLOR ,
7312 WINED3DSAMP_MAGFILTER ,
7313 WINED3DSAMP_MINFILTER ,
7314 WINED3DSAMP_MIPFILTER ,
7315 WINED3DSAMP_MIPMAPLODBIAS ,
7316 WINED3DSAMP_MAXMIPLEVEL ,
7317 WINED3DSAMP_MAXANISOTROPY ,
7318 WINED3DSAMP_SRGBTEXTURE ,
7319 WINED3DSAMP_ELEMENTINDEX
7322 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7323 WINED3DRS_AMBIENT ,
7324 WINED3DRS_AMBIENTMATERIALSOURCE ,
7325 WINED3DRS_CLIPPING ,
7326 WINED3DRS_CLIPPLANEENABLE ,
7327 WINED3DRS_COLORVERTEX ,
7328 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7329 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7330 WINED3DRS_FOGDENSITY ,
7331 WINED3DRS_FOGEND ,
7332 WINED3DRS_FOGSTART ,
7333 WINED3DRS_FOGTABLEMODE ,
7334 WINED3DRS_FOGVERTEXMODE ,
7335 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7336 WINED3DRS_LIGHTING ,
7337 WINED3DRS_LOCALVIEWER ,
7338 WINED3DRS_MULTISAMPLEANTIALIAS ,
7339 WINED3DRS_MULTISAMPLEMASK ,
7340 WINED3DRS_NORMALIZENORMALS ,
7341 WINED3DRS_PATCHEDGESTYLE ,
7342 WINED3DRS_POINTSCALE_A ,
7343 WINED3DRS_POINTSCALE_B ,
7344 WINED3DRS_POINTSCALE_C ,
7345 WINED3DRS_POINTSCALEENABLE ,
7346 WINED3DRS_POINTSIZE ,
7347 WINED3DRS_POINTSIZE_MAX ,
7348 WINED3DRS_POINTSIZE_MIN ,
7349 WINED3DRS_POINTSPRITEENABLE ,
7350 WINED3DRS_RANGEFOGENABLE ,
7351 WINED3DRS_SPECULARMATERIALSOURCE ,
7352 WINED3DRS_TWEENFACTOR ,
7353 WINED3DRS_VERTEXBLEND ,
7354 WINED3DRS_CULLMODE ,
7355 WINED3DRS_FOGCOLOR
7358 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7359 WINED3DTSS_TEXCOORDINDEX ,
7360 WINED3DTSS_TEXTURETRANSFORMFLAGS
7363 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7364 WINED3DSAMP_DMAPOFFSET
7367 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7368 DWORD rep = StateTable[state].representative;
7369 DWORD idx;
7370 BYTE shift;
7371 UINT i;
7372 WineD3DContext *context;
7374 if(!rep) return;
7375 for(i = 0; i < This->numContexts; i++) {
7376 context = This->contexts[i];
7377 if(isStateDirty(context, rep)) continue;
7379 context->dirtyArray[context->numDirtyEntries++] = rep;
7380 idx = rep >> 5;
7381 shift = rep & 0x1f;
7382 context->isStateDirty[idx] |= (1 << shift);
7386 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7387 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7388 /* The drawable size of a pbuffer render target is the current pbuffer size
7390 *width = dev->pbufferWidth;
7391 *height = dev->pbufferHeight;
7394 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7395 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7397 *width = This->pow2Width;
7398 *height = This->pow2Height;
7401 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7402 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7403 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7404 * current context's drawable, which is the size of the back buffer of the swapchain
7405 * the active context belongs to. The back buffer of the swapchain is stored as the
7406 * surface the context belongs to.
7408 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7409 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;