push e57f4907e24f93b118c5a715e9cf13b17e600a1f
[wine/hacks.git] / dlls / wined3d / device.c
blob1ec8ea8825b98dc017ae8e33deadc328990cbb39
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 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
899 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
900 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
902 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
903 (Width != pow2Width || Height != pow2Height) &&
904 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
906 object->baseTexture.pow2Matrix[0] = (float)Width;
907 object->baseTexture.pow2Matrix[5] = (float)Height;
908 object->baseTexture.pow2Matrix[10] = 1.0;
909 object->baseTexture.pow2Matrix[15] = 1.0;
910 object->target = GL_TEXTURE_RECTANGLE_ARB;
911 } else {
912 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
913 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
914 object->baseTexture.pow2Matrix[10] = 1.0;
915 object->baseTexture.pow2Matrix[15] = 1.0;
916 object->target = GL_TEXTURE_2D;
918 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
920 /* Calculate levels for mip mapping */
921 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
922 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
923 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
924 return WINED3DERR_INVALIDCALL;
926 if(Levels > 1) {
927 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
928 return WINED3DERR_INVALIDCALL;
930 object->baseTexture.levels = 1;
931 } else if (Levels == 0) {
932 TRACE("calculating levels %d\n", object->baseTexture.levels);
933 object->baseTexture.levels++;
934 tmpW = Width;
935 tmpH = Height;
936 while (tmpW > 1 || tmpH > 1) {
937 tmpW = max(1, tmpW >> 1);
938 tmpH = max(1, tmpH >> 1);
939 object->baseTexture.levels++;
941 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
944 /* Generate all the surfaces */
945 tmpW = Width;
946 tmpH = Height;
947 for (i = 0; i < object->baseTexture.levels; i++)
949 /* use the callback to create the texture surface */
950 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
951 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
952 FIXME("Failed to create surface %p\n", object);
953 /* clean up */
954 object->surfaces[i] = NULL;
955 IWineD3DTexture_Release((IWineD3DTexture *)object);
957 *ppTexture = NULL;
958 return hr;
961 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
962 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
963 /* calculate the next mipmap level */
964 tmpW = max(1, tmpW >> 1);
965 tmpH = max(1, tmpH >> 1);
967 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
969 TRACE("(%p) : Created texture %p\n", This, object);
970 return WINED3D_OK;
973 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
974 UINT Width, UINT Height, UINT Depth,
975 UINT Levels, DWORD Usage,
976 WINED3DFORMAT Format, WINED3DPOOL Pool,
977 IWineD3DVolumeTexture **ppVolumeTexture,
978 HANDLE *pSharedHandle, IUnknown *parent,
979 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
982 IWineD3DVolumeTextureImpl *object;
983 unsigned int i;
984 UINT tmpW;
985 UINT tmpH;
986 UINT tmpD;
987 const GlPixelFormatDesc *glDesc;
989 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
991 /* TODO: It should only be possible to create textures for formats
992 that are reported as supported */
993 if (WINED3DFMT_UNKNOWN >= Format) {
994 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
995 return WINED3DERR_INVALIDCALL;
997 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
998 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
999 return WINED3DERR_INVALIDCALL;
1002 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
1003 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1005 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1006 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1008 object->width = Width;
1009 object->height = Height;
1010 object->depth = Depth;
1012 /* Is NP2 support for volumes needed? */
1013 object->baseTexture.pow2Matrix[ 0] = 1.0;
1014 object->baseTexture.pow2Matrix[ 5] = 1.0;
1015 object->baseTexture.pow2Matrix[10] = 1.0;
1016 object->baseTexture.pow2Matrix[15] = 1.0;
1018 /* Calculate levels for mip mapping */
1019 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1020 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1021 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1022 return WINED3DERR_INVALIDCALL;
1024 if(Levels > 1) {
1025 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1026 return WINED3DERR_INVALIDCALL;
1028 Levels = 1;
1029 } else if (Levels == 0) {
1030 object->baseTexture.levels++;
1031 tmpW = Width;
1032 tmpH = Height;
1033 tmpD = Depth;
1034 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
1035 tmpW = max(1, tmpW >> 1);
1036 tmpH = max(1, tmpH >> 1);
1037 tmpD = max(1, tmpD >> 1);
1038 object->baseTexture.levels++;
1040 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1043 /* Generate all the surfaces */
1044 tmpW = Width;
1045 tmpH = Height;
1046 tmpD = Depth;
1048 for (i = 0; i < object->baseTexture.levels; i++)
1050 HRESULT hr;
1051 /* Create the volume */
1052 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1053 &object->volumes[i], pSharedHandle);
1055 if(FAILED(hr)) {
1056 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1057 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1058 *ppVolumeTexture = NULL;
1059 return hr;
1062 /* Set its container to this object */
1063 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1065 /* calculate the next mipmap level */
1066 tmpW = max(1, tmpW >> 1);
1067 tmpH = max(1, tmpH >> 1);
1068 tmpD = max(1, tmpD >> 1);
1070 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1072 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1073 TRACE("(%p) : Created volume texture %p\n", This, object);
1074 return WINED3D_OK;
1077 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1078 UINT Width, UINT Height, UINT Depth,
1079 DWORD Usage,
1080 WINED3DFORMAT Format, WINED3DPOOL Pool,
1081 IWineD3DVolume** ppVolume,
1082 HANDLE* pSharedHandle, IUnknown *parent) {
1084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1085 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1086 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1088 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1089 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1090 return WINED3DERR_INVALIDCALL;
1093 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1095 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1096 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1098 object->currentDesc.Width = Width;
1099 object->currentDesc.Height = Height;
1100 object->currentDesc.Depth = Depth;
1101 object->bytesPerPixel = formatDesc->bpp;
1103 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1104 object->lockable = TRUE;
1105 object->locked = FALSE;
1106 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1107 object->dirty = TRUE;
1109 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1112 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1113 UINT Levels, DWORD Usage,
1114 WINED3DFORMAT Format, WINED3DPOOL Pool,
1115 IWineD3DCubeTexture **ppCubeTexture,
1116 HANDLE *pSharedHandle, IUnknown *parent,
1117 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1120 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1121 unsigned int i, j;
1122 UINT tmpW;
1123 HRESULT hr;
1124 unsigned int pow2EdgeLength = EdgeLength;
1125 const GlPixelFormatDesc *glDesc;
1126 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1128 /* TODO: It should only be possible to create textures for formats
1129 that are reported as supported */
1130 if (WINED3DFMT_UNKNOWN >= Format) {
1131 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1132 return WINED3DERR_INVALIDCALL;
1135 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1136 WARN("(%p) : Tried to create not supported cube texture\n", This);
1137 return WINED3DERR_INVALIDCALL;
1140 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1141 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1143 TRACE("(%p) Create Cube Texture\n", This);
1145 /** Non-power2 support **/
1147 /* Find the nearest pow2 match */
1148 pow2EdgeLength = 1;
1149 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1151 object->edgeLength = EdgeLength;
1152 /* TODO: support for native non-power 2 */
1153 /* Precalculated scaling for 'faked' non power of two texture coords */
1154 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1155 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1156 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1157 object->baseTexture.pow2Matrix[15] = 1.0;
1159 /* Calculate levels for mip mapping */
1160 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1161 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1162 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1163 HeapFree(GetProcessHeap(), 0, object);
1164 *ppCubeTexture = NULL;
1166 return WINED3DERR_INVALIDCALL;
1168 if(Levels > 1) {
1169 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1170 HeapFree(GetProcessHeap(), 0, object);
1171 *ppCubeTexture = NULL;
1173 return WINED3DERR_INVALIDCALL;
1175 Levels = 1;
1176 } else if (Levels == 0) {
1177 object->baseTexture.levels++;
1178 tmpW = EdgeLength;
1179 while (tmpW > 1) {
1180 tmpW = max(1, tmpW >> 1);
1181 object->baseTexture.levels++;
1183 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1186 /* Generate all the surfaces */
1187 tmpW = EdgeLength;
1188 for (i = 0; i < object->baseTexture.levels; i++) {
1190 /* Create the 6 faces */
1191 for (j = 0; j < 6; j++) {
1193 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1194 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1196 if(hr!= WINED3D_OK) {
1197 /* clean up */
1198 int k;
1199 int l;
1200 for (l = 0; l < j; l++) {
1201 IWineD3DSurface_Release(object->surfaces[l][i]);
1203 for (k = 0; k < i; k++) {
1204 for (l = 0; l < 6; l++) {
1205 IWineD3DSurface_Release(object->surfaces[l][k]);
1209 FIXME("(%p) Failed to create surface\n",object);
1210 HeapFree(GetProcessHeap(),0,object);
1211 *ppCubeTexture = NULL;
1212 return hr;
1214 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1215 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1217 tmpW = max(1, tmpW >> 1);
1219 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1221 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1222 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1223 return WINED3D_OK;
1226 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1228 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1229 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1231 /* Just a check to see if we support this type of query */
1232 switch(Type) {
1233 case WINED3DQUERYTYPE_OCCLUSION:
1234 TRACE("(%p) occlusion query\n", This);
1235 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1236 hr = WINED3D_OK;
1237 else
1238 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1239 break;
1241 case WINED3DQUERYTYPE_EVENT:
1242 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1243 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1244 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1246 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1248 hr = WINED3D_OK;
1249 break;
1251 case WINED3DQUERYTYPE_VCACHE:
1252 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1253 case WINED3DQUERYTYPE_VERTEXSTATS:
1254 case WINED3DQUERYTYPE_TIMESTAMP:
1255 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1256 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1257 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1258 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1259 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1260 case WINED3DQUERYTYPE_PIXELTIMINGS:
1261 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1262 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1263 default:
1264 FIXME("(%p) Unhandled query type %d\n", This, Type);
1266 if(NULL == ppQuery || hr != WINED3D_OK) {
1267 return hr;
1270 D3DCREATEOBJECTINSTANCE(object, Query)
1271 object->type = Type;
1272 object->state = QUERY_CREATED;
1273 /* allocated the 'extended' data based on the type of query requested */
1274 switch(Type){
1275 case WINED3DQUERYTYPE_OCCLUSION:
1276 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1277 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1279 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1280 TRACE("(%p) Allocating data for an occlusion query\n", This);
1281 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1282 break;
1284 case WINED3DQUERYTYPE_EVENT:
1285 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1286 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1288 if(GL_SUPPORT(APPLE_FENCE)) {
1289 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1290 checkGLcall("glGenFencesAPPLE");
1291 } else if(GL_SUPPORT(NV_FENCE)) {
1292 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1293 checkGLcall("glGenFencesNV");
1295 break;
1297 case WINED3DQUERYTYPE_VCACHE:
1298 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1299 case WINED3DQUERYTYPE_VERTEXSTATS:
1300 case WINED3DQUERYTYPE_TIMESTAMP:
1301 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1302 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1303 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1304 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1305 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1306 case WINED3DQUERYTYPE_PIXELTIMINGS:
1307 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1308 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1309 default:
1310 object->extendedData = 0;
1311 FIXME("(%p) Unhandled query type %d\n",This , Type);
1313 TRACE("(%p) : Created Query %p\n", This, object);
1314 return WINED3D_OK;
1317 /*****************************************************************************
1318 * IWineD3DDeviceImpl_SetupFullscreenWindow
1320 * Helper function that modifies a HWND's Style and ExStyle for proper
1321 * fullscreen use.
1323 * Params:
1324 * iface: Pointer to the IWineD3DDevice interface
1325 * window: Window to setup
1327 *****************************************************************************/
1328 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1331 LONG style, exStyle;
1332 /* Don't do anything if an original style is stored.
1333 * That shouldn't happen
1335 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1336 if (This->style || This->exStyle) {
1337 ERR("(%p): Want to change the window parameters of HWND %p, but "
1338 "another style is stored for restoration afterwards\n", This, window);
1341 /* Get the parameters and save them */
1342 style = GetWindowLongW(window, GWL_STYLE);
1343 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1344 This->style = style;
1345 This->exStyle = exStyle;
1347 /* Filter out window decorations */
1348 style &= ~WS_CAPTION;
1349 style &= ~WS_THICKFRAME;
1350 exStyle &= ~WS_EX_WINDOWEDGE;
1351 exStyle &= ~WS_EX_CLIENTEDGE;
1353 /* Make sure the window is managed, otherwise we won't get keyboard input */
1354 style |= WS_POPUP | WS_SYSMENU;
1356 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1357 This->style, This->exStyle, style, exStyle);
1359 SetWindowLongW(window, GWL_STYLE, style);
1360 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1362 /* Inform the window about the update. */
1363 SetWindowPos(window, HWND_TOP, 0, 0,
1364 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1365 ShowWindow(window, SW_NORMAL);
1368 /*****************************************************************************
1369 * IWineD3DDeviceImpl_RestoreWindow
1371 * Helper function that restores a windows' properties when taking it out
1372 * of fullscreen mode
1374 * Params:
1375 * iface: Pointer to the IWineD3DDevice interface
1376 * window: Window to setup
1378 *****************************************************************************/
1379 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1382 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1383 * switch, do nothing
1385 if (!This->style && !This->exStyle) return;
1387 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1388 This, window, This->style, This->exStyle);
1390 SetWindowLongW(window, GWL_STYLE, This->style);
1391 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1393 /* Delete the old values */
1394 This->style = 0;
1395 This->exStyle = 0;
1397 /* Inform the window about the update */
1398 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1399 0, 0, 0, 0, /* Pos, Size, ignored */
1400 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1403 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1404 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1405 IUnknown* parent,
1406 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1407 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1410 HDC hDc;
1411 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1412 HRESULT hr = WINED3D_OK;
1413 IUnknown *bufferParent;
1414 BOOL displaymode_set = FALSE;
1415 WINED3DDISPLAYMODE Mode;
1416 const StaticPixelFormatDesc *formatDesc;
1418 TRACE("(%p) : Created Additional Swap Chain\n", This);
1420 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1421 * does a device hold a reference to a swap chain giving them a lifetime of the device
1422 * or does the swap chain notify the device of its destruction.
1423 *******************************/
1425 /* Check the params */
1426 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1427 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1428 return WINED3DERR_INVALIDCALL;
1429 } else if (pPresentationParameters->BackBufferCount > 1) {
1430 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");
1433 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1435 /*********************
1436 * Lookup the window Handle and the relating X window handle
1437 ********************/
1439 /* Setup hwnd we are using, plus which display this equates to */
1440 object->win_handle = pPresentationParameters->hDeviceWindow;
1441 if (!object->win_handle) {
1442 object->win_handle = This->createParms.hFocusWindow;
1444 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1446 hDc = GetDC(object->win_handle);
1447 TRACE("Using hDc %p\n", hDc);
1449 if (NULL == hDc) {
1450 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1451 return WINED3DERR_NOTAVAILABLE;
1454 /* Get info on the current display setup */
1455 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1456 object->orig_width = Mode.Width;
1457 object->orig_height = Mode.Height;
1458 object->orig_fmt = Mode.Format;
1459 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1461 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1462 * then the corresponding dimension of the client area of the hDeviceWindow
1463 * (or the focus window, if hDeviceWindow is NULL) is taken.
1464 **********************/
1466 if (pPresentationParameters->Windowed &&
1467 ((pPresentationParameters->BackBufferWidth == 0) ||
1468 (pPresentationParameters->BackBufferHeight == 0) ||
1469 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1471 RECT Rect;
1472 GetClientRect(object->win_handle, &Rect);
1474 if (pPresentationParameters->BackBufferWidth == 0) {
1475 pPresentationParameters->BackBufferWidth = Rect.right;
1476 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1478 if (pPresentationParameters->BackBufferHeight == 0) {
1479 pPresentationParameters->BackBufferHeight = Rect.bottom;
1480 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1482 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1483 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1484 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1488 /* Put the correct figures in the presentation parameters */
1489 TRACE("Copying across presentation parameters\n");
1490 object->presentParms = *pPresentationParameters;
1492 TRACE("calling rendertarget CB\n");
1493 hr = D3DCB_CreateRenderTarget(This->parent,
1494 parent,
1495 object->presentParms.BackBufferWidth,
1496 object->presentParms.BackBufferHeight,
1497 object->presentParms.BackBufferFormat,
1498 object->presentParms.MultiSampleType,
1499 object->presentParms.MultiSampleQuality,
1500 TRUE /* Lockable */,
1501 &object->frontBuffer,
1502 NULL /* pShared (always null)*/);
1503 if (object->frontBuffer != NULL) {
1504 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1505 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1506 } else {
1507 ERR("Failed to create the front buffer\n");
1508 goto error;
1511 /*********************
1512 * Windowed / Fullscreen
1513 *******************/
1516 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1517 * so we should really check to see if there is a fullscreen swapchain already
1518 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1519 **************************************/
1521 if (!pPresentationParameters->Windowed) {
1522 WINED3DDISPLAYMODE mode;
1525 /* Change the display settings */
1526 mode.Width = pPresentationParameters->BackBufferWidth;
1527 mode.Height = pPresentationParameters->BackBufferHeight;
1528 mode.Format = pPresentationParameters->BackBufferFormat;
1529 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1531 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1532 displaymode_set = TRUE;
1533 IWineD3DDevice_SetFullscreen(iface, TRUE);
1537 * Create an opengl context for the display visual
1538 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1539 * use different properties after that point in time. FIXME: How to handle when requested format
1540 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1541 * it chooses is identical to the one already being used!
1542 **********************************/
1543 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1545 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1546 if(!object->context)
1547 return E_OUTOFMEMORY;
1548 object->num_contexts = 1;
1550 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1551 if (!object->context[0]) {
1552 ERR("Failed to create a new context\n");
1553 hr = WINED3DERR_NOTAVAILABLE;
1554 goto error;
1555 } else {
1556 TRACE("Context created (HWND=%p, glContext=%p)\n",
1557 object->win_handle, object->context[0]->glCtx);
1560 /*********************
1561 * Create the back, front and stencil buffers
1562 *******************/
1563 if(object->presentParms.BackBufferCount > 0) {
1564 int i;
1566 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1567 if(!object->backBuffer) {
1568 ERR("Out of memory\n");
1569 hr = E_OUTOFMEMORY;
1570 goto error;
1573 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1574 TRACE("calling rendertarget CB\n");
1575 hr = D3DCB_CreateRenderTarget(This->parent,
1576 parent,
1577 object->presentParms.BackBufferWidth,
1578 object->presentParms.BackBufferHeight,
1579 object->presentParms.BackBufferFormat,
1580 object->presentParms.MultiSampleType,
1581 object->presentParms.MultiSampleQuality,
1582 TRUE /* Lockable */,
1583 &object->backBuffer[i],
1584 NULL /* pShared (always null)*/);
1585 if(hr == WINED3D_OK && object->backBuffer[i]) {
1586 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1587 } else {
1588 ERR("Cannot create new back buffer\n");
1589 goto error;
1591 ENTER_GL();
1592 glDrawBuffer(GL_BACK);
1593 checkGLcall("glDrawBuffer(GL_BACK)");
1594 LEAVE_GL();
1596 } else {
1597 object->backBuffer = NULL;
1599 /* Single buffering - draw to front buffer */
1600 ENTER_GL();
1601 glDrawBuffer(GL_FRONT);
1602 checkGLcall("glDrawBuffer(GL_FRONT)");
1603 LEAVE_GL();
1606 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1607 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1608 TRACE("Creating depth stencil buffer\n");
1609 if (This->auto_depth_stencil_buffer == NULL ) {
1610 hr = D3DCB_CreateDepthStencil(This->parent,
1611 parent,
1612 object->presentParms.BackBufferWidth,
1613 object->presentParms.BackBufferHeight,
1614 object->presentParms.AutoDepthStencilFormat,
1615 object->presentParms.MultiSampleType,
1616 object->presentParms.MultiSampleQuality,
1617 FALSE /* FIXME: Discard */,
1618 &This->auto_depth_stencil_buffer,
1619 NULL /* pShared (always null)*/ );
1620 if (This->auto_depth_stencil_buffer != NULL)
1621 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1624 /** TODO: A check on width, height and multisample types
1625 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1626 ****************************/
1627 object->wantsDepthStencilBuffer = TRUE;
1628 } else {
1629 object->wantsDepthStencilBuffer = FALSE;
1632 TRACE("Created swapchain %p\n", object);
1633 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1634 return WINED3D_OK;
1636 error:
1637 if (displaymode_set) {
1638 DEVMODEW devmode;
1639 RECT clip_rc;
1641 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1642 ClipCursor(NULL);
1644 /* Change the display settings */
1645 memset(&devmode, 0, sizeof(devmode));
1646 devmode.dmSize = sizeof(devmode);
1647 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1648 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1649 devmode.dmPelsWidth = object->orig_width;
1650 devmode.dmPelsHeight = object->orig_height;
1651 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1654 if (object->backBuffer) {
1655 int i;
1656 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1657 if(object->backBuffer[i]) {
1658 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1659 IUnknown_Release(bufferParent); /* once for the get parent */
1660 if (IUnknown_Release(bufferParent) > 0) {
1661 FIXME("(%p) Something's still holding the back buffer\n",This);
1665 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1666 object->backBuffer = NULL;
1668 if(object->context[0])
1669 DestroyContext(This, object->context[0]);
1670 if(object->frontBuffer) {
1671 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1672 IUnknown_Release(bufferParent); /* once for the get parent */
1673 if (IUnknown_Release(bufferParent) > 0) {
1674 FIXME("(%p) Something's still holding the front buffer\n",This);
1677 HeapFree(GetProcessHeap(), 0, object);
1678 return hr;
1681 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1682 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1684 TRACE("(%p)\n", This);
1686 return This->NumberOfSwapChains;
1689 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1691 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1693 if(iSwapChain < This->NumberOfSwapChains) {
1694 *pSwapChain = This->swapchains[iSwapChain];
1695 IWineD3DSwapChain_AddRef(*pSwapChain);
1696 TRACE("(%p) returning %p\n", This, *pSwapChain);
1697 return WINED3D_OK;
1698 } else {
1699 TRACE("Swapchain out of range\n");
1700 *pSwapChain = NULL;
1701 return WINED3DERR_INVALIDCALL;
1705 /*****
1706 * Vertex Declaration
1707 *****/
1708 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1709 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1711 IWineD3DVertexDeclarationImpl *object = NULL;
1712 HRESULT hr = WINED3D_OK;
1714 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1715 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1717 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1719 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1720 if(FAILED(hr)) {
1721 *ppVertexDeclaration = NULL;
1722 HeapFree(GetProcessHeap(), 0, object);
1725 return hr;
1728 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1729 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1731 unsigned int idx, idx2;
1732 unsigned int offset;
1733 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1734 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1735 BOOL has_blend_idx = has_blend &&
1736 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1737 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1738 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1739 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1740 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1741 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1742 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1744 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1745 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1747 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1748 WINED3DVERTEXELEMENT *elements = NULL;
1750 unsigned int size;
1751 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1752 if (has_blend_idx) num_blends--;
1754 /* Compute declaration size */
1755 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1756 has_psize + has_diffuse + has_specular + num_textures + 1;
1758 /* convert the declaration */
1759 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1760 if (!elements)
1761 return 0;
1763 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1764 idx = 0;
1765 if (has_pos) {
1766 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1767 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1768 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1770 else {
1771 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1772 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1774 elements[idx].UsageIndex = 0;
1775 idx++;
1777 if (has_blend && (num_blends > 0)) {
1778 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1779 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1780 else
1781 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1782 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1783 elements[idx].UsageIndex = 0;
1784 idx++;
1786 if (has_blend_idx) {
1787 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1788 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1789 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1790 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1791 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1792 else
1793 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1794 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1795 elements[idx].UsageIndex = 0;
1796 idx++;
1798 if (has_normal) {
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1800 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1801 elements[idx].UsageIndex = 0;
1802 idx++;
1804 if (has_psize) {
1805 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1806 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1807 elements[idx].UsageIndex = 0;
1808 idx++;
1810 if (has_diffuse) {
1811 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1812 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1813 elements[idx].UsageIndex = 0;
1814 idx++;
1816 if (has_specular) {
1817 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1818 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1819 elements[idx].UsageIndex = 1;
1820 idx++;
1822 for (idx2 = 0; idx2 < num_textures; idx2++) {
1823 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1824 switch (numcoords) {
1825 case WINED3DFVF_TEXTUREFORMAT1:
1826 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1827 break;
1828 case WINED3DFVF_TEXTUREFORMAT2:
1829 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1830 break;
1831 case WINED3DFVF_TEXTUREFORMAT3:
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1833 break;
1834 case WINED3DFVF_TEXTUREFORMAT4:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1836 break;
1838 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1839 elements[idx].UsageIndex = idx2;
1840 idx++;
1843 /* Now compute offsets, and initialize the rest of the fields */
1844 for (idx = 0, offset = 0; idx < size-1; idx++) {
1845 elements[idx].Stream = 0;
1846 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1847 elements[idx].Offset = offset;
1848 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1851 *ppVertexElements = elements;
1852 return size;
1855 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1856 WINED3DVERTEXELEMENT* elements = NULL;
1857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1858 unsigned int size;
1859 DWORD hr;
1861 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1862 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1864 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1865 HeapFree(GetProcessHeap(), 0, elements);
1866 if (hr != S_OK) return hr;
1868 return WINED3D_OK;
1871 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1872 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1874 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1875 HRESULT hr = WINED3D_OK;
1876 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1877 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1879 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1881 if (vertex_declaration) {
1882 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1885 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1887 if (WINED3D_OK != hr) {
1888 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1889 IWineD3DVertexShader_Release(*ppVertexShader);
1890 return WINED3DERR_INVALIDCALL;
1892 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1894 return WINED3D_OK;
1897 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1899 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1900 HRESULT hr = WINED3D_OK;
1902 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1903 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1904 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1905 if (WINED3D_OK == hr) {
1906 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1907 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1908 } else {
1909 WARN("(%p) : Failed to create pixel shader\n", This);
1912 return hr;
1915 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1917 IWineD3DPaletteImpl *object;
1918 HRESULT hr;
1919 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1921 /* Create the new object */
1922 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1923 if(!object) {
1924 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1925 return E_OUTOFMEMORY;
1928 object->lpVtbl = &IWineD3DPalette_Vtbl;
1929 object->ref = 1;
1930 object->Flags = Flags;
1931 object->parent = Parent;
1932 object->wineD3DDevice = This;
1933 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1935 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1937 if(!object->hpal) {
1938 HeapFree( GetProcessHeap(), 0, object);
1939 return E_OUTOFMEMORY;
1942 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1943 if(FAILED(hr)) {
1944 IWineD3DPalette_Release((IWineD3DPalette *) object);
1945 return hr;
1948 *Palette = (IWineD3DPalette *) object;
1950 return WINED3D_OK;
1953 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1954 HBITMAP hbm;
1955 BITMAP bm;
1956 HRESULT hr;
1957 HDC dcb = NULL, dcs = NULL;
1958 WINEDDCOLORKEY colorkey;
1960 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1961 if(hbm)
1963 GetObjectA(hbm, sizeof(BITMAP), &bm);
1964 dcb = CreateCompatibleDC(NULL);
1965 if(!dcb) goto out;
1966 SelectObject(dcb, hbm);
1968 else
1970 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1971 * couldn't be loaded
1973 memset(&bm, 0, sizeof(bm));
1974 bm.bmWidth = 32;
1975 bm.bmHeight = 32;
1978 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1979 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1980 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1981 if(FAILED(hr)) {
1982 ERR("Wine logo requested, but failed to create surface\n");
1983 goto out;
1986 if(dcb) {
1987 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1988 if(FAILED(hr)) goto out;
1989 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1990 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1992 colorkey.dwColorSpaceLowValue = 0;
1993 colorkey.dwColorSpaceHighValue = 0;
1994 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1995 } else {
1996 /* Fill the surface with a white color to show that wined3d is there */
1997 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2000 out:
2001 if(dcb) {
2002 DeleteDC(dcb);
2004 if(hbm) {
2005 DeleteObject(hbm);
2007 return;
2010 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2012 IWineD3DSwapChainImpl *swapchain = NULL;
2013 HRESULT hr;
2014 DWORD state;
2016 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2017 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2019 /* TODO: Test if OpenGL is compiled in and loaded */
2021 TRACE("(%p) : Creating stateblock\n", This);
2022 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2023 hr = IWineD3DDevice_CreateStateBlock(iface,
2024 WINED3DSBT_INIT,
2025 (IWineD3DStateBlock **)&This->stateBlock,
2026 NULL);
2027 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2028 WARN("Failed to create stateblock\n");
2029 goto err_out;
2031 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2032 This->updateStateBlock = This->stateBlock;
2033 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2035 hr = allocate_shader_constants(This->updateStateBlock);
2036 if (WINED3D_OK != hr) {
2037 goto err_out;
2040 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2041 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2042 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2044 /* Initialize the texture unit mapping to a 1:1 mapping */
2045 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2046 if (state < GL_LIMITS(fragment_samplers)) {
2047 This->texUnitMap[state] = state;
2048 This->rev_tex_unit_map[state] = state;
2049 } else {
2050 This->texUnitMap[state] = -1;
2051 This->rev_tex_unit_map[state] = -1;
2055 /* Setup the implicit swapchain */
2056 TRACE("Creating implicit swapchain\n");
2057 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2058 if (FAILED(hr) || !swapchain) {
2059 WARN("Failed to create implicit swapchain\n");
2060 goto err_out;
2063 This->NumberOfSwapChains = 1;
2064 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2065 if(!This->swapchains) {
2066 ERR("Out of memory!\n");
2067 goto err_out;
2069 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2071 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2072 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2073 This->render_targets[0] = swapchain->backBuffer[0];
2074 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2076 else {
2077 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2078 This->render_targets[0] = swapchain->frontBuffer;
2079 This->lastActiveRenderTarget = swapchain->frontBuffer;
2081 IWineD3DSurface_AddRef(This->render_targets[0]);
2082 This->activeContext = swapchain->context[0];
2083 This->lastThread = GetCurrentThreadId();
2085 /* Depth Stencil support */
2086 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2087 if (NULL != This->stencilBufferTarget) {
2088 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2091 /* Set up some starting GL setup */
2092 ENTER_GL();
2094 /* Setup all the devices defaults */
2095 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2096 #if 0
2097 IWineD3DImpl_CheckGraphicsMemory();
2098 #endif
2100 { /* Set a default viewport */
2101 WINED3DVIEWPORT vp;
2102 vp.X = 0;
2103 vp.Y = 0;
2104 vp.Width = pPresentationParameters->BackBufferWidth;
2105 vp.Height = pPresentationParameters->BackBufferHeight;
2106 vp.MinZ = 0.0f;
2107 vp.MaxZ = 1.0f;
2108 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2111 /* Initialize the current view state */
2112 This->view_ident = 1;
2113 This->contexts[0]->last_was_rhw = 0;
2114 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2115 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2117 switch(wined3d_settings.offscreen_rendering_mode) {
2118 case ORM_FBO:
2119 case ORM_PBUFFER:
2120 This->offscreenBuffer = GL_BACK;
2121 break;
2123 case ORM_BACKBUFFER:
2125 if(GL_LIMITS(aux_buffers) > 0) {
2126 TRACE("Using auxilliary buffer for offscreen rendering\n");
2127 This->offscreenBuffer = GL_AUX0;
2128 } else {
2129 TRACE("Using back buffer for offscreen rendering\n");
2130 This->offscreenBuffer = GL_BACK;
2135 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2136 LEAVE_GL();
2138 /* Clear the screen */
2139 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2140 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2141 0x00, 1.0, 0);
2143 This->d3d_initialized = TRUE;
2145 if(wined3d_settings.logo) {
2146 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2148 return WINED3D_OK;
2150 err_out:
2151 HeapFree(GetProcessHeap(), 0, This->render_targets);
2152 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2153 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2154 HeapFree(GetProcessHeap(), 0, This->swapchains);
2155 This->NumberOfSwapChains = 0;
2156 if(swapchain) {
2157 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2159 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2160 if(This->stateBlock) {
2161 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2162 This->stateBlock = NULL;
2164 return hr;
2167 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2169 int sampler;
2170 UINT i;
2171 TRACE("(%p)\n", This);
2173 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2175 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2176 * it was created. Thus make sure a context is active for the glDelete* calls
2178 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2180 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2182 TRACE("Deleting high order patches\n");
2183 for(i = 0; i < PATCHMAP_SIZE; i++) {
2184 struct list *e1, *e2;
2185 struct WineD3DRectPatch *patch;
2186 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2187 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2188 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2192 /* Delete the palette conversion shader if it is around */
2193 if(This->paletteConversionShader) {
2194 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2195 This->paletteConversionShader = 0;
2198 /* Delete the pbuffer context if there is any */
2199 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2201 /* Delete the mouse cursor texture */
2202 if(This->cursorTexture) {
2203 ENTER_GL();
2204 glDeleteTextures(1, &This->cursorTexture);
2205 LEAVE_GL();
2206 This->cursorTexture = 0;
2209 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2210 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2212 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2213 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2216 /* Release the update stateblock */
2217 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2218 if(This->updateStateBlock != This->stateBlock)
2219 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2221 This->updateStateBlock = NULL;
2223 { /* because were not doing proper internal refcounts releasing the primary state block
2224 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2225 to set this->stateBlock = NULL; first */
2226 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2227 This->stateBlock = NULL;
2229 /* Release the stateblock */
2230 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2231 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2235 /* Release the buffers (with sanity checks)*/
2236 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2237 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2238 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2239 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2241 This->stencilBufferTarget = NULL;
2243 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2244 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2245 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2247 TRACE("Setting rendertarget to NULL\n");
2248 This->render_targets[0] = NULL;
2250 if (This->auto_depth_stencil_buffer) {
2251 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2252 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2254 This->auto_depth_stencil_buffer = NULL;
2257 for(i=0; i < This->NumberOfSwapChains; i++) {
2258 TRACE("Releasing the implicit swapchain %d\n", i);
2259 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2260 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2264 HeapFree(GetProcessHeap(), 0, This->swapchains);
2265 This->swapchains = NULL;
2266 This->NumberOfSwapChains = 0;
2268 HeapFree(GetProcessHeap(), 0, This->render_targets);
2269 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2270 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2271 This->render_targets = NULL;
2272 This->fbo_color_attachments = NULL;
2273 This->draw_buffers = NULL;
2276 This->d3d_initialized = FALSE;
2277 return WINED3D_OK;
2280 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2282 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2284 /* Setup the window for fullscreen mode */
2285 if(fullscreen && !This->ddraw_fullscreen) {
2286 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2287 } else if(!fullscreen && This->ddraw_fullscreen) {
2288 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2291 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2292 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2293 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2294 * separately.
2296 This->ddraw_fullscreen = fullscreen;
2299 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2300 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2301 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2303 * There is no way to deactivate thread safety once it is enabled.
2305 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2308 /*For now just store the flag(needed in case of ddraw) */
2309 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2311 return;
2314 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2315 DEVMODEW devmode;
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2317 LONG ret;
2318 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2319 RECT clip_rc;
2321 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2323 /* Resize the screen even without a window:
2324 * The app could have unset it with SetCooperativeLevel, but not called
2325 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2326 * but we don't have any hwnd
2329 memset(&devmode, 0, sizeof(devmode));
2330 devmode.dmSize = sizeof(devmode);
2331 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2332 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2333 devmode.dmPelsWidth = pMode->Width;
2334 devmode.dmPelsHeight = pMode->Height;
2336 devmode.dmDisplayFrequency = pMode->RefreshRate;
2337 if (pMode->RefreshRate != 0) {
2338 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2341 /* Only change the mode if necessary */
2342 if( (This->ddraw_width == pMode->Width) &&
2343 (This->ddraw_height == pMode->Height) &&
2344 (This->ddraw_format == pMode->Format) &&
2345 (pMode->RefreshRate == 0) ) {
2346 return WINED3D_OK;
2349 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2350 if (ret != DISP_CHANGE_SUCCESSFUL) {
2351 if(devmode.dmDisplayFrequency != 0) {
2352 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2353 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2354 devmode.dmDisplayFrequency = 0;
2355 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2357 if(ret != DISP_CHANGE_SUCCESSFUL) {
2358 return WINED3DERR_NOTAVAILABLE;
2362 /* Store the new values */
2363 This->ddraw_width = pMode->Width;
2364 This->ddraw_height = pMode->Height;
2365 This->ddraw_format = pMode->Format;
2367 /* Only do this with a window of course */
2368 if(This->ddraw_window)
2369 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2371 /* And finally clip mouse to our screen */
2372 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2373 ClipCursor(&clip_rc);
2375 return WINED3D_OK;
2378 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2380 *ppD3D= This->wineD3D;
2381 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2382 IWineD3D_AddRef(*ppD3D);
2383 return WINED3D_OK;
2386 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2389 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2390 (This->adapter->TextureRam/(1024*1024)),
2391 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2392 /* return simulated texture memory left */
2393 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2398 /*****
2399 * Get / Set FVF
2400 *****/
2401 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2404 /* Update the current state block */
2405 This->updateStateBlock->changed.fvf = TRUE;
2407 if(This->updateStateBlock->fvf == fvf) {
2408 TRACE("Application is setting the old fvf over, nothing to do\n");
2409 return WINED3D_OK;
2412 This->updateStateBlock->fvf = fvf;
2413 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2414 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2415 return WINED3D_OK;
2419 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2421 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2422 *pfvf = This->stateBlock->fvf;
2423 return WINED3D_OK;
2426 /*****
2427 * Get / Set Stream Source
2428 *****/
2429 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2431 IWineD3DVertexBuffer *oldSrc;
2433 if (StreamNumber >= MAX_STREAMS) {
2434 WARN("Stream out of range %d\n", StreamNumber);
2435 return WINED3DERR_INVALIDCALL;
2436 } else if(OffsetInBytes & 0x3) {
2437 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2438 return WINED3DERR_INVALIDCALL;
2441 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2442 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2444 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2446 if(oldSrc == pStreamData &&
2447 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2448 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2449 TRACE("Application is setting the old values over, nothing to do\n");
2450 return WINED3D_OK;
2453 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2454 if (pStreamData) {
2455 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2456 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2459 /* Handle recording of state blocks */
2460 if (This->isRecordingState) {
2461 TRACE("Recording... not performing anything\n");
2462 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2463 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2464 return WINED3D_OK;
2467 /* Need to do a getParent and pass the references up */
2468 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2469 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2470 so for now, just count internally */
2471 if (pStreamData != NULL) {
2472 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2473 InterlockedIncrement(&vbImpl->bindCount);
2474 IWineD3DVertexBuffer_AddRef(pStreamData);
2476 if (oldSrc != NULL) {
2477 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2478 IWineD3DVertexBuffer_Release(oldSrc);
2481 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2483 return WINED3D_OK;
2486 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2489 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2490 This->stateBlock->streamSource[StreamNumber],
2491 This->stateBlock->streamOffset[StreamNumber],
2492 This->stateBlock->streamStride[StreamNumber]);
2494 if (StreamNumber >= MAX_STREAMS) {
2495 WARN("Stream out of range %d\n", StreamNumber);
2496 return WINED3DERR_INVALIDCALL;
2498 *pStream = This->stateBlock->streamSource[StreamNumber];
2499 *pStride = This->stateBlock->streamStride[StreamNumber];
2500 if (pOffset) {
2501 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2504 if (*pStream != NULL) {
2505 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2507 return WINED3D_OK;
2510 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2512 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2513 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2515 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2516 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2518 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2519 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2521 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2522 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2523 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2526 return WINED3D_OK;
2529 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2533 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2535 TRACE("(%p) : returning %d\n", This, *Divider);
2537 return WINED3D_OK;
2540 /*****
2541 * Get / Set & Multiply Transform
2542 *****/
2543 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2546 /* Most of this routine, comments included copied from ddraw tree initially: */
2547 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2549 /* Handle recording of state blocks */
2550 if (This->isRecordingState) {
2551 TRACE("Recording... not performing anything\n");
2552 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2553 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2554 return WINED3D_OK;
2558 * If the new matrix is the same as the current one,
2559 * we cut off any further processing. this seems to be a reasonable
2560 * optimization because as was noticed, some apps (warcraft3 for example)
2561 * tend towards setting the same matrix repeatedly for some reason.
2563 * From here on we assume that the new matrix is different, wherever it matters.
2565 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2566 TRACE("The app is setting the same matrix over again\n");
2567 return WINED3D_OK;
2568 } else {
2569 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2573 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2574 where ViewMat = Camera space, WorldMat = world space.
2576 In OpenGL, camera and world space is combined into GL_MODELVIEW
2577 matrix. The Projection matrix stay projection matrix.
2580 /* Capture the times we can just ignore the change for now */
2581 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2582 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2583 /* Handled by the state manager */
2586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2587 return WINED3D_OK;
2590 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2592 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2593 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2594 return WINED3D_OK;
2597 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2598 WINED3DMATRIX *mat = NULL;
2599 WINED3DMATRIX temp;
2601 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2602 * below means it will be recorded in a state block change, but it
2603 * works regardless where it is recorded.
2604 * If this is found to be wrong, change to StateBlock.
2606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2607 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2609 if (State < HIGHEST_TRANSFORMSTATE)
2611 mat = &This->updateStateBlock->transforms[State];
2612 } else {
2613 FIXME("Unhandled transform state!!\n");
2616 multiply_matrix(&temp, mat, pMatrix);
2618 /* Apply change via set transform - will reapply to eg. lights this way */
2619 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2622 /*****
2623 * Get / Set Light
2624 *****/
2625 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2626 you can reference any indexes you want as long as that number max are enabled at any
2627 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2628 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2629 but when recording, just build a chain pretty much of commands to be replayed. */
2631 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2632 float rho;
2633 PLIGHTINFOEL *object = NULL;
2634 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2635 struct list *e;
2637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2638 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2640 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2641 * the gl driver.
2643 if(!pLight) {
2644 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2645 return WINED3DERR_INVALIDCALL;
2648 switch(pLight->Type) {
2649 case WINED3DLIGHT_POINT:
2650 case WINED3DLIGHT_SPOT:
2651 case WINED3DLIGHT_PARALLELPOINT:
2652 case WINED3DLIGHT_GLSPOT:
2653 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2654 * most wanted
2656 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2657 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2658 return WINED3DERR_INVALIDCALL;
2660 break;
2662 case WINED3DLIGHT_DIRECTIONAL:
2663 /* Ignores attenuation */
2664 break;
2666 default:
2667 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2668 return WINED3DERR_INVALIDCALL;
2671 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2672 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2673 if(object->OriginalIndex == Index) break;
2674 object = NULL;
2677 if(!object) {
2678 TRACE("Adding new light\n");
2679 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2680 if(!object) {
2681 ERR("Out of memory error when allocating a light\n");
2682 return E_OUTOFMEMORY;
2684 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2685 object->glIndex = -1;
2686 object->OriginalIndex = Index;
2687 object->changed = TRUE;
2690 /* Initialize the object */
2691 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,
2692 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2693 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2694 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2695 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2696 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2697 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2699 /* Save away the information */
2700 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2702 switch (pLight->Type) {
2703 case WINED3DLIGHT_POINT:
2704 /* Position */
2705 object->lightPosn[0] = pLight->Position.x;
2706 object->lightPosn[1] = pLight->Position.y;
2707 object->lightPosn[2] = pLight->Position.z;
2708 object->lightPosn[3] = 1.0f;
2709 object->cutoff = 180.0f;
2710 /* FIXME: Range */
2711 break;
2713 case WINED3DLIGHT_DIRECTIONAL:
2714 /* Direction */
2715 object->lightPosn[0] = -pLight->Direction.x;
2716 object->lightPosn[1] = -pLight->Direction.y;
2717 object->lightPosn[2] = -pLight->Direction.z;
2718 object->lightPosn[3] = 0.0;
2719 object->exponent = 0.0f;
2720 object->cutoff = 180.0f;
2721 break;
2723 case WINED3DLIGHT_SPOT:
2724 /* Position */
2725 object->lightPosn[0] = pLight->Position.x;
2726 object->lightPosn[1] = pLight->Position.y;
2727 object->lightPosn[2] = pLight->Position.z;
2728 object->lightPosn[3] = 1.0;
2730 /* Direction */
2731 object->lightDirn[0] = pLight->Direction.x;
2732 object->lightDirn[1] = pLight->Direction.y;
2733 object->lightDirn[2] = pLight->Direction.z;
2734 object->lightDirn[3] = 1.0;
2737 * opengl-ish and d3d-ish spot lights use too different models for the
2738 * light "intensity" as a function of the angle towards the main light direction,
2739 * so we only can approximate very roughly.
2740 * however spot lights are rather rarely used in games (if ever used at all).
2741 * furthermore if still used, probably nobody pays attention to such details.
2743 if (pLight->Falloff == 0) {
2744 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2745 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2746 * will always be 1.0 for both of them, and we don't have to care for the
2747 * rest of the rather complex calculation
2749 object->exponent = 0;
2750 } else {
2751 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2752 if (rho < 0.0001) rho = 0.0001f;
2753 object->exponent = -0.3/log(cos(rho/2));
2755 if (object->exponent > 128.0) {
2756 object->exponent = 128.0;
2758 object->cutoff = pLight->Phi*90/M_PI;
2760 /* FIXME: Range */
2761 break;
2763 default:
2764 FIXME("Unrecognized light type %d\n", pLight->Type);
2767 /* Update the live definitions if the light is currently assigned a glIndex */
2768 if (object->glIndex != -1 && !This->isRecordingState) {
2769 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2771 return WINED3D_OK;
2774 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2775 PLIGHTINFOEL *lightInfo = NULL;
2776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2777 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2778 struct list *e;
2779 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2781 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2782 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2783 if(lightInfo->OriginalIndex == Index) break;
2784 lightInfo = NULL;
2787 if (lightInfo == NULL) {
2788 TRACE("Light information requested but light not defined\n");
2789 return WINED3DERR_INVALIDCALL;
2792 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2793 return WINED3D_OK;
2796 /*****
2797 * Get / Set Light Enable
2798 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2799 *****/
2800 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2801 PLIGHTINFOEL *lightInfo = NULL;
2802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2803 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2804 struct list *e;
2805 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2807 /* Tests show true = 128...not clear why */
2808 Enable = Enable? 128: 0;
2810 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2811 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2812 if(lightInfo->OriginalIndex == Index) break;
2813 lightInfo = NULL;
2815 TRACE("Found light: %p\n", lightInfo);
2817 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2818 if (lightInfo == NULL) {
2820 TRACE("Light enabled requested but light not defined, so defining one!\n");
2821 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2823 /* Search for it again! Should be fairly quick as near head of list */
2824 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2825 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2826 if(lightInfo->OriginalIndex == Index) break;
2827 lightInfo = NULL;
2829 if (lightInfo == NULL) {
2830 FIXME("Adding default lights has failed dismally\n");
2831 return WINED3DERR_INVALIDCALL;
2835 lightInfo->enabledChanged = TRUE;
2836 if(!Enable) {
2837 if(lightInfo->glIndex != -1) {
2838 if(!This->isRecordingState) {
2839 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2842 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2843 lightInfo->glIndex = -1;
2844 } else {
2845 TRACE("Light already disabled, nothing to do\n");
2847 lightInfo->enabled = FALSE;
2848 } else {
2849 lightInfo->enabled = TRUE;
2850 if (lightInfo->glIndex != -1) {
2851 /* nop */
2852 TRACE("Nothing to do as light was enabled\n");
2853 } else {
2854 int i;
2855 /* Find a free gl light */
2856 for(i = 0; i < This->maxConcurrentLights; i++) {
2857 if(This->stateBlock->activeLights[i] == NULL) {
2858 This->stateBlock->activeLights[i] = lightInfo;
2859 lightInfo->glIndex = i;
2860 break;
2863 if(lightInfo->glIndex == -1) {
2864 /* Our tests show that Windows returns D3D_OK in this situation, even with
2865 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2866 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2867 * as well for those lights.
2869 * TODO: Test how this affects rendering
2871 FIXME("Too many concurrently active lights\n");
2872 return WINED3D_OK;
2875 /* i == lightInfo->glIndex */
2876 if(!This->isRecordingState) {
2877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2882 return WINED3D_OK;
2885 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2887 PLIGHTINFOEL *lightInfo = NULL;
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 struct list *e;
2890 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2891 TRACE("(%p) : for idx(%d)\n", This, Index);
2893 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2894 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2895 if(lightInfo->OriginalIndex == Index) break;
2896 lightInfo = NULL;
2899 if (lightInfo == NULL) {
2900 TRACE("Light enabled state requested but light not defined\n");
2901 return WINED3DERR_INVALIDCALL;
2903 /* true is 128 according to SetLightEnable */
2904 *pEnable = lightInfo->enabled ? 128 : 0;
2905 return WINED3D_OK;
2908 /*****
2909 * Get / Set Clip Planes
2910 *****/
2911 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2913 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2915 /* Validate Index */
2916 if (Index >= GL_LIMITS(clipplanes)) {
2917 TRACE("Application has requested clipplane this device doesn't support\n");
2918 return WINED3DERR_INVALIDCALL;
2921 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2923 if(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]) {
2927 TRACE("Application is setting old values over, nothing to do\n");
2928 return WINED3D_OK;
2931 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2932 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2933 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2934 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2936 /* Handle recording of state blocks */
2937 if (This->isRecordingState) {
2938 TRACE("Recording... not performing anything\n");
2939 return WINED3D_OK;
2942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2944 return WINED3D_OK;
2947 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2949 TRACE("(%p) : for idx %d\n", This, Index);
2951 /* Validate Index */
2952 if (Index >= GL_LIMITS(clipplanes)) {
2953 TRACE("Application has requested clipplane this device doesn't support\n");
2954 return WINED3DERR_INVALIDCALL;
2957 pPlane[0] = This->stateBlock->clipplane[Index][0];
2958 pPlane[1] = This->stateBlock->clipplane[Index][1];
2959 pPlane[2] = This->stateBlock->clipplane[Index][2];
2960 pPlane[3] = This->stateBlock->clipplane[Index][3];
2961 return WINED3D_OK;
2964 /*****
2965 * Get / Set Clip Plane Status
2966 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2967 *****/
2968 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2970 FIXME("(%p) : stub\n", This);
2971 if (NULL == pClipStatus) {
2972 return WINED3DERR_INVALIDCALL;
2974 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2975 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2976 return WINED3D_OK;
2979 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2981 FIXME("(%p) : stub\n", This);
2982 if (NULL == pClipStatus) {
2983 return WINED3DERR_INVALIDCALL;
2985 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2986 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2987 return WINED3D_OK;
2990 /*****
2991 * Get / Set Material
2992 *****/
2993 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 This->updateStateBlock->changed.material = TRUE;
2997 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2999 /* Handle recording of state blocks */
3000 if (This->isRecordingState) {
3001 TRACE("Recording... not performing anything\n");
3002 return WINED3D_OK;
3005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3006 return WINED3D_OK;
3009 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3011 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
3012 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3013 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3014 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3015 pMaterial->Ambient.b, pMaterial->Ambient.a);
3016 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3017 pMaterial->Specular.b, pMaterial->Specular.a);
3018 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3019 pMaterial->Emissive.b, pMaterial->Emissive.a);
3020 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3022 return WINED3D_OK;
3025 /*****
3026 * Get / Set Indices
3027 *****/
3028 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3029 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3030 IWineD3DIndexBuffer *oldIdxs;
3032 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3033 oldIdxs = This->updateStateBlock->pIndexData;
3035 This->updateStateBlock->changed.indices = TRUE;
3036 This->updateStateBlock->pIndexData = pIndexData;
3038 /* Handle recording of state blocks */
3039 if (This->isRecordingState) {
3040 TRACE("Recording... not performing anything\n");
3041 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3042 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3043 return WINED3D_OK;
3046 if(oldIdxs != pIndexData) {
3047 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3048 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3049 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3051 return WINED3D_OK;
3054 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 *ppIndexData = This->stateBlock->pIndexData;
3059 /* up ref count on ppindexdata */
3060 if (*ppIndexData) {
3061 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3062 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3063 }else{
3064 TRACE("(%p) No index data set\n", This);
3066 TRACE("Returning %p\n", *ppIndexData);
3068 return WINED3D_OK;
3071 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3072 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 TRACE("(%p)->(%d)\n", This, BaseIndex);
3076 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3077 TRACE("Application is setting the old value over, nothing to do\n");
3078 return WINED3D_OK;
3081 This->updateStateBlock->baseVertexIndex = BaseIndex;
3083 if (This->isRecordingState) {
3084 TRACE("Recording... not performing anything\n");
3085 return WINED3D_OK;
3087 /* The base vertex index affects the stream sources */
3088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3089 return WINED3D_OK;
3092 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 TRACE("(%p) : base_index %p\n", This, base_index);
3096 *base_index = This->stateBlock->baseVertexIndex;
3098 TRACE("Returning %u\n", *base_index);
3100 return WINED3D_OK;
3103 /*****
3104 * Get / Set Viewports
3105 *****/
3106 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3109 TRACE("(%p)\n", This);
3110 This->updateStateBlock->changed.viewport = TRUE;
3111 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3113 /* Handle recording of state blocks */
3114 if (This->isRecordingState) {
3115 TRACE("Recording... not performing anything\n");
3116 return WINED3D_OK;
3119 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3120 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3123 return WINED3D_OK;
3127 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 TRACE("(%p)\n", This);
3130 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3131 return WINED3D_OK;
3134 /*****
3135 * Get / Set Render States
3136 * TODO: Verify against dx9 definitions
3137 *****/
3138 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3141 DWORD oldValue = This->stateBlock->renderState[State];
3143 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3145 This->updateStateBlock->changed.renderState[State] = TRUE;
3146 This->updateStateBlock->renderState[State] = Value;
3148 /* Handle recording of state blocks */
3149 if (This->isRecordingState) {
3150 TRACE("Recording... not performing anything\n");
3151 return WINED3D_OK;
3154 /* Compared here and not before the assignment to allow proper stateblock recording */
3155 if(Value == oldValue) {
3156 TRACE("Application is setting the old value over, nothing to do\n");
3157 } else {
3158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3161 return WINED3D_OK;
3164 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3165 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3166 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3167 *pValue = This->stateBlock->renderState[State];
3168 return WINED3D_OK;
3171 /*****
3172 * Get / Set Sampler States
3173 * TODO: Verify against dx9 definitions
3174 *****/
3176 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3178 DWORD oldValue;
3180 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3181 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3183 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3184 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3187 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3188 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3189 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3192 * SetSampler is designed to allow for more than the standard up to 8 textures
3193 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3194 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3196 * http://developer.nvidia.com/object/General_FAQ.html#t6
3198 * There are two new settings for GForce
3199 * the sampler one:
3200 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3201 * and the texture one:
3202 * GL_MAX_TEXTURE_COORDS_ARB.
3203 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3204 ******************/
3206 oldValue = This->stateBlock->samplerState[Sampler][Type];
3207 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3208 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3210 /* Handle recording of state blocks */
3211 if (This->isRecordingState) {
3212 TRACE("Recording... not performing anything\n");
3213 return WINED3D_OK;
3216 if(oldValue == Value) {
3217 TRACE("Application is setting the old value over, nothing to do\n");
3218 return WINED3D_OK;
3221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3223 return WINED3D_OK;
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3229 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3230 This, Sampler, debug_d3dsamplerstate(Type), Type);
3232 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3233 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3236 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3237 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3238 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3240 *Value = This->stateBlock->samplerState[Sampler][Type];
3241 TRACE("(%p) : Returning %#x\n", This, *Value);
3243 return WINED3D_OK;
3246 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3249 This->updateStateBlock->changed.scissorRect = TRUE;
3250 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3251 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3252 return WINED3D_OK;
3254 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3256 if(This->isRecordingState) {
3257 TRACE("Recording... not performing anything\n");
3258 return WINED3D_OK;
3261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3263 return WINED3D_OK;
3266 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3269 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3270 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3271 return WINED3D_OK;
3274 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3276 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3278 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3280 This->updateStateBlock->vertexDecl = pDecl;
3281 This->updateStateBlock->changed.vertexDecl = TRUE;
3283 if (This->isRecordingState) {
3284 TRACE("Recording... not performing anything\n");
3285 return WINED3D_OK;
3286 } else if(pDecl == oldDecl) {
3287 /* Checked after the assignment to allow proper stateblock recording */
3288 TRACE("Application is setting the old declaration over, nothing to do\n");
3289 return WINED3D_OK;
3292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3293 return WINED3D_OK;
3296 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3299 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3301 *ppDecl = This->stateBlock->vertexDecl;
3302 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3303 return WINED3D_OK;
3306 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3308 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3310 This->updateStateBlock->vertexShader = pShader;
3311 This->updateStateBlock->changed.vertexShader = TRUE;
3313 if (This->isRecordingState) {
3314 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3315 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3316 TRACE("Recording... not performing anything\n");
3317 return WINED3D_OK;
3318 } else if(oldShader == pShader) {
3319 /* Checked here to allow proper stateblock recording */
3320 TRACE("App is setting the old shader over, nothing to do\n");
3321 return WINED3D_OK;
3324 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3325 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3326 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3330 return WINED3D_OK;
3333 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3336 if (NULL == ppShader) {
3337 return WINED3DERR_INVALIDCALL;
3339 *ppShader = This->stateBlock->vertexShader;
3340 if( NULL != *ppShader)
3341 IWineD3DVertexShader_AddRef(*ppShader);
3343 TRACE("(%p) : returning %p\n", This, *ppShader);
3344 return WINED3D_OK;
3347 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3348 IWineD3DDevice *iface,
3349 UINT start,
3350 CONST BOOL *srcData,
3351 UINT count) {
3353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3354 int i, cnt = min(count, MAX_CONST_B - start);
3356 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3357 iface, srcData, start, count);
3359 if (srcData == NULL || cnt < 0)
3360 return WINED3DERR_INVALIDCALL;
3362 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3363 for (i = 0; i < cnt; i++)
3364 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3366 for (i = start; i < cnt + start; ++i) {
3367 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3372 return WINED3D_OK;
3375 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3376 IWineD3DDevice *iface,
3377 UINT start,
3378 BOOL *dstData,
3379 UINT count) {
3381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3382 int cnt = min(count, MAX_CONST_B - start);
3384 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3385 iface, dstData, start, count);
3387 if (dstData == NULL || cnt < 0)
3388 return WINED3DERR_INVALIDCALL;
3390 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3391 return WINED3D_OK;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3395 IWineD3DDevice *iface,
3396 UINT start,
3397 CONST int *srcData,
3398 UINT count) {
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 int i, cnt = min(count, MAX_CONST_I - start);
3403 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3404 iface, srcData, start, count);
3406 if (srcData == NULL || cnt < 0)
3407 return WINED3DERR_INVALIDCALL;
3409 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3410 for (i = 0; i < cnt; i++)
3411 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3412 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3414 for (i = start; i < cnt + start; ++i) {
3415 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3418 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3420 return WINED3D_OK;
3423 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3424 IWineD3DDevice *iface,
3425 UINT start,
3426 int *dstData,
3427 UINT count) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3430 int cnt = min(count, MAX_CONST_I - start);
3432 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3433 iface, dstData, start, count);
3435 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3436 return WINED3DERR_INVALIDCALL;
3438 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3439 return WINED3D_OK;
3442 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3443 IWineD3DDevice *iface,
3444 UINT start,
3445 CONST float *srcData,
3446 UINT count) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 int i;
3451 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3452 iface, srcData, start, count);
3454 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3455 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3456 return WINED3DERR_INVALIDCALL;
3458 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3459 if(TRACE_ON(d3d)) {
3460 for (i = 0; i < count; i++)
3461 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3462 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3465 for (i = start; i < count + start; ++i) {
3466 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3467 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3468 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3469 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3470 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3472 ptr->idx[ptr->count++] = i;
3473 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3477 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3479 return WINED3D_OK;
3482 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3483 IWineD3DDevice *iface,
3484 UINT start,
3485 float *dstData,
3486 UINT count) {
3488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3489 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3491 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3492 iface, dstData, start, count);
3494 if (dstData == NULL || cnt < 0)
3495 return WINED3DERR_INVALIDCALL;
3497 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3498 return WINED3D_OK;
3501 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3502 DWORD i;
3503 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3508 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3509 int i = This->rev_tex_unit_map[unit];
3510 int j = This->texUnitMap[stage];
3512 This->texUnitMap[stage] = unit;
3513 if (i != -1 && i != stage) {
3514 This->texUnitMap[i] = -1;
3517 This->rev_tex_unit_map[unit] = stage;
3518 if (j != -1 && j != unit) {
3519 This->rev_tex_unit_map[j] = -1;
3523 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3524 int i;
3526 for (i = 0; i < MAX_TEXTURES; ++i) {
3527 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3528 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3529 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3530 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3531 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3532 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3533 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3534 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3536 if (color_op == WINED3DTOP_DISABLE) {
3537 /* Not used, and disable higher stages */
3538 while (i < MAX_TEXTURES) {
3539 This->fixed_function_usage_map[i] = FALSE;
3540 ++i;
3542 break;
3545 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3546 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3547 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3548 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3549 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3550 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3551 This->fixed_function_usage_map[i] = TRUE;
3552 } else {
3553 This->fixed_function_usage_map[i] = FALSE;
3556 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3557 This->fixed_function_usage_map[i+1] = TRUE;
3562 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3563 int i, tex;
3565 device_update_fixed_function_usage_map(This);
3567 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3568 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3569 if (!This->fixed_function_usage_map[i]) continue;
3571 if (This->texUnitMap[i] != i) {
3572 device_map_stage(This, i, i);
3573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3574 markTextureStagesDirty(This, i);
3577 return;
3580 /* Now work out the mapping */
3581 tex = 0;
3582 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3583 if (!This->fixed_function_usage_map[i]) continue;
3585 if (This->texUnitMap[i] != tex) {
3586 device_map_stage(This, i, tex);
3587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3588 markTextureStagesDirty(This, i);
3591 ++tex;
3595 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3596 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3597 int i;
3599 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3600 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3601 device_map_stage(This, i, i);
3602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3603 if (i < MAX_TEXTURES) {
3604 markTextureStagesDirty(This, i);
3610 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3611 int current_mapping = This->rev_tex_unit_map[unit];
3613 if (current_mapping == -1) {
3614 /* Not currently used */
3615 return TRUE;
3618 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3619 /* Used by a fragment sampler */
3621 if (!pshader_sampler_tokens) {
3622 /* No pixel shader, check fixed function */
3623 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3626 /* Pixel shader, check the shader's sampler map */
3627 return !pshader_sampler_tokens[current_mapping];
3630 /* Used by a vertex sampler */
3631 return !vshader_sampler_tokens[current_mapping];
3634 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3635 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3636 DWORD *pshader_sampler_tokens = NULL;
3637 int start = GL_LIMITS(combined_samplers) - 1;
3638 int i;
3640 if (ps) {
3641 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3643 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3644 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3645 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3648 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3649 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3650 if (vshader_sampler_tokens[i]) {
3651 if (This->texUnitMap[vsampler_idx] != -1) {
3652 /* Already mapped somewhere */
3653 continue;
3656 while (start >= 0) {
3657 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3658 device_map_stage(This, vsampler_idx, start);
3659 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3661 --start;
3662 break;
3665 --start;
3671 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3672 BOOL vs = use_vs(This);
3673 BOOL ps = use_ps(This);
3675 * Rules are:
3676 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3677 * that would be really messy and require shader recompilation
3678 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3679 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3681 if (ps) {
3682 device_map_psamplers(This);
3683 } else {
3684 device_map_fixed_function_samplers(This);
3687 if (vs) {
3688 device_map_vsamplers(This, ps);
3692 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3694 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3695 This->updateStateBlock->pixelShader = pShader;
3696 This->updateStateBlock->changed.pixelShader = TRUE;
3698 /* Handle recording of state blocks */
3699 if (This->isRecordingState) {
3700 TRACE("Recording... not performing anything\n");
3703 if (This->isRecordingState) {
3704 TRACE("Recording... not performing anything\n");
3705 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3706 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3707 return WINED3D_OK;
3710 if(pShader == oldShader) {
3711 TRACE("App is setting the old pixel shader over, nothing to do\n");
3712 return WINED3D_OK;
3715 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3716 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3718 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3719 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3721 return WINED3D_OK;
3724 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3727 if (NULL == ppShader) {
3728 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3729 return WINED3DERR_INVALIDCALL;
3732 *ppShader = This->stateBlock->pixelShader;
3733 if (NULL != *ppShader) {
3734 IWineD3DPixelShader_AddRef(*ppShader);
3736 TRACE("(%p) : returning %p\n", This, *ppShader);
3737 return WINED3D_OK;
3740 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3741 IWineD3DDevice *iface,
3742 UINT start,
3743 CONST BOOL *srcData,
3744 UINT count) {
3746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3747 int i, cnt = min(count, MAX_CONST_B - start);
3749 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3750 iface, srcData, start, count);
3752 if (srcData == NULL || cnt < 0)
3753 return WINED3DERR_INVALIDCALL;
3755 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3756 for (i = 0; i < cnt; i++)
3757 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3759 for (i = start; i < cnt + start; ++i) {
3760 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3765 return WINED3D_OK;
3768 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3769 IWineD3DDevice *iface,
3770 UINT start,
3771 BOOL *dstData,
3772 UINT count) {
3774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3775 int cnt = min(count, MAX_CONST_B - start);
3777 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3778 iface, dstData, start, count);
3780 if (dstData == NULL || cnt < 0)
3781 return WINED3DERR_INVALIDCALL;
3783 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3784 return WINED3D_OK;
3787 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3788 IWineD3DDevice *iface,
3789 UINT start,
3790 CONST int *srcData,
3791 UINT count) {
3793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3794 int i, cnt = min(count, MAX_CONST_I - start);
3796 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3797 iface, srcData, start, count);
3799 if (srcData == NULL || cnt < 0)
3800 return WINED3DERR_INVALIDCALL;
3802 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3803 for (i = 0; i < cnt; i++)
3804 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3805 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3807 for (i = start; i < cnt + start; ++i) {
3808 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3813 return WINED3D_OK;
3816 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3817 IWineD3DDevice *iface,
3818 UINT start,
3819 int *dstData,
3820 UINT count) {
3822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3823 int cnt = min(count, MAX_CONST_I - start);
3825 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3826 iface, dstData, start, count);
3828 if (dstData == NULL || cnt < 0)
3829 return WINED3DERR_INVALIDCALL;
3831 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3832 return WINED3D_OK;
3835 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3836 IWineD3DDevice *iface,
3837 UINT start,
3838 CONST float *srcData,
3839 UINT count) {
3841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3842 int i;
3844 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3845 iface, srcData, start, count);
3847 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3848 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3849 return WINED3DERR_INVALIDCALL;
3851 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3852 if(TRACE_ON(d3d)) {
3853 for (i = 0; i < count; i++)
3854 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3855 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3858 for (i = start; i < count + start; ++i) {
3859 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3860 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3861 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3862 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3863 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3865 ptr->idx[ptr->count++] = i;
3866 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3872 return WINED3D_OK;
3875 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3876 IWineD3DDevice *iface,
3877 UINT start,
3878 float *dstData,
3879 UINT count) {
3881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3882 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3884 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3885 iface, dstData, start, count);
3887 if (dstData == NULL || cnt < 0)
3888 return WINED3DERR_INVALIDCALL;
3890 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3891 return WINED3D_OK;
3894 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3895 static HRESULT
3896 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3897 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3898 unsigned int i;
3899 DWORD DestFVF = dest->fvf;
3900 WINED3DVIEWPORT vp;
3901 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3902 BOOL doClip;
3903 int numTextures;
3905 if (lpStrideData->u.s.normal.lpData) {
3906 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3909 if (lpStrideData->u.s.position.lpData == NULL) {
3910 ERR("Source has no position mask\n");
3911 return WINED3DERR_INVALIDCALL;
3914 /* We might access VBOs from this code, so hold the lock */
3915 ENTER_GL();
3917 if (dest->resource.allocatedMemory == NULL) {
3918 /* This may happen if we do direct locking into a vbo. Unlikely,
3919 * but theoretically possible(ddraw processvertices test)
3921 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3922 if(!dest->resource.allocatedMemory) {
3923 LEAVE_GL();
3924 ERR("Out of memory\n");
3925 return E_OUTOFMEMORY;
3927 if(dest->vbo) {
3928 void *src;
3929 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3930 checkGLcall("glBindBufferARB");
3931 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3932 if(src) {
3933 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3935 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3936 checkGLcall("glUnmapBufferARB");
3940 /* Get a pointer into the destination vbo(create one if none exists) and
3941 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3943 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3944 CreateVBO(dest);
3947 if(dest->vbo) {
3948 unsigned char extrabytes = 0;
3949 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3950 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3951 * this may write 4 extra bytes beyond the area that should be written
3953 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3954 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3955 if(!dest_conv_addr) {
3956 ERR("Out of memory\n");
3957 /* Continue without storing converted vertices */
3959 dest_conv = dest_conv_addr;
3962 /* Should I clip?
3963 * a) WINED3DRS_CLIPPING is enabled
3964 * b) WINED3DVOP_CLIP is passed
3966 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3967 static BOOL warned = FALSE;
3969 * The clipping code is not quite correct. Some things need
3970 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3971 * so disable clipping for now.
3972 * (The graphics in Half-Life are broken, and my processvertices
3973 * test crashes with IDirect3DDevice3)
3974 doClip = TRUE;
3976 doClip = FALSE;
3977 if(!warned) {
3978 warned = TRUE;
3979 FIXME("Clipping is broken and disabled for now\n");
3981 } else doClip = FALSE;
3982 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3984 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3985 WINED3DTS_VIEW,
3986 &view_mat);
3987 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3988 WINED3DTS_PROJECTION,
3989 &proj_mat);
3990 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3991 WINED3DTS_WORLDMATRIX(0),
3992 &world_mat);
3994 TRACE("View mat:\n");
3995 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);
3996 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);
3997 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);
3998 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);
4000 TRACE("Proj mat:\n");
4001 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);
4002 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);
4003 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);
4004 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);
4006 TRACE("World mat:\n");
4007 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);
4008 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);
4009 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);
4010 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);
4012 /* Get the viewport */
4013 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4014 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4015 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4017 multiply_matrix(&mat,&view_mat,&world_mat);
4018 multiply_matrix(&mat,&proj_mat,&mat);
4020 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4022 for (i = 0; i < dwCount; i+= 1) {
4023 unsigned int tex_index;
4025 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4026 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4027 /* The position first */
4028 float *p =
4029 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4030 float x, y, z, rhw;
4031 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4033 /* Multiplication with world, view and projection matrix */
4034 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);
4035 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);
4036 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);
4037 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);
4039 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4041 /* WARNING: The following things are taken from d3d7 and were not yet checked
4042 * against d3d8 or d3d9!
4045 /* Clipping conditions: From
4046 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4048 * A vertex is clipped if it does not match the following requirements
4049 * -rhw < x <= rhw
4050 * -rhw < y <= rhw
4051 * 0 < z <= rhw
4052 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4054 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4055 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4059 if( !doClip ||
4060 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4061 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4062 ( rhw > eps ) ) ) {
4064 /* "Normal" viewport transformation (not clipped)
4065 * 1) The values are divided by rhw
4066 * 2) The y axis is negative, so multiply it with -1
4067 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4068 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4069 * 4) Multiply x with Width/2 and add Width/2
4070 * 5) The same for the height
4071 * 6) Add the viewpoint X and Y to the 2D coordinates and
4072 * The minimum Z value to z
4073 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4075 * Well, basically it's simply a linear transformation into viewport
4076 * coordinates
4079 x /= rhw;
4080 y /= rhw;
4081 z /= rhw;
4083 y *= -1;
4085 x *= vp.Width / 2;
4086 y *= vp.Height / 2;
4087 z *= vp.MaxZ - vp.MinZ;
4089 x += vp.Width / 2 + vp.X;
4090 y += vp.Height / 2 + vp.Y;
4091 z += vp.MinZ;
4093 rhw = 1 / rhw;
4094 } else {
4095 /* That vertex got clipped
4096 * Contrary to OpenGL it is not dropped completely, it just
4097 * undergoes a different calculation.
4099 TRACE("Vertex got clipped\n");
4100 x += rhw;
4101 y += rhw;
4103 x /= 2;
4104 y /= 2;
4106 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4107 * outside of the main vertex buffer memory. That needs some more
4108 * investigation...
4112 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4115 ( (float *) dest_ptr)[0] = x;
4116 ( (float *) dest_ptr)[1] = y;
4117 ( (float *) dest_ptr)[2] = z;
4118 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4120 dest_ptr += 3 * sizeof(float);
4122 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4123 dest_ptr += sizeof(float);
4126 if(dest_conv) {
4127 float w = 1 / rhw;
4128 ( (float *) dest_conv)[0] = x * w;
4129 ( (float *) dest_conv)[1] = y * w;
4130 ( (float *) dest_conv)[2] = z * w;
4131 ( (float *) dest_conv)[3] = w;
4133 dest_conv += 3 * sizeof(float);
4135 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4136 dest_conv += sizeof(float);
4140 if (DestFVF & WINED3DFVF_PSIZE) {
4141 dest_ptr += sizeof(DWORD);
4142 if(dest_conv) dest_conv += sizeof(DWORD);
4144 if (DestFVF & WINED3DFVF_NORMAL) {
4145 float *normal =
4146 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4147 /* AFAIK this should go into the lighting information */
4148 FIXME("Didn't expect the destination to have a normal\n");
4149 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4150 if(dest_conv) {
4151 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4155 if (DestFVF & WINED3DFVF_DIFFUSE) {
4156 DWORD *color_d =
4157 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4158 if(!color_d) {
4159 static BOOL warned = FALSE;
4161 if(!warned) {
4162 ERR("No diffuse color in source, but destination has one\n");
4163 warned = TRUE;
4166 *( (DWORD *) dest_ptr) = 0xffffffff;
4167 dest_ptr += sizeof(DWORD);
4169 if(dest_conv) {
4170 *( (DWORD *) dest_conv) = 0xffffffff;
4171 dest_conv += sizeof(DWORD);
4174 else {
4175 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4176 if(dest_conv) {
4177 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4178 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4179 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4180 dest_conv += sizeof(DWORD);
4185 if (DestFVF & WINED3DFVF_SPECULAR) {
4186 /* What's the color value in the feedback buffer? */
4187 DWORD *color_s =
4188 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4189 if(!color_s) {
4190 static BOOL warned = FALSE;
4192 if(!warned) {
4193 ERR("No specular color in source, but destination has one\n");
4194 warned = TRUE;
4197 *( (DWORD *) dest_ptr) = 0xFF000000;
4198 dest_ptr += sizeof(DWORD);
4200 if(dest_conv) {
4201 *( (DWORD *) dest_conv) = 0xFF000000;
4202 dest_conv += sizeof(DWORD);
4205 else {
4206 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4207 if(dest_conv) {
4208 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4209 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4210 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4211 dest_conv += sizeof(DWORD);
4216 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4217 float *tex_coord =
4218 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4219 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4220 if(!tex_coord) {
4221 ERR("No source texture, but destination requests one\n");
4222 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4223 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4225 else {
4226 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4227 if(dest_conv) {
4228 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4234 if(dest_conv) {
4235 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4236 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4237 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4238 dwCount * get_flexible_vertex_size(DestFVF),
4239 dest_conv_addr));
4240 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4241 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4244 LEAVE_GL();
4246 return WINED3D_OK;
4248 #undef copy_and_next
4250 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4252 WineDirect3DVertexStridedData strided;
4253 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4254 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4256 if(pVertexDecl) {
4257 ERR("Output vertex declaration not implemented yet\n");
4260 /* Need any context to write to the vbo. */
4261 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4263 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4264 * control the streamIsUP flag, thus restore it afterwards.
4266 This->stateBlock->streamIsUP = FALSE;
4267 memset(&strided, 0, sizeof(strided));
4268 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4269 This->stateBlock->streamIsUP = streamWasUP;
4271 if(vbo || SrcStartIndex) {
4272 unsigned int i;
4273 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4274 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4276 * Also get the start index in, but only loop over all elements if there's something to add at all.
4278 #define FIXSRC(type) \
4279 if(strided.u.s.type.VBO) { \
4280 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4281 strided.u.s.type.VBO = 0; \
4282 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4283 ENTER_GL(); \
4284 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4285 vb->vbo = 0; \
4286 LEAVE_GL(); \
4288 if(strided.u.s.type.lpData) { \
4289 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4291 FIXSRC(position);
4292 FIXSRC(blendWeights);
4293 FIXSRC(blendMatrixIndices);
4294 FIXSRC(normal);
4295 FIXSRC(pSize);
4296 FIXSRC(diffuse);
4297 FIXSRC(specular);
4298 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4299 FIXSRC(texCoords[i]);
4301 FIXSRC(position2);
4302 FIXSRC(normal2);
4303 FIXSRC(tangent);
4304 FIXSRC(binormal);
4305 FIXSRC(tessFactor);
4306 FIXSRC(fog);
4307 FIXSRC(depth);
4308 FIXSRC(sample);
4309 #undef FIXSRC
4312 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4315 /*****
4316 * Get / Set Texture Stage States
4317 * TODO: Verify against dx9 definitions
4318 *****/
4319 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4321 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4323 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4325 if (Stage >= MAX_TEXTURES) {
4326 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4327 return WINED3D_OK;
4330 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4331 This->updateStateBlock->textureState[Stage][Type] = Value;
4333 if (This->isRecordingState) {
4334 TRACE("Recording... not performing anything\n");
4335 return WINED3D_OK;
4338 /* Checked after the assignments to allow proper stateblock recording */
4339 if(oldValue == Value) {
4340 TRACE("App is setting the old value over, nothing to do\n");
4341 return WINED3D_OK;
4344 if(Stage > This->stateBlock->lowest_disabled_stage &&
4345 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4346 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4347 * Changes in other states are important on disabled stages too
4349 return WINED3D_OK;
4352 if(Type == WINED3DTSS_COLOROP) {
4353 int i;
4355 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4356 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4357 * they have to be disabled
4359 * The current stage is dirtified below.
4361 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4362 TRACE("Additionally dirtifying stage %d\n", i);
4363 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4365 This->stateBlock->lowest_disabled_stage = Stage;
4366 TRACE("New lowest disabled: %d\n", Stage);
4367 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4368 /* Previously disabled stage enabled. Stages above it may need enabling
4369 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4370 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4372 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4375 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4376 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4377 break;
4379 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4382 This->stateBlock->lowest_disabled_stage = i;
4383 TRACE("New lowest disabled: %d\n", i);
4385 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4386 /* TODO: Built a stage -> texture unit mapping for register combiners */
4390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4392 return WINED3D_OK;
4395 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4397 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4398 *pValue = This->updateStateBlock->textureState[Stage][Type];
4399 return WINED3D_OK;
4402 /*****
4403 * Get / Set Texture
4404 *****/
4405 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4407 IWineD3DBaseTexture *oldTexture;
4409 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4411 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4412 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4415 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4416 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4417 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4420 oldTexture = This->updateStateBlock->textures[Stage];
4422 if(pTexture != NULL) {
4423 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4425 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4426 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4427 return WINED3DERR_INVALIDCALL;
4429 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4432 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4433 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4435 This->updateStateBlock->changed.textures[Stage] = TRUE;
4436 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4437 This->updateStateBlock->textures[Stage] = pTexture;
4439 /* Handle recording of state blocks */
4440 if (This->isRecordingState) {
4441 TRACE("Recording... not performing anything\n");
4442 return WINED3D_OK;
4445 if(oldTexture == pTexture) {
4446 TRACE("App is setting the same texture again, nothing to do\n");
4447 return WINED3D_OK;
4450 /** NOTE: MSDN says that setTexture increases the reference count,
4451 * and that the application must set the texture back to null (or have a leaky application),
4452 * This means we should pass the refcount up to the parent
4453 *******************************/
4454 if (NULL != This->updateStateBlock->textures[Stage]) {
4455 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4456 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4458 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4459 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4460 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4461 * so the COLOROP and ALPHAOP have to be dirtified.
4463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4466 if(bindCount == 1) {
4467 new->baseTexture.sampler = Stage;
4469 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4473 if (NULL != oldTexture) {
4474 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4475 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4477 IWineD3DBaseTexture_Release(oldTexture);
4478 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4480 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4483 if(bindCount && old->baseTexture.sampler == Stage) {
4484 int i;
4485 /* Have to do a search for the other sampler(s) where the texture is bound to
4486 * Shouldn't happen as long as apps bind a texture only to one stage
4488 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4489 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4490 if(This->updateStateBlock->textures[i] == oldTexture) {
4491 old->baseTexture.sampler = i;
4492 break;
4498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4500 return WINED3D_OK;
4503 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4506 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4508 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4509 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4512 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4513 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4514 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4517 *ppTexture=This->stateBlock->textures[Stage];
4518 if (*ppTexture)
4519 IWineD3DBaseTexture_AddRef(*ppTexture);
4521 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4523 return WINED3D_OK;
4526 /*****
4527 * Get Back Buffer
4528 *****/
4529 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4530 IWineD3DSurface **ppBackBuffer) {
4531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4532 IWineD3DSwapChain *swapChain;
4533 HRESULT hr;
4535 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4537 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4538 if (hr == WINED3D_OK) {
4539 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4540 IWineD3DSwapChain_Release(swapChain);
4541 } else {
4542 *ppBackBuffer = NULL;
4544 return hr;
4547 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4548 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4549 WARN("(%p) : stub, calling idirect3d for now\n", This);
4550 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4553 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4555 IWineD3DSwapChain *swapChain;
4556 HRESULT hr;
4558 if(iSwapChain > 0) {
4559 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4560 if (hr == WINED3D_OK) {
4561 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4562 IWineD3DSwapChain_Release(swapChain);
4563 } else {
4564 FIXME("(%p) Error getting display mode\n", This);
4566 } else {
4567 /* Don't read the real display mode,
4568 but return the stored mode instead. X11 can't change the color
4569 depth, and some apps are pretty angry if they SetDisplayMode from
4570 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4572 Also don't relay to the swapchain because with ddraw it's possible
4573 that there isn't a swapchain at all */
4574 pMode->Width = This->ddraw_width;
4575 pMode->Height = This->ddraw_height;
4576 pMode->Format = This->ddraw_format;
4577 pMode->RefreshRate = 0;
4578 hr = WINED3D_OK;
4581 return hr;
4584 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 TRACE("(%p)->(%p)\n", This, hWnd);
4588 if(This->ddraw_fullscreen) {
4589 if(This->ddraw_window && This->ddraw_window != hWnd) {
4590 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4592 if(hWnd && This->ddraw_window != hWnd) {
4593 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4597 This->ddraw_window = hWnd;
4598 return WINED3D_OK;
4601 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4603 TRACE("(%p)->(%p)\n", This, hWnd);
4605 *hWnd = This->ddraw_window;
4606 return WINED3D_OK;
4609 /*****
4610 * Stateblock related functions
4611 *****/
4613 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4615 IWineD3DStateBlockImpl *object;
4616 HRESULT temp_result;
4617 int i;
4619 TRACE("(%p)\n", This);
4621 if (This->isRecordingState) {
4622 return WINED3DERR_INVALIDCALL;
4625 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4626 if (NULL == object ) {
4627 FIXME("(%p)Error allocating memory for stateblock\n", This);
4628 return E_OUTOFMEMORY;
4630 TRACE("(%p) created object %p\n", This, object);
4631 object->wineD3DDevice= This;
4632 /** FIXME: object->parent = parent; **/
4633 object->parent = NULL;
4634 object->blockType = WINED3DSBT_RECORDED;
4635 object->ref = 1;
4636 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4638 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4639 list_init(&object->lightMap[i]);
4642 temp_result = allocate_shader_constants(object);
4643 if (WINED3D_OK != temp_result)
4644 return temp_result;
4646 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4647 This->updateStateBlock = object;
4648 This->isRecordingState = TRUE;
4650 TRACE("(%p) recording stateblock %p\n",This , object);
4651 return WINED3D_OK;
4654 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4656 unsigned int i, j;
4657 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4659 if (!This->isRecordingState) {
4660 FIXME("(%p) not recording! returning error\n", This);
4661 *ppStateBlock = NULL;
4662 return WINED3DERR_INVALIDCALL;
4665 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4666 if(object->changed.renderState[i]) {
4667 object->contained_render_states[object->num_contained_render_states] = i;
4668 object->num_contained_render_states++;
4671 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4672 if(object->changed.transform[i]) {
4673 object->contained_transform_states[object->num_contained_transform_states] = i;
4674 object->num_contained_transform_states++;
4677 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4678 if(object->changed.vertexShaderConstantsF[i]) {
4679 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4680 object->num_contained_vs_consts_f++;
4683 for(i = 0; i < MAX_CONST_I; i++) {
4684 if(object->changed.vertexShaderConstantsI[i]) {
4685 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4686 object->num_contained_vs_consts_i++;
4689 for(i = 0; i < MAX_CONST_B; i++) {
4690 if(object->changed.vertexShaderConstantsB[i]) {
4691 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4692 object->num_contained_vs_consts_b++;
4695 for(i = 0; i < MAX_CONST_I; i++) {
4696 if(object->changed.pixelShaderConstantsI[i]) {
4697 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4698 object->num_contained_ps_consts_i++;
4701 for(i = 0; i < MAX_CONST_B; i++) {
4702 if(object->changed.pixelShaderConstantsB[i]) {
4703 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4704 object->num_contained_ps_consts_b++;
4707 for(i = 0; i < MAX_TEXTURES; i++) {
4708 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4709 if(object->changed.textureState[i][j]) {
4710 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4711 object->contained_tss_states[object->num_contained_tss_states].state = j;
4712 object->num_contained_tss_states++;
4716 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4717 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4718 if(object->changed.samplerState[i][j]) {
4719 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4720 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4721 object->num_contained_sampler_states++;
4726 *ppStateBlock = (IWineD3DStateBlock*) object;
4727 This->isRecordingState = FALSE;
4728 This->updateStateBlock = This->stateBlock;
4729 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4730 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4731 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4732 return WINED3D_OK;
4735 /*****
4736 * Scene related functions
4737 *****/
4738 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4739 /* At the moment we have no need for any functionality at the beginning
4740 of a scene */
4741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4742 TRACE("(%p)\n", This);
4744 if(This->inScene) {
4745 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4746 return WINED3DERR_INVALIDCALL;
4748 This->inScene = TRUE;
4749 return WINED3D_OK;
4752 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4754 TRACE("(%p)\n", This);
4756 if(!This->inScene) {
4757 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4758 return WINED3DERR_INVALIDCALL;
4761 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4762 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4763 ENTER_GL();
4764 glFlush();
4765 checkGLcall("glFlush");
4766 LEAVE_GL();
4768 This->inScene = FALSE;
4769 return WINED3D_OK;
4772 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4773 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4774 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4776 IWineD3DSwapChain *swapChain = NULL;
4777 int i;
4778 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4780 TRACE("(%p) Presenting the frame\n", This);
4782 for(i = 0 ; i < swapchains ; i ++) {
4784 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4785 TRACE("presentinng chain %d, %p\n", i, swapChain);
4786 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4787 IWineD3DSwapChain_Release(swapChain);
4790 return WINED3D_OK;
4793 /* Not called from the VTable (internal subroutine) */
4794 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4795 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4796 float Z, DWORD Stencil) {
4797 GLbitfield glMask = 0;
4798 unsigned int i;
4799 WINED3DRECT curRect;
4800 RECT vp_rect;
4801 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4802 UINT drawable_width, drawable_height;
4804 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4805 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4806 * for the cleared parts, and the untouched parts.
4808 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4809 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4810 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4811 * checking all this if the dest surface is in the drawable anyway.
4813 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4814 while(1) {
4815 if(vp->X != 0 || vp->Y != 0 ||
4816 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4817 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4818 break;
4820 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4821 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4822 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4823 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4824 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4825 break;
4827 if(Count > 0 && pRects && (
4828 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4829 pRects[0].x2 < target->currentDesc.Width ||
4830 pRects[0].y2 < target->currentDesc.Height)) {
4831 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4832 break;
4834 break;
4838 target->get_drawable_size(target, &drawable_width, &drawable_height);
4840 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4841 ENTER_GL();
4843 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4844 apply_fbo_state((IWineD3DDevice *) This);
4847 /* Only set the values up once, as they are not changing */
4848 if (Flags & WINED3DCLEAR_STENCIL) {
4849 glClearStencil(Stencil);
4850 checkGLcall("glClearStencil");
4851 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4852 glStencilMask(0xFFFFFFFF);
4855 if (Flags & WINED3DCLEAR_ZBUFFER) {
4856 glDepthMask(GL_TRUE);
4857 glClearDepth(Z);
4858 checkGLcall("glClearDepth");
4859 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4860 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4863 if (Flags & WINED3DCLEAR_TARGET) {
4864 TRACE("Clearing screen with glClear to color %x\n", Color);
4865 glClearColor(D3DCOLOR_R(Color),
4866 D3DCOLOR_G(Color),
4867 D3DCOLOR_B(Color),
4868 D3DCOLOR_A(Color));
4869 checkGLcall("glClearColor");
4871 /* Clear ALL colors! */
4872 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4873 glMask = glMask | GL_COLOR_BUFFER_BIT;
4876 vp_rect.left = vp->X;
4877 vp_rect.top = vp->Y;
4878 vp_rect.right = vp->X + vp->Width;
4879 vp_rect.bottom = vp->Y + vp->Height;
4880 if (!(Count > 0 && pRects)) {
4881 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4882 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4884 if(This->render_offscreen) {
4885 glScissor(vp_rect.left, vp_rect.top,
4886 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4887 } else {
4888 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4889 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4891 checkGLcall("glScissor");
4892 glClear(glMask);
4893 checkGLcall("glClear");
4894 } else {
4895 /* Now process each rect in turn */
4896 for (i = 0; i < Count; i++) {
4897 /* Note gl uses lower left, width/height */
4898 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4899 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4900 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4902 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4903 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4904 curRect.x1, (target->currentDesc.Height - curRect.y2),
4905 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4907 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4908 * The rectangle is not cleared, no error is returned, but further rectanlges are
4909 * still cleared if they are valid
4911 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4912 TRACE("Rectangle with negative dimensions, ignoring\n");
4913 continue;
4916 if(This->render_offscreen) {
4917 glScissor(curRect.x1, curRect.y1,
4918 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4919 } else {
4920 glScissor(curRect.x1, drawable_height - curRect.y2,
4921 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4923 checkGLcall("glScissor");
4925 glClear(glMask);
4926 checkGLcall("glClear");
4930 /* Restore the old values (why..?) */
4931 if (Flags & WINED3DCLEAR_STENCIL) {
4932 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4934 if (Flags & WINED3DCLEAR_TARGET) {
4935 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4936 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4937 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4938 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4939 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4941 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4942 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4944 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4945 /* TODO: Move the fbo logic into ModifyLocation() */
4946 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4947 target->Flags |= SFLAG_INTEXTURE;
4950 LEAVE_GL();
4952 return WINED3D_OK;
4955 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4956 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4958 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4960 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4961 Count, pRects, Flags, Color, Z, Stencil);
4963 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4964 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4965 /* TODO: What about depth stencil buffers without stencil bits? */
4966 return WINED3DERR_INVALIDCALL;
4969 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4972 /*****
4973 * Drawing functions
4974 *****/
4975 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4976 UINT PrimitiveCount) {
4978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4980 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4981 debug_d3dprimitivetype(PrimitiveType),
4982 StartVertex, PrimitiveCount);
4984 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4985 if(This->stateBlock->streamIsUP) {
4986 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4987 This->stateBlock->streamIsUP = FALSE;
4990 if(This->stateBlock->loadBaseVertexIndex != 0) {
4991 This->stateBlock->loadBaseVertexIndex = 0;
4992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4994 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4995 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4996 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4997 return WINED3D_OK;
5000 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5001 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5002 WINED3DPRIMITIVETYPE PrimitiveType,
5003 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5006 UINT idxStride = 2;
5007 IWineD3DIndexBuffer *pIB;
5008 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5009 GLuint vbo;
5011 pIB = This->stateBlock->pIndexData;
5012 if (!pIB) {
5013 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5014 * without an index buffer set. (The first time at least...)
5015 * D3D8 simply dies, but I doubt it can do much harm to return
5016 * D3DERR_INVALIDCALL there as well. */
5017 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5018 return WINED3DERR_INVALIDCALL;
5021 if(This->stateBlock->streamIsUP) {
5022 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5023 This->stateBlock->streamIsUP = FALSE;
5025 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5027 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5028 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5029 minIndex, NumVertices, startIndex, primCount);
5031 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5032 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5033 idxStride = 2;
5034 } else {
5035 idxStride = 4;
5038 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5039 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5043 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5044 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5046 return WINED3D_OK;
5049 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5050 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5051 UINT VertexStreamZeroStride) {
5052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5053 IWineD3DVertexBuffer *vb;
5055 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5056 debug_d3dprimitivetype(PrimitiveType),
5057 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5059 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5060 vb = This->stateBlock->streamSource[0];
5061 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5062 if(vb) IWineD3DVertexBuffer_Release(vb);
5063 This->stateBlock->streamOffset[0] = 0;
5064 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5065 This->stateBlock->streamIsUP = TRUE;
5066 This->stateBlock->loadBaseVertexIndex = 0;
5068 /* TODO: Only mark dirty if drawing from a different UP address */
5069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5071 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5072 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5074 /* MSDN specifies stream zero settings must be set to NULL */
5075 This->stateBlock->streamStride[0] = 0;
5076 This->stateBlock->streamSource[0] = NULL;
5078 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5079 * the new stream sources or use UP drawing again
5081 return WINED3D_OK;
5084 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5085 UINT MinVertexIndex, UINT NumVertices,
5086 UINT PrimitiveCount, CONST void* pIndexData,
5087 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5088 UINT VertexStreamZeroStride) {
5089 int idxStride;
5090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5091 IWineD3DVertexBuffer *vb;
5092 IWineD3DIndexBuffer *ib;
5094 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5095 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5096 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5097 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5099 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5100 idxStride = 2;
5101 } else {
5102 idxStride = 4;
5105 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5106 vb = This->stateBlock->streamSource[0];
5107 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5108 if(vb) IWineD3DVertexBuffer_Release(vb);
5109 This->stateBlock->streamIsUP = TRUE;
5110 This->stateBlock->streamOffset[0] = 0;
5111 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5113 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5114 This->stateBlock->baseVertexIndex = 0;
5115 This->stateBlock->loadBaseVertexIndex = 0;
5116 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5117 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5120 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5122 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5123 This->stateBlock->streamSource[0] = NULL;
5124 This->stateBlock->streamStride[0] = 0;
5125 ib = This->stateBlock->pIndexData;
5126 if(ib) {
5127 IWineD3DIndexBuffer_Release(ib);
5128 This->stateBlock->pIndexData = NULL;
5130 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5131 * SetStreamSource to specify a vertex buffer
5134 return WINED3D_OK;
5137 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5140 /* Mark the state dirty until we have nicer tracking
5141 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5142 * that value.
5144 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5145 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5146 This->stateBlock->baseVertexIndex = 0;
5147 This->up_strided = DrawPrimStrideData;
5148 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5149 This->up_strided = NULL;
5150 return WINED3D_OK;
5153 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5155 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5157 /* Mark the state dirty until we have nicer tracking
5158 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5159 * that value.
5161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5163 This->stateBlock->streamIsUP = TRUE;
5164 This->stateBlock->baseVertexIndex = 0;
5165 This->up_strided = DrawPrimStrideData;
5166 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5167 This->up_strided = NULL;
5168 return WINED3D_OK;
5171 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5172 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5173 * not callable by the app directly no parameter validation checks are needed here.
5175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5176 WINED3DLOCKED_BOX src;
5177 WINED3DLOCKED_BOX dst;
5178 HRESULT hr;
5179 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5181 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5182 * dirtification to improve loading performance.
5184 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5185 if(FAILED(hr)) return hr;
5186 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5187 if(FAILED(hr)) {
5188 IWineD3DVolume_UnlockBox(pSourceVolume);
5189 return hr;
5192 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5194 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5195 if(FAILED(hr)) {
5196 IWineD3DVolume_UnlockBox(pSourceVolume);
5197 } else {
5198 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5200 return hr;
5203 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5204 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5206 HRESULT hr = WINED3D_OK;
5207 WINED3DRESOURCETYPE sourceType;
5208 WINED3DRESOURCETYPE destinationType;
5209 int i ,levels;
5211 /* TODO: think about moving the code into IWineD3DBaseTexture */
5213 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5215 /* verify that the source and destination textures aren't NULL */
5216 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5217 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5218 This, pSourceTexture, pDestinationTexture);
5219 hr = WINED3DERR_INVALIDCALL;
5222 if (pSourceTexture == pDestinationTexture) {
5223 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5224 This, pSourceTexture, pDestinationTexture);
5225 hr = WINED3DERR_INVALIDCALL;
5227 /* Verify that the source and destination textures are the same type */
5228 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5229 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5231 if (sourceType != destinationType) {
5232 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5233 This);
5234 hr = WINED3DERR_INVALIDCALL;
5237 /* check that both textures have the identical numbers of levels */
5238 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5239 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5240 hr = WINED3DERR_INVALIDCALL;
5243 if (WINED3D_OK == hr) {
5245 /* Make sure that the destination texture is loaded */
5246 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5248 /* Update every surface level of the texture */
5249 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5251 switch (sourceType) {
5252 case WINED3DRTYPE_TEXTURE:
5254 IWineD3DSurface *srcSurface;
5255 IWineD3DSurface *destSurface;
5257 for (i = 0 ; i < levels ; ++i) {
5258 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5259 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5260 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5261 IWineD3DSurface_Release(srcSurface);
5262 IWineD3DSurface_Release(destSurface);
5263 if (WINED3D_OK != hr) {
5264 WARN("(%p) : Call to update surface failed\n", This);
5265 return hr;
5269 break;
5270 case WINED3DRTYPE_CUBETEXTURE:
5272 IWineD3DSurface *srcSurface;
5273 IWineD3DSurface *destSurface;
5274 WINED3DCUBEMAP_FACES faceType;
5276 for (i = 0 ; i < levels ; ++i) {
5277 /* Update each cube face */
5278 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5279 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5280 if (WINED3D_OK != hr) {
5281 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5282 } else {
5283 TRACE("Got srcSurface %p\n", srcSurface);
5285 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5286 if (WINED3D_OK != hr) {
5287 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5288 } else {
5289 TRACE("Got desrSurface %p\n", destSurface);
5291 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5292 IWineD3DSurface_Release(srcSurface);
5293 IWineD3DSurface_Release(destSurface);
5294 if (WINED3D_OK != hr) {
5295 WARN("(%p) : Call to update surface failed\n", This);
5296 return hr;
5301 break;
5303 case WINED3DRTYPE_VOLUMETEXTURE:
5305 IWineD3DVolume *srcVolume = NULL;
5306 IWineD3DVolume *destVolume = NULL;
5308 for (i = 0 ; i < levels ; ++i) {
5309 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5310 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5311 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5312 IWineD3DVolume_Release(srcVolume);
5313 IWineD3DVolume_Release(destVolume);
5314 if (WINED3D_OK != hr) {
5315 WARN("(%p) : Call to update volume failed\n", This);
5316 return hr;
5320 break;
5322 default:
5323 FIXME("(%p) : Unsupported source and destination type\n", This);
5324 hr = WINED3DERR_INVALIDCALL;
5328 return hr;
5331 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5332 IWineD3DSwapChain *swapChain;
5333 HRESULT hr;
5334 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5335 if(hr == WINED3D_OK) {
5336 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5337 IWineD3DSwapChain_Release(swapChain);
5339 return hr;
5342 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5344 /* return a sensible default */
5345 *pNumPasses = 1;
5346 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5347 FIXME("(%p) : stub\n", This);
5348 return WINED3D_OK;
5351 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5353 int j;
5354 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5355 if (PaletteNumber >= MAX_PALETTES) {
5356 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5357 return WINED3DERR_INVALIDCALL;
5359 for (j = 0; j < 256; ++j) {
5360 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5361 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5362 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5363 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5365 TRACE("(%p) : returning\n", This);
5366 return WINED3D_OK;
5369 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5371 int j;
5372 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5373 if (PaletteNumber >= MAX_PALETTES) {
5374 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5375 return WINED3DERR_INVALIDCALL;
5377 for (j = 0; j < 256; ++j) {
5378 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5379 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5380 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5381 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5383 TRACE("(%p) : returning\n", This);
5384 return WINED3D_OK;
5387 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5389 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5390 if (PaletteNumber >= MAX_PALETTES) {
5391 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5392 return WINED3DERR_INVALIDCALL;
5394 /*TODO: stateblocks */
5395 This->currentPalette = PaletteNumber;
5396 TRACE("(%p) : returning\n", This);
5397 return WINED3D_OK;
5400 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5402 if (PaletteNumber == NULL) {
5403 WARN("(%p) : returning Invalid Call\n", This);
5404 return WINED3DERR_INVALIDCALL;
5406 /*TODO: stateblocks */
5407 *PaletteNumber = This->currentPalette;
5408 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5409 return WINED3D_OK;
5412 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5414 static BOOL showFixmes = TRUE;
5415 if (showFixmes) {
5416 FIXME("(%p) : stub\n", This);
5417 showFixmes = FALSE;
5420 This->softwareVertexProcessing = bSoftware;
5421 return WINED3D_OK;
5425 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5427 static BOOL showFixmes = TRUE;
5428 if (showFixmes) {
5429 FIXME("(%p) : stub\n", This);
5430 showFixmes = FALSE;
5432 return This->softwareVertexProcessing;
5436 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5438 IWineD3DSwapChain *swapChain;
5439 HRESULT hr;
5441 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5443 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5444 if(hr == WINED3D_OK){
5445 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5446 IWineD3DSwapChain_Release(swapChain);
5447 }else{
5448 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5450 return hr;
5454 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5456 static BOOL showfixmes = TRUE;
5457 if(nSegments != 0.0f) {
5458 if( showfixmes) {
5459 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5460 showfixmes = FALSE;
5463 return WINED3D_OK;
5466 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5468 static BOOL showfixmes = TRUE;
5469 if( showfixmes) {
5470 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5471 showfixmes = FALSE;
5473 return 0.0f;
5476 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5478 /** TODO: remove casts to IWineD3DSurfaceImpl
5479 * NOTE: move code to surface to accomplish this
5480 ****************************************/
5481 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5482 int srcWidth, srcHeight;
5483 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5484 WINED3DFORMAT destFormat, srcFormat;
5485 UINT destSize;
5486 int srcLeft, destLeft, destTop;
5487 WINED3DPOOL srcPool, destPool;
5488 int offset = 0;
5489 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5490 glDescriptor *glDescription = NULL;
5491 GLenum dummy;
5492 int bpp;
5493 CONVERT_TYPES convert = NO_CONVERSION;
5495 WINED3DSURFACE_DESC winedesc;
5497 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5498 memset(&winedesc, 0, sizeof(winedesc));
5499 winedesc.Width = &srcSurfaceWidth;
5500 winedesc.Height = &srcSurfaceHeight;
5501 winedesc.Pool = &srcPool;
5502 winedesc.Format = &srcFormat;
5504 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5506 winedesc.Width = &destSurfaceWidth;
5507 winedesc.Height = &destSurfaceHeight;
5508 winedesc.Pool = &destPool;
5509 winedesc.Format = &destFormat;
5510 winedesc.Size = &destSize;
5512 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5514 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5515 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5516 return WINED3DERR_INVALIDCALL;
5519 /* This call loads the opengl surface directly, instead of copying the surface to the
5520 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5521 * copy in sysmem and use regular surface loading.
5523 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5524 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5525 if(convert != NO_CONVERSION) {
5526 return IWineD3DSurface_BltFast(pDestinationSurface,
5527 pDestPoint ? pDestPoint->x : 0,
5528 pDestPoint ? pDestPoint->y : 0,
5529 pSourceSurface, (RECT *) pSourceRect, 0);
5532 if (destFormat == WINED3DFMT_UNKNOWN) {
5533 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5534 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5536 /* Get the update surface description */
5537 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5540 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5542 ENTER_GL();
5544 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5545 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5546 checkGLcall("glActiveTextureARB");
5549 /* Make sure the surface is loaded and up to date */
5550 IWineD3DSurface_PreLoad(pDestinationSurface);
5552 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5554 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5555 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5556 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5557 srcLeft = pSourceRect ? pSourceRect->left : 0;
5558 destLeft = pDestPoint ? pDestPoint->x : 0;
5559 destTop = pDestPoint ? pDestPoint->y : 0;
5562 /* This function doesn't support compressed textures
5563 the pitch is just bytesPerPixel * width */
5564 if(srcWidth != srcSurfaceWidth || srcLeft ){
5565 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5566 offset += srcLeft * pSrcSurface->bytesPerPixel;
5567 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5569 /* TODO DXT formats */
5571 if(pSourceRect != NULL && pSourceRect->top != 0){
5572 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5574 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5575 ,This
5576 ,glDescription->level
5577 ,destLeft
5578 ,destTop
5579 ,srcWidth
5580 ,srcHeight
5581 ,glDescription->glFormat
5582 ,glDescription->glType
5583 ,IWineD3DSurface_GetData(pSourceSurface)
5586 /* Sanity check */
5587 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5589 /* need to lock the surface to get the data */
5590 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5593 /* TODO: Cube and volume support */
5594 if(rowoffset != 0){
5595 /* not a whole row so we have to do it a line at a time */
5596 int j;
5598 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5599 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5601 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5603 glTexSubImage2D(glDescription->target
5604 ,glDescription->level
5605 ,destLeft
5607 ,srcWidth
5609 ,glDescription->glFormat
5610 ,glDescription->glType
5611 ,data /* could be quicker using */
5613 data += rowoffset;
5616 } else { /* Full width, so just write out the whole texture */
5618 if (WINED3DFMT_DXT1 == destFormat ||
5619 WINED3DFMT_DXT2 == destFormat ||
5620 WINED3DFMT_DXT3 == destFormat ||
5621 WINED3DFMT_DXT4 == destFormat ||
5622 WINED3DFMT_DXT5 == destFormat) {
5623 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5624 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5625 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5626 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5627 } if (destFormat != srcFormat) {
5628 FIXME("Updating mixed format compressed texture is not curretly support\n");
5629 } else {
5630 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5631 glDescription->level,
5632 glDescription->glFormatInternal,
5633 srcWidth,
5634 srcHeight,
5636 destSize,
5637 IWineD3DSurface_GetData(pSourceSurface));
5639 } else {
5640 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5644 } else {
5645 glTexSubImage2D(glDescription->target
5646 ,glDescription->level
5647 ,destLeft
5648 ,destTop
5649 ,srcWidth
5650 ,srcHeight
5651 ,glDescription->glFormat
5652 ,glDescription->glType
5653 ,IWineD3DSurface_GetData(pSourceSurface)
5657 checkGLcall("glTexSubImage2D");
5659 LEAVE_GL();
5661 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5662 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5664 return WINED3D_OK;
5667 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5669 struct WineD3DRectPatch *patch;
5670 unsigned int i;
5671 struct list *e;
5672 BOOL found;
5673 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5675 if(!(Handle || pRectPatchInfo)) {
5676 /* TODO: Write a test for the return value, thus the FIXME */
5677 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5678 return WINED3DERR_INVALIDCALL;
5681 if(Handle) {
5682 i = PATCHMAP_HASHFUNC(Handle);
5683 found = FALSE;
5684 LIST_FOR_EACH(e, &This->patches[i]) {
5685 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5686 if(patch->Handle == Handle) {
5687 found = TRUE;
5688 break;
5692 if(!found) {
5693 TRACE("Patch does not exist. Creating a new one\n");
5694 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5695 patch->Handle = Handle;
5696 list_add_head(&This->patches[i], &patch->entry);
5697 } else {
5698 TRACE("Found existing patch %p\n", patch);
5700 } else {
5701 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5702 * attributes we have to tesselate, read back, and draw. This needs a patch
5703 * management structure instance. Create one.
5705 * A possible improvement is to check if a vertex shader is used, and if not directly
5706 * draw the patch.
5708 FIXME("Drawing an uncached patch. This is slow\n");
5709 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5712 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5713 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5714 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5715 HRESULT hr;
5716 TRACE("Tesselation density or patch info changed, retesselating\n");
5718 if(pRectPatchInfo) {
5719 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5721 patch->numSegs[0] = pNumSegs[0];
5722 patch->numSegs[1] = pNumSegs[1];
5723 patch->numSegs[2] = pNumSegs[2];
5724 patch->numSegs[3] = pNumSegs[3];
5726 hr = tesselate_rectpatch(This, patch);
5727 if(FAILED(hr)) {
5728 WARN("Patch tesselation failed\n");
5730 /* Do not release the handle to store the params of the patch */
5731 if(!Handle) {
5732 HeapFree(GetProcessHeap(), 0, patch);
5734 return hr;
5738 This->currentPatch = patch;
5739 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5740 This->currentPatch = NULL;
5742 /* Destroy uncached patches */
5743 if(!Handle) {
5744 HeapFree(GetProcessHeap(), 0, patch->mem);
5745 HeapFree(GetProcessHeap(), 0, patch);
5747 return WINED3D_OK;
5750 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5751 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5753 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5754 FIXME("(%p) : Stub\n", This);
5755 return WINED3D_OK;
5758 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5760 int i;
5761 struct WineD3DRectPatch *patch;
5762 struct list *e;
5763 TRACE("(%p) Handle(%d)\n", This, Handle);
5765 i = PATCHMAP_HASHFUNC(Handle);
5766 LIST_FOR_EACH(e, &This->patches[i]) {
5767 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5768 if(patch->Handle == Handle) {
5769 TRACE("Deleting patch %p\n", patch);
5770 list_remove(&patch->entry);
5771 HeapFree(GetProcessHeap(), 0, patch->mem);
5772 HeapFree(GetProcessHeap(), 0, patch);
5773 return WINED3D_OK;
5777 /* TODO: Write a test for the return value */
5778 FIXME("Attempt to destroy nonexistent patch\n");
5779 return WINED3DERR_INVALIDCALL;
5782 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5783 HRESULT hr;
5784 IWineD3DSwapChain *swapchain;
5786 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5787 if (SUCCEEDED(hr)) {
5788 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5789 return swapchain;
5792 return NULL;
5795 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5798 if (!*fbo) {
5799 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5800 checkGLcall("glGenFramebuffersEXT()");
5802 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5803 checkGLcall("glBindFramebuffer()");
5806 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5807 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5808 IWineD3DBaseTextureImpl *texture_impl;
5809 GLenum texttarget, target;
5810 GLint old_binding;
5812 texttarget = surface_impl->glDescription.target;
5813 if(texttarget == GL_TEXTURE_2D) {
5814 target = GL_TEXTURE_2D;
5815 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5816 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5817 target = GL_TEXTURE_RECTANGLE_ARB;
5818 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5819 } else {
5820 target = GL_TEXTURE_CUBE_MAP_ARB;
5821 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5824 IWineD3DSurface_PreLoad(surface);
5826 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5827 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5828 glBindTexture(target, old_binding);
5830 /* Update base texture states array */
5831 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5832 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5833 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5834 if (texture_impl->baseTexture.bindCount) {
5835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5838 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5841 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5842 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5844 checkGLcall("attach_surface_fbo");
5847 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5849 IWineD3DSwapChain *swapchain;
5851 swapchain = get_swapchain(surface);
5852 if (swapchain) {
5853 GLenum buffer;
5855 TRACE("Surface %p is onscreen\n", surface);
5857 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5858 buffer = surface_get_gl_buffer(surface, swapchain);
5859 glDrawBuffer(buffer);
5860 checkGLcall("glDrawBuffer()");
5861 } else {
5862 TRACE("Surface %p is offscreen\n", surface);
5863 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5864 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5867 if (rect) {
5868 glEnable(GL_SCISSOR_TEST);
5869 if(!swapchain) {
5870 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5871 } else {
5872 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5873 rect->x2 - rect->x1, rect->y2 - rect->y1);
5875 checkGLcall("glScissor");
5876 } else {
5877 glDisable(GL_SCISSOR_TEST);
5879 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5881 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5884 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5885 glClear(GL_COLOR_BUFFER_BIT);
5886 checkGLcall("glClear");
5888 if (This->render_offscreen) {
5889 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5890 } else {
5891 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5892 checkGLcall("glBindFramebuffer()");
5895 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5896 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5897 glDrawBuffer(GL_BACK);
5898 checkGLcall("glDrawBuffer()");
5902 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5903 unsigned int r, g, b, a;
5904 DWORD ret;
5906 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5907 destfmt == WINED3DFMT_R8G8B8)
5908 return color;
5910 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5912 a = (color & 0xff000000) >> 24;
5913 r = (color & 0x00ff0000) >> 16;
5914 g = (color & 0x0000ff00) >> 8;
5915 b = (color & 0x000000ff) >> 0;
5917 switch(destfmt)
5919 case WINED3DFMT_R5G6B5:
5920 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5921 r = (r * 32) / 256;
5922 g = (g * 64) / 256;
5923 b = (b * 32) / 256;
5924 ret = r << 11;
5925 ret |= g << 5;
5926 ret |= b;
5927 TRACE("Returning %08x\n", ret);
5928 return ret;
5930 case WINED3DFMT_X1R5G5B5:
5931 case WINED3DFMT_A1R5G5B5:
5932 a = (a * 2) / 256;
5933 r = (r * 32) / 256;
5934 g = (g * 32) / 256;
5935 b = (b * 32) / 256;
5936 ret = a << 15;
5937 ret |= r << 10;
5938 ret |= g << 5;
5939 ret |= b << 0;
5940 TRACE("Returning %08x\n", ret);
5941 return ret;
5943 case WINED3DFMT_A8:
5944 TRACE("Returning %08x\n", a);
5945 return a;
5947 case WINED3DFMT_X4R4G4B4:
5948 case WINED3DFMT_A4R4G4B4:
5949 a = (a * 16) / 256;
5950 r = (r * 16) / 256;
5951 g = (g * 16) / 256;
5952 b = (b * 16) / 256;
5953 ret = a << 12;
5954 ret |= r << 8;
5955 ret |= g << 4;
5956 ret |= b << 0;
5957 TRACE("Returning %08x\n", ret);
5958 return ret;
5960 case WINED3DFMT_R3G3B2:
5961 r = (r * 8) / 256;
5962 g = (g * 8) / 256;
5963 b = (b * 4) / 256;
5964 ret = r << 5;
5965 ret |= g << 2;
5966 ret |= b << 0;
5967 TRACE("Returning %08x\n", ret);
5968 return ret;
5970 case WINED3DFMT_X8B8G8R8:
5971 case WINED3DFMT_A8B8G8R8:
5972 ret = a << 24;
5973 ret |= b << 16;
5974 ret |= g << 8;
5975 ret |= r << 0;
5976 TRACE("Returning %08x\n", ret);
5977 return ret;
5979 case WINED3DFMT_A2R10G10B10:
5980 a = (a * 4) / 256;
5981 r = (r * 1024) / 256;
5982 g = (g * 1024) / 256;
5983 b = (b * 1024) / 256;
5984 ret = a << 30;
5985 ret |= r << 20;
5986 ret |= g << 10;
5987 ret |= b << 0;
5988 TRACE("Returning %08x\n", ret);
5989 return ret;
5991 case WINED3DFMT_A2B10G10R10:
5992 a = (a * 4) / 256;
5993 r = (r * 1024) / 256;
5994 g = (g * 1024) / 256;
5995 b = (b * 1024) / 256;
5996 ret = a << 30;
5997 ret |= b << 20;
5998 ret |= g << 10;
5999 ret |= r << 0;
6000 TRACE("Returning %08x\n", ret);
6001 return ret;
6003 default:
6004 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6005 return 0;
6009 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6011 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6012 WINEDDBLTFX BltFx;
6013 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6015 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6016 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6017 return WINED3DERR_INVALIDCALL;
6020 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6021 color_fill_fbo(iface, pSurface, pRect, color);
6022 return WINED3D_OK;
6023 } else {
6024 /* Just forward this to the DirectDraw blitting engine */
6025 memset(&BltFx, 0, sizeof(BltFx));
6026 BltFx.dwSize = sizeof(BltFx);
6027 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6028 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6032 /* rendertarget and depth stencil functions */
6033 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6036 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6037 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6038 return WINED3DERR_INVALIDCALL;
6041 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6042 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6043 /* Note inc ref on returned surface */
6044 if(*ppRenderTarget != NULL)
6045 IWineD3DSurface_AddRef(*ppRenderTarget);
6046 return WINED3D_OK;
6049 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6051 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6052 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6053 IWineD3DSwapChainImpl *Swapchain;
6054 HRESULT hr;
6056 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6058 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6059 if(hr != WINED3D_OK) {
6060 ERR("Can't get the swapchain\n");
6061 return hr;
6064 /* Make sure to release the swapchain */
6065 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6067 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6068 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6069 return WINED3DERR_INVALIDCALL;
6071 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6072 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6073 return WINED3DERR_INVALIDCALL;
6076 if(Swapchain->frontBuffer != Front) {
6077 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6079 if(Swapchain->frontBuffer)
6080 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6081 Swapchain->frontBuffer = Front;
6083 if(Swapchain->frontBuffer) {
6084 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6088 if(Back && !Swapchain->backBuffer) {
6089 /* We need memory for the back buffer array - only one back buffer this way */
6090 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6091 if(!Swapchain->backBuffer) {
6092 ERR("Out of memory\n");
6093 return E_OUTOFMEMORY;
6097 if(Swapchain->backBuffer[0] != Back) {
6098 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6100 /* What to do about the context here in the case of multithreading? Not sure.
6101 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6103 ENTER_GL();
6104 if(!Swapchain->backBuffer[0]) {
6105 /* GL was told to draw to the front buffer at creation,
6106 * undo that
6108 glDrawBuffer(GL_BACK);
6109 checkGLcall("glDrawBuffer(GL_BACK)");
6110 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6111 Swapchain->presentParms.BackBufferCount = 1;
6112 } else if (!Back) {
6113 /* That makes problems - disable for now */
6114 /* glDrawBuffer(GL_FRONT); */
6115 checkGLcall("glDrawBuffer(GL_FRONT)");
6116 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6117 Swapchain->presentParms.BackBufferCount = 0;
6119 LEAVE_GL();
6121 if(Swapchain->backBuffer[0])
6122 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6123 Swapchain->backBuffer[0] = Back;
6125 if(Swapchain->backBuffer[0]) {
6126 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6127 } else {
6128 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6129 Swapchain->backBuffer = NULL;
6134 return WINED3D_OK;
6137 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6139 *ppZStencilSurface = This->stencilBufferTarget;
6140 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6142 if(*ppZStencilSurface != NULL) {
6143 /* Note inc ref on returned surface */
6144 IWineD3DSurface_AddRef(*ppZStencilSurface);
6145 return WINED3D_OK;
6146 } else {
6147 return WINED3DERR_NOTFOUND;
6151 /* TODO: Handle stencil attachments */
6152 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6154 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6156 TRACE("Set depth stencil to %p\n", depth_stencil);
6158 if (depth_stencil_impl) {
6159 if (depth_stencil_impl->current_renderbuffer) {
6160 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6161 checkGLcall("glFramebufferRenderbufferEXT()");
6162 } else {
6163 IWineD3DBaseTextureImpl *texture_impl;
6164 GLenum texttarget, target;
6165 GLint old_binding = 0;
6167 texttarget = depth_stencil_impl->glDescription.target;
6168 if(texttarget == GL_TEXTURE_2D) {
6169 target = GL_TEXTURE_2D;
6170 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6171 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6172 target = GL_TEXTURE_RECTANGLE_ARB;
6173 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6174 } else {
6175 target = GL_TEXTURE_CUBE_MAP_ARB;
6176 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6179 IWineD3DSurface_PreLoad(depth_stencil);
6181 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6182 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6183 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6184 glBindTexture(target, old_binding);
6186 /* Update base texture states array */
6187 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6188 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6189 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6190 if (texture_impl->baseTexture.bindCount) {
6191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6194 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6197 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6198 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6199 checkGLcall("glFramebufferTexture2DEXT()");
6201 } else {
6202 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6203 checkGLcall("glFramebufferTexture2DEXT()");
6207 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6208 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6209 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6211 TRACE("Set render target %u to %p\n", idx, render_target);
6213 if (rtimpl) {
6214 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6215 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6216 } else {
6217 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6218 checkGLcall("glFramebufferTexture2DEXT()");
6220 This->draw_buffers[idx] = GL_NONE;
6224 static void check_fbo_status(IWineD3DDevice *iface) {
6225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6226 GLenum status;
6228 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6229 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6230 TRACE("FBO complete\n");
6231 } else {
6232 IWineD3DSurfaceImpl *attachment;
6233 int i;
6234 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6236 /* Dump the FBO attachments */
6237 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6238 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6239 if (attachment) {
6240 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6241 attachment->pow2Width, attachment->pow2Height);
6244 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6245 if (attachment) {
6246 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6247 attachment->pow2Width, attachment->pow2Height);
6252 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6254 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6255 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6257 if (!ds_impl) return FALSE;
6259 if (ds_impl->current_renderbuffer) {
6260 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6261 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6264 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6265 rt_impl->pow2Height != ds_impl->pow2Height);
6268 void apply_fbo_state(IWineD3DDevice *iface) {
6269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6270 unsigned int i;
6272 if (This->render_offscreen) {
6273 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6275 /* Apply render targets */
6276 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6277 IWineD3DSurface *render_target = This->render_targets[i];
6278 if (This->fbo_color_attachments[i] != render_target) {
6279 set_render_target_fbo(iface, i, render_target);
6280 This->fbo_color_attachments[i] = render_target;
6284 /* Apply depth targets */
6285 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6286 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6287 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6289 if (This->stencilBufferTarget) {
6290 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6292 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6293 This->fbo_depth_attachment = This->stencilBufferTarget;
6296 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6297 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6298 checkGLcall("glDrawBuffers()");
6299 } else {
6300 glDrawBuffer(This->draw_buffers[0]);
6301 checkGLcall("glDrawBuffer()");
6303 } else {
6304 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6307 check_fbo_status(iface);
6310 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6311 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6312 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6313 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6314 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6315 GLenum gl_filter;
6317 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6318 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6319 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6320 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6322 switch (filter) {
6323 case WINED3DTEXF_LINEAR:
6324 gl_filter = GL_LINEAR;
6325 break;
6327 default:
6328 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6329 case WINED3DTEXF_NONE:
6330 case WINED3DTEXF_POINT:
6331 gl_filter = GL_NEAREST;
6332 break;
6335 /* Attach src surface to src fbo */
6336 src_swapchain = get_swapchain(src_surface);
6337 if (src_swapchain) {
6338 GLenum buffer;
6340 TRACE("Source surface %p is onscreen\n", src_surface);
6341 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6342 /* Make sure the drawable is up to date. In the offscreen case
6343 * attach_surface_fbo() implicitly takes care of this. */
6344 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6346 ENTER_GL();
6347 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6348 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6349 glReadBuffer(buffer);
6350 checkGLcall("glReadBuffer()");
6352 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6353 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6354 } else {
6355 TRACE("Source surface %p is offscreen\n", src_surface);
6356 ENTER_GL();
6357 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6358 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6359 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6360 checkGLcall("glReadBuffer()");
6362 LEAVE_GL();
6364 /* Attach dst surface to dst fbo */
6365 dst_swapchain = get_swapchain(dst_surface);
6366 if (dst_swapchain) {
6367 GLenum buffer;
6369 TRACE("Destination surface %p is onscreen\n", dst_surface);
6370 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6371 /* Make sure the drawable is up to date. In the offscreen case
6372 * attach_surface_fbo() implicitly takes care of this. */
6373 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6375 ENTER_GL();
6376 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6377 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6378 glDrawBuffer(buffer);
6379 checkGLcall("glDrawBuffer()");
6381 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6382 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6383 } else {
6384 TRACE("Destination surface %p is offscreen\n", dst_surface);
6386 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6387 if(!src_swapchain) {
6388 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6391 ENTER_GL();
6392 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6393 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6394 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6395 checkGLcall("glDrawBuffer()");
6397 glDisable(GL_SCISSOR_TEST);
6398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6400 if (flip) {
6401 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6402 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6403 checkGLcall("glBlitFramebuffer()");
6404 } else {
6405 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6406 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6407 checkGLcall("glBlitFramebuffer()");
6410 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6412 if (This->render_offscreen) {
6413 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6414 } else {
6415 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6416 checkGLcall("glBindFramebuffer()");
6419 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6420 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6421 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6422 glDrawBuffer(GL_BACK);
6423 checkGLcall("glDrawBuffer()");
6425 LEAVE_GL();
6428 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6430 WINED3DVIEWPORT viewport;
6432 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6434 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6435 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6436 This, RenderTargetIndex, GL_LIMITS(buffers));
6437 return WINED3DERR_INVALIDCALL;
6440 /* MSDN says that null disables the render target
6441 but a device must always be associated with a render target
6442 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6444 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6445 for more details
6447 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6448 FIXME("Trying to set render target 0 to NULL\n");
6449 return WINED3DERR_INVALIDCALL;
6451 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6452 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);
6453 return WINED3DERR_INVALIDCALL;
6456 /* If we are trying to set what we already have, don't bother */
6457 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6458 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6459 return WINED3D_OK;
6461 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6462 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6463 This->render_targets[RenderTargetIndex] = pRenderTarget;
6465 /* Render target 0 is special */
6466 if(RenderTargetIndex == 0) {
6467 /* Finally, reset the viewport as the MSDN states. */
6468 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6469 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6470 viewport.X = 0;
6471 viewport.Y = 0;
6472 viewport.MaxZ = 1.0f;
6473 viewport.MinZ = 0.0f;
6474 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6475 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6476 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6478 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6480 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6481 * ctx properly.
6482 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6483 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6485 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6487 return WINED3D_OK;
6490 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6491 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6492 HRESULT hr = WINED3D_OK;
6493 IWineD3DSurface *tmp;
6495 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6497 if (pNewZStencil == This->stencilBufferTarget) {
6498 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6499 } else {
6500 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6501 * depending on the renter target implementation being used.
6502 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6503 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6504 * stencil buffer and incur an extra memory overhead
6505 ******************************************************/
6507 tmp = This->stencilBufferTarget;
6508 This->stencilBufferTarget = pNewZStencil;
6509 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6510 /* should we be calling the parent or the wined3d surface? */
6511 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6512 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6513 hr = WINED3D_OK;
6515 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6516 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6518 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6519 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6523 return hr;
6526 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6527 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6529 /* TODO: the use of Impl is deprecated. */
6530 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6531 WINED3DLOCKED_RECT lockedRect;
6533 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6535 /* some basic validation checks */
6536 if(This->cursorTexture) {
6537 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6538 ENTER_GL();
6539 glDeleteTextures(1, &This->cursorTexture);
6540 LEAVE_GL();
6541 This->cursorTexture = 0;
6544 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6545 This->haveHardwareCursor = TRUE;
6546 else
6547 This->haveHardwareCursor = FALSE;
6549 if(pCursorBitmap) {
6550 WINED3DLOCKED_RECT rect;
6552 /* MSDN: Cursor must be A8R8G8B8 */
6553 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6554 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6555 return WINED3DERR_INVALIDCALL;
6558 /* MSDN: Cursor must be smaller than the display mode */
6559 if(pSur->currentDesc.Width > This->ddraw_width ||
6560 pSur->currentDesc.Height > This->ddraw_height) {
6561 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);
6562 return WINED3DERR_INVALIDCALL;
6565 if (!This->haveHardwareCursor) {
6566 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6568 /* Do not store the surface's pointer because the application may
6569 * release it after setting the cursor image. Windows doesn't
6570 * addref the set surface, so we can't do this either without
6571 * creating circular refcount dependencies. Copy out the gl texture
6572 * instead.
6574 This->cursorWidth = pSur->currentDesc.Width;
6575 This->cursorHeight = pSur->currentDesc.Height;
6576 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6578 const GlPixelFormatDesc *glDesc;
6579 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6580 char *mem, *bits = (char *)rect.pBits;
6581 GLint intfmt = glDesc->glInternal;
6582 GLint format = glDesc->glFormat;
6583 GLint type = glDesc->glType;
6584 INT height = This->cursorHeight;
6585 INT width = This->cursorWidth;
6586 INT bpp = tableEntry->bpp;
6587 INT i;
6589 /* Reformat the texture memory (pitch and width can be
6590 * different) */
6591 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6592 for(i = 0; i < height; i++)
6593 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6594 IWineD3DSurface_UnlockRect(pCursorBitmap);
6595 ENTER_GL();
6597 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6598 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6599 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6602 /* Make sure that a proper texture unit is selected */
6603 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6604 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6605 checkGLcall("glActiveTextureARB");
6607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6608 /* Create a new cursor texture */
6609 glGenTextures(1, &This->cursorTexture);
6610 checkGLcall("glGenTextures");
6611 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6612 checkGLcall("glBindTexture");
6613 /* Copy the bitmap memory into the cursor texture */
6614 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6615 HeapFree(GetProcessHeap(), 0, mem);
6616 checkGLcall("glTexImage2D");
6618 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6619 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6620 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6623 LEAVE_GL();
6625 else
6627 FIXME("A cursor texture was not returned.\n");
6628 This->cursorTexture = 0;
6631 else
6633 /* Draw a hardware cursor */
6634 ICONINFO cursorInfo;
6635 HCURSOR cursor;
6636 /* Create and clear maskBits because it is not needed for
6637 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6638 * chunks. */
6639 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6640 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6641 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6642 WINED3DLOCK_NO_DIRTY_UPDATE |
6643 WINED3DLOCK_READONLY
6645 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6646 pSur->currentDesc.Height);
6648 cursorInfo.fIcon = FALSE;
6649 cursorInfo.xHotspot = XHotSpot;
6650 cursorInfo.yHotspot = YHotSpot;
6651 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6652 pSur->currentDesc.Height, 1,
6653 1, &maskBits);
6654 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6655 pSur->currentDesc.Height, 1,
6656 32, lockedRect.pBits);
6657 IWineD3DSurface_UnlockRect(pCursorBitmap);
6658 /* Create our cursor and clean up. */
6659 cursor = CreateIconIndirect(&cursorInfo);
6660 SetCursor(cursor);
6661 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6662 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6663 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6664 This->hardwareCursor = cursor;
6665 HeapFree(GetProcessHeap(), 0, maskBits);
6669 This->xHotSpot = XHotSpot;
6670 This->yHotSpot = YHotSpot;
6671 return WINED3D_OK;
6674 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6675 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6676 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6678 This->xScreenSpace = XScreenSpace;
6679 This->yScreenSpace = YScreenSpace;
6681 return;
6685 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6687 BOOL oldVisible = This->bCursorVisible;
6688 POINT pt;
6690 TRACE("(%p) : visible(%d)\n", This, bShow);
6693 * When ShowCursor is first called it should make the cursor appear at the OS's last
6694 * known cursor position. Because of this, some applications just repetitively call
6695 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6697 GetCursorPos(&pt);
6698 This->xScreenSpace = pt.x;
6699 This->yScreenSpace = pt.y;
6701 if (This->haveHardwareCursor) {
6702 This->bCursorVisible = bShow;
6703 if (bShow)
6704 SetCursor(This->hardwareCursor);
6705 else
6706 SetCursor(NULL);
6708 else
6710 if (This->cursorTexture)
6711 This->bCursorVisible = bShow;
6714 return oldVisible;
6717 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6719 IWineD3DResourceImpl *resource;
6720 TRACE("(%p) : state (%u)\n", This, This->state);
6722 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6723 switch (This->state) {
6724 case WINED3D_OK:
6725 return WINED3D_OK;
6726 case WINED3DERR_DEVICELOST:
6728 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6729 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6730 return WINED3DERR_DEVICENOTRESET;
6732 return WINED3DERR_DEVICELOST;
6734 case WINED3DERR_DRIVERINTERNALERROR:
6735 return WINED3DERR_DRIVERINTERNALERROR;
6738 /* Unknown state */
6739 return WINED3DERR_DRIVERINTERNALERROR;
6743 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6745 /** FIXME: Resource tracking needs to be done,
6746 * The closes we can do to this is set the priorities of all managed textures low
6747 * and then reset them.
6748 ***********************************************************/
6749 FIXME("(%p) : stub\n", This);
6750 return WINED3D_OK;
6753 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6754 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6756 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6757 if(surface->Flags & SFLAG_DIBSECTION) {
6758 /* Release the DC */
6759 SelectObject(surface->hDC, surface->dib.holdbitmap);
6760 DeleteDC(surface->hDC);
6761 /* Release the DIB section */
6762 DeleteObject(surface->dib.DIBsection);
6763 surface->dib.bitmap_data = NULL;
6764 surface->resource.allocatedMemory = NULL;
6765 surface->Flags &= ~SFLAG_DIBSECTION;
6767 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6768 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6769 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6770 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6771 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6772 } else {
6773 surface->pow2Width = surface->pow2Height = 1;
6774 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6775 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6777 if(surface->glDescription.textureName) {
6778 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6779 ENTER_GL();
6780 glDeleteTextures(1, &surface->glDescription.textureName);
6781 LEAVE_GL();
6782 surface->glDescription.textureName = 0;
6783 surface->Flags &= ~SFLAG_CLIENT;
6785 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6786 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6787 surface->Flags |= SFLAG_NONPOW2;
6788 } else {
6789 surface->Flags &= ~SFLAG_NONPOW2;
6791 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6792 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6795 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6796 TRACE("Unloading resource %p\n", resource);
6797 IWineD3DResource_UnLoad(resource);
6798 IWineD3DResource_Release(resource);
6799 return S_OK;
6802 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6804 IWineD3DSwapChainImpl *swapchain;
6805 HRESULT hr;
6806 BOOL DisplayModeChanged = FALSE;
6807 WINED3DDISPLAYMODE mode;
6808 IWineD3DBaseShaderImpl *shader;
6809 TRACE("(%p)\n", This);
6811 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6812 if(FAILED(hr)) {
6813 ERR("Failed to get the first implicit swapchain\n");
6814 return hr;
6817 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6818 * on an existing gl context, so there's no real need for recreation.
6820 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6822 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6824 TRACE("New params:\n");
6825 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6826 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6827 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6828 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6829 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6830 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6831 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6832 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6833 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6834 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6835 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6836 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6837 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6839 /* No special treatment of these parameters. Just store them */
6840 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6841 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6842 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6843 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6845 /* What to do about these? */
6846 if(pPresentationParameters->BackBufferCount != 0 &&
6847 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6848 ERR("Cannot change the back buffer count yet\n");
6850 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6851 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6852 ERR("Cannot change the back buffer format yet\n");
6854 if(pPresentationParameters->hDeviceWindow != NULL &&
6855 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6856 ERR("Cannot change the device window yet\n");
6858 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6859 ERR("What do do about a changed auto depth stencil parameter?\n");
6862 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6863 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6864 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6867 if(pPresentationParameters->Windowed) {
6868 mode.Width = swapchain->orig_width;
6869 mode.Height = swapchain->orig_height;
6870 mode.RefreshRate = 0;
6871 mode.Format = swapchain->presentParms.BackBufferFormat;
6872 } else {
6873 mode.Width = pPresentationParameters->BackBufferWidth;
6874 mode.Height = pPresentationParameters->BackBufferHeight;
6875 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6876 mode.Format = swapchain->presentParms.BackBufferFormat;
6878 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6879 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6880 pPresentationParameters->BackBufferWidth,
6881 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6884 /* Should Width == 800 && Height == 0 set 800x600? */
6885 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6886 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6887 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6889 WINED3DVIEWPORT vp;
6890 int i;
6892 vp.X = 0;
6893 vp.Y = 0;
6894 vp.Width = pPresentationParameters->BackBufferWidth;
6895 vp.Height = pPresentationParameters->BackBufferHeight;
6896 vp.MinZ = 0;
6897 vp.MaxZ = 1;
6899 if(!pPresentationParameters->Windowed) {
6900 DisplayModeChanged = TRUE;
6902 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6903 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6905 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6906 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6907 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6910 /* Now set the new viewport */
6911 IWineD3DDevice_SetViewport(iface, &vp);
6914 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6915 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6916 DisplayModeChanged) {
6918 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6919 if(!pPresentationParameters->Windowed) {
6920 IWineD3DDevice_SetFullscreen(iface, TRUE);
6923 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6925 /* Switching out of fullscreen mode? First set the original res, then change the window */
6926 if(pPresentationParameters->Windowed) {
6927 IWineD3DDevice_SetFullscreen(iface, FALSE);
6929 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6932 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6933 return WINED3D_OK;
6936 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6938 /** FIXME: always true at the moment **/
6939 if(!bEnableDialogs) {
6940 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6942 return WINED3D_OK;
6946 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6948 TRACE("(%p) : pParameters %p\n", This, pParameters);
6950 *pParameters = This->createParms;
6951 return WINED3D_OK;
6954 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6955 IWineD3DSwapChain *swapchain;
6956 HRESULT hrc = WINED3D_OK;
6958 TRACE("Relaying to swapchain\n");
6960 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6961 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6962 IWineD3DSwapChain_Release(swapchain);
6964 return;
6967 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6968 IWineD3DSwapChain *swapchain;
6969 HRESULT hrc = WINED3D_OK;
6971 TRACE("Relaying to swapchain\n");
6973 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6974 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6975 IWineD3DSwapChain_Release(swapchain);
6977 return;
6981 /** ********************************************************
6982 * Notification functions
6983 ** ********************************************************/
6984 /** This function must be called in the release of a resource when ref == 0,
6985 * the contents of resource must still be correct,
6986 * any handles to other resource held by the caller must be closed
6987 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6988 *****************************************************/
6989 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6992 TRACE("(%p) : Adding Resource %p\n", This, resource);
6993 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
6996 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6999 TRACE("(%p) : Removing resource %p\n", This, resource);
7001 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7005 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7006 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7007 int counter;
7009 TRACE("(%p) : resource %p\n", This, resource);
7010 switch(IWineD3DResource_GetType(resource)){
7011 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7012 case WINED3DRTYPE_SURFACE: {
7013 unsigned int i;
7015 /* Cleanup any FBO attachments if d3d is enabled */
7016 if(This->d3d_initialized) {
7017 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7018 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7020 TRACE("Last active render target destroyed\n");
7021 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7022 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7023 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7024 * and the lastActiveRenderTarget member shouldn't matter
7026 if(swapchain) {
7027 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7028 TRACE("Activating primary back buffer\n");
7029 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7030 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7031 /* Single buffering environment */
7032 TRACE("Activating primary front buffer\n");
7033 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7034 } else {
7035 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7036 /* Implicit render target destroyed, that means the device is being destroyed
7037 * whatever we set here, it shouldn't matter
7039 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7041 } else {
7042 /* May happen during ddraw uninitialization */
7043 TRACE("Render target set, but swapchain does not exist!\n");
7044 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7048 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7049 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7050 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7051 set_render_target_fbo(iface, i, NULL);
7052 This->fbo_color_attachments[i] = NULL;
7055 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7056 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7057 set_depth_stencil_fbo(iface, NULL);
7058 This->fbo_depth_attachment = NULL;
7062 break;
7064 case WINED3DRTYPE_TEXTURE:
7065 case WINED3DRTYPE_CUBETEXTURE:
7066 case WINED3DRTYPE_VOLUMETEXTURE:
7067 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7068 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7069 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7070 This->stateBlock->textures[counter] = NULL;
7072 if (This->updateStateBlock != This->stateBlock ){
7073 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7074 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7075 This->updateStateBlock->textures[counter] = NULL;
7079 break;
7080 case WINED3DRTYPE_VOLUME:
7081 /* TODO: nothing really? */
7082 break;
7083 case WINED3DRTYPE_VERTEXBUFFER:
7084 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7086 int streamNumber;
7087 TRACE("Cleaning up stream pointers\n");
7089 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7090 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7091 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7093 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7094 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7095 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7096 This->updateStateBlock->streamSource[streamNumber] = 0;
7097 /* Set changed flag? */
7100 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) */
7101 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7102 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7103 This->stateBlock->streamSource[streamNumber] = 0;
7106 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7107 else { /* This shouldn't happen */
7108 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7110 #endif
7114 break;
7115 case WINED3DRTYPE_INDEXBUFFER:
7116 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7117 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7118 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7119 This->updateStateBlock->pIndexData = NULL;
7122 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7123 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7124 This->stateBlock->pIndexData = NULL;
7128 break;
7129 default:
7130 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7131 break;
7135 /* Remove the resource from the resourceStore */
7136 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7138 TRACE("Resource released\n");
7142 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7144 IWineD3DResourceImpl *resource, *cursor;
7145 HRESULT ret;
7146 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7148 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7149 TRACE("enumerating resource %p\n", resource);
7150 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7151 ret = pCallback((IWineD3DResource *) resource, pData);
7152 if(ret == S_FALSE) {
7153 TRACE("Canceling enumeration\n");
7154 break;
7157 return WINED3D_OK;
7160 /**********************************************************
7161 * IWineD3DDevice VTbl follows
7162 **********************************************************/
7164 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7166 /*** IUnknown methods ***/
7167 IWineD3DDeviceImpl_QueryInterface,
7168 IWineD3DDeviceImpl_AddRef,
7169 IWineD3DDeviceImpl_Release,
7170 /*** IWineD3DDevice methods ***/
7171 IWineD3DDeviceImpl_GetParent,
7172 /*** Creation methods**/
7173 IWineD3DDeviceImpl_CreateVertexBuffer,
7174 IWineD3DDeviceImpl_CreateIndexBuffer,
7175 IWineD3DDeviceImpl_CreateStateBlock,
7176 IWineD3DDeviceImpl_CreateSurface,
7177 IWineD3DDeviceImpl_CreateTexture,
7178 IWineD3DDeviceImpl_CreateVolumeTexture,
7179 IWineD3DDeviceImpl_CreateVolume,
7180 IWineD3DDeviceImpl_CreateCubeTexture,
7181 IWineD3DDeviceImpl_CreateQuery,
7182 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7183 IWineD3DDeviceImpl_CreateVertexDeclaration,
7184 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7185 IWineD3DDeviceImpl_CreateVertexShader,
7186 IWineD3DDeviceImpl_CreatePixelShader,
7187 IWineD3DDeviceImpl_CreatePalette,
7188 /*** Odd functions **/
7189 IWineD3DDeviceImpl_Init3D,
7190 IWineD3DDeviceImpl_Uninit3D,
7191 IWineD3DDeviceImpl_SetFullscreen,
7192 IWineD3DDeviceImpl_SetMultithreaded,
7193 IWineD3DDeviceImpl_EvictManagedResources,
7194 IWineD3DDeviceImpl_GetAvailableTextureMem,
7195 IWineD3DDeviceImpl_GetBackBuffer,
7196 IWineD3DDeviceImpl_GetCreationParameters,
7197 IWineD3DDeviceImpl_GetDeviceCaps,
7198 IWineD3DDeviceImpl_GetDirect3D,
7199 IWineD3DDeviceImpl_GetDisplayMode,
7200 IWineD3DDeviceImpl_SetDisplayMode,
7201 IWineD3DDeviceImpl_GetHWND,
7202 IWineD3DDeviceImpl_SetHWND,
7203 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7204 IWineD3DDeviceImpl_GetRasterStatus,
7205 IWineD3DDeviceImpl_GetSwapChain,
7206 IWineD3DDeviceImpl_Reset,
7207 IWineD3DDeviceImpl_SetDialogBoxMode,
7208 IWineD3DDeviceImpl_SetCursorProperties,
7209 IWineD3DDeviceImpl_SetCursorPosition,
7210 IWineD3DDeviceImpl_ShowCursor,
7211 IWineD3DDeviceImpl_TestCooperativeLevel,
7212 /*** Getters and setters **/
7213 IWineD3DDeviceImpl_SetClipPlane,
7214 IWineD3DDeviceImpl_GetClipPlane,
7215 IWineD3DDeviceImpl_SetClipStatus,
7216 IWineD3DDeviceImpl_GetClipStatus,
7217 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7218 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7219 IWineD3DDeviceImpl_SetDepthStencilSurface,
7220 IWineD3DDeviceImpl_GetDepthStencilSurface,
7221 IWineD3DDeviceImpl_SetFVF,
7222 IWineD3DDeviceImpl_GetFVF,
7223 IWineD3DDeviceImpl_SetGammaRamp,
7224 IWineD3DDeviceImpl_GetGammaRamp,
7225 IWineD3DDeviceImpl_SetIndices,
7226 IWineD3DDeviceImpl_GetIndices,
7227 IWineD3DDeviceImpl_SetBaseVertexIndex,
7228 IWineD3DDeviceImpl_GetBaseVertexIndex,
7229 IWineD3DDeviceImpl_SetLight,
7230 IWineD3DDeviceImpl_GetLight,
7231 IWineD3DDeviceImpl_SetLightEnable,
7232 IWineD3DDeviceImpl_GetLightEnable,
7233 IWineD3DDeviceImpl_SetMaterial,
7234 IWineD3DDeviceImpl_GetMaterial,
7235 IWineD3DDeviceImpl_SetNPatchMode,
7236 IWineD3DDeviceImpl_GetNPatchMode,
7237 IWineD3DDeviceImpl_SetPaletteEntries,
7238 IWineD3DDeviceImpl_GetPaletteEntries,
7239 IWineD3DDeviceImpl_SetPixelShader,
7240 IWineD3DDeviceImpl_GetPixelShader,
7241 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7242 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7243 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7244 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7245 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7246 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7247 IWineD3DDeviceImpl_SetRenderState,
7248 IWineD3DDeviceImpl_GetRenderState,
7249 IWineD3DDeviceImpl_SetRenderTarget,
7250 IWineD3DDeviceImpl_GetRenderTarget,
7251 IWineD3DDeviceImpl_SetFrontBackBuffers,
7252 IWineD3DDeviceImpl_SetSamplerState,
7253 IWineD3DDeviceImpl_GetSamplerState,
7254 IWineD3DDeviceImpl_SetScissorRect,
7255 IWineD3DDeviceImpl_GetScissorRect,
7256 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7257 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7258 IWineD3DDeviceImpl_SetStreamSource,
7259 IWineD3DDeviceImpl_GetStreamSource,
7260 IWineD3DDeviceImpl_SetStreamSourceFreq,
7261 IWineD3DDeviceImpl_GetStreamSourceFreq,
7262 IWineD3DDeviceImpl_SetTexture,
7263 IWineD3DDeviceImpl_GetTexture,
7264 IWineD3DDeviceImpl_SetTextureStageState,
7265 IWineD3DDeviceImpl_GetTextureStageState,
7266 IWineD3DDeviceImpl_SetTransform,
7267 IWineD3DDeviceImpl_GetTransform,
7268 IWineD3DDeviceImpl_SetVertexDeclaration,
7269 IWineD3DDeviceImpl_GetVertexDeclaration,
7270 IWineD3DDeviceImpl_SetVertexShader,
7271 IWineD3DDeviceImpl_GetVertexShader,
7272 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7273 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7274 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7275 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7276 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7277 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7278 IWineD3DDeviceImpl_SetViewport,
7279 IWineD3DDeviceImpl_GetViewport,
7280 IWineD3DDeviceImpl_MultiplyTransform,
7281 IWineD3DDeviceImpl_ValidateDevice,
7282 IWineD3DDeviceImpl_ProcessVertices,
7283 /*** State block ***/
7284 IWineD3DDeviceImpl_BeginStateBlock,
7285 IWineD3DDeviceImpl_EndStateBlock,
7286 /*** Scene management ***/
7287 IWineD3DDeviceImpl_BeginScene,
7288 IWineD3DDeviceImpl_EndScene,
7289 IWineD3DDeviceImpl_Present,
7290 IWineD3DDeviceImpl_Clear,
7291 /*** Drawing ***/
7292 IWineD3DDeviceImpl_DrawPrimitive,
7293 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7294 IWineD3DDeviceImpl_DrawPrimitiveUP,
7295 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7296 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7297 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7298 IWineD3DDeviceImpl_DrawRectPatch,
7299 IWineD3DDeviceImpl_DrawTriPatch,
7300 IWineD3DDeviceImpl_DeletePatch,
7301 IWineD3DDeviceImpl_ColorFill,
7302 IWineD3DDeviceImpl_UpdateTexture,
7303 IWineD3DDeviceImpl_UpdateSurface,
7304 IWineD3DDeviceImpl_GetFrontBufferData,
7305 /*** object tracking ***/
7306 IWineD3DDeviceImpl_ResourceReleased,
7307 IWineD3DDeviceImpl_EnumResources
7311 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7312 WINED3DRS_ALPHABLENDENABLE ,
7313 WINED3DRS_ALPHAFUNC ,
7314 WINED3DRS_ALPHAREF ,
7315 WINED3DRS_ALPHATESTENABLE ,
7316 WINED3DRS_BLENDOP ,
7317 WINED3DRS_COLORWRITEENABLE ,
7318 WINED3DRS_DESTBLEND ,
7319 WINED3DRS_DITHERENABLE ,
7320 WINED3DRS_FILLMODE ,
7321 WINED3DRS_FOGDENSITY ,
7322 WINED3DRS_FOGEND ,
7323 WINED3DRS_FOGSTART ,
7324 WINED3DRS_LASTPIXEL ,
7325 WINED3DRS_SHADEMODE ,
7326 WINED3DRS_SRCBLEND ,
7327 WINED3DRS_STENCILENABLE ,
7328 WINED3DRS_STENCILFAIL ,
7329 WINED3DRS_STENCILFUNC ,
7330 WINED3DRS_STENCILMASK ,
7331 WINED3DRS_STENCILPASS ,
7332 WINED3DRS_STENCILREF ,
7333 WINED3DRS_STENCILWRITEMASK ,
7334 WINED3DRS_STENCILZFAIL ,
7335 WINED3DRS_TEXTUREFACTOR ,
7336 WINED3DRS_WRAP0 ,
7337 WINED3DRS_WRAP1 ,
7338 WINED3DRS_WRAP2 ,
7339 WINED3DRS_WRAP3 ,
7340 WINED3DRS_WRAP4 ,
7341 WINED3DRS_WRAP5 ,
7342 WINED3DRS_WRAP6 ,
7343 WINED3DRS_WRAP7 ,
7344 WINED3DRS_ZENABLE ,
7345 WINED3DRS_ZFUNC ,
7346 WINED3DRS_ZWRITEENABLE
7349 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7350 WINED3DTSS_ADDRESSW ,
7351 WINED3DTSS_ALPHAARG0 ,
7352 WINED3DTSS_ALPHAARG1 ,
7353 WINED3DTSS_ALPHAARG2 ,
7354 WINED3DTSS_ALPHAOP ,
7355 WINED3DTSS_BUMPENVLOFFSET ,
7356 WINED3DTSS_BUMPENVLSCALE ,
7357 WINED3DTSS_BUMPENVMAT00 ,
7358 WINED3DTSS_BUMPENVMAT01 ,
7359 WINED3DTSS_BUMPENVMAT10 ,
7360 WINED3DTSS_BUMPENVMAT11 ,
7361 WINED3DTSS_COLORARG0 ,
7362 WINED3DTSS_COLORARG1 ,
7363 WINED3DTSS_COLORARG2 ,
7364 WINED3DTSS_COLOROP ,
7365 WINED3DTSS_RESULTARG ,
7366 WINED3DTSS_TEXCOORDINDEX ,
7367 WINED3DTSS_TEXTURETRANSFORMFLAGS
7370 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7371 WINED3DSAMP_ADDRESSU ,
7372 WINED3DSAMP_ADDRESSV ,
7373 WINED3DSAMP_ADDRESSW ,
7374 WINED3DSAMP_BORDERCOLOR ,
7375 WINED3DSAMP_MAGFILTER ,
7376 WINED3DSAMP_MINFILTER ,
7377 WINED3DSAMP_MIPFILTER ,
7378 WINED3DSAMP_MIPMAPLODBIAS ,
7379 WINED3DSAMP_MAXMIPLEVEL ,
7380 WINED3DSAMP_MAXANISOTROPY ,
7381 WINED3DSAMP_SRGBTEXTURE ,
7382 WINED3DSAMP_ELEMENTINDEX
7385 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7386 WINED3DRS_AMBIENT ,
7387 WINED3DRS_AMBIENTMATERIALSOURCE ,
7388 WINED3DRS_CLIPPING ,
7389 WINED3DRS_CLIPPLANEENABLE ,
7390 WINED3DRS_COLORVERTEX ,
7391 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7392 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7393 WINED3DRS_FOGDENSITY ,
7394 WINED3DRS_FOGEND ,
7395 WINED3DRS_FOGSTART ,
7396 WINED3DRS_FOGTABLEMODE ,
7397 WINED3DRS_FOGVERTEXMODE ,
7398 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7399 WINED3DRS_LIGHTING ,
7400 WINED3DRS_LOCALVIEWER ,
7401 WINED3DRS_MULTISAMPLEANTIALIAS ,
7402 WINED3DRS_MULTISAMPLEMASK ,
7403 WINED3DRS_NORMALIZENORMALS ,
7404 WINED3DRS_PATCHEDGESTYLE ,
7405 WINED3DRS_POINTSCALE_A ,
7406 WINED3DRS_POINTSCALE_B ,
7407 WINED3DRS_POINTSCALE_C ,
7408 WINED3DRS_POINTSCALEENABLE ,
7409 WINED3DRS_POINTSIZE ,
7410 WINED3DRS_POINTSIZE_MAX ,
7411 WINED3DRS_POINTSIZE_MIN ,
7412 WINED3DRS_POINTSPRITEENABLE ,
7413 WINED3DRS_RANGEFOGENABLE ,
7414 WINED3DRS_SPECULARMATERIALSOURCE ,
7415 WINED3DRS_TWEENFACTOR ,
7416 WINED3DRS_VERTEXBLEND ,
7417 WINED3DRS_CULLMODE ,
7418 WINED3DRS_FOGCOLOR
7421 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7422 WINED3DTSS_TEXCOORDINDEX ,
7423 WINED3DTSS_TEXTURETRANSFORMFLAGS
7426 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7427 WINED3DSAMP_DMAPOFFSET
7430 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7431 DWORD rep = StateTable[state].representative;
7432 DWORD idx;
7433 BYTE shift;
7434 UINT i;
7435 WineD3DContext *context;
7437 if(!rep) return;
7438 for(i = 0; i < This->numContexts; i++) {
7439 context = This->contexts[i];
7440 if(isStateDirty(context, rep)) continue;
7442 context->dirtyArray[context->numDirtyEntries++] = rep;
7443 idx = rep >> 5;
7444 shift = rep & 0x1f;
7445 context->isStateDirty[idx] |= (1 << shift);
7449 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7450 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7451 /* The drawable size of a pbuffer render target is the current pbuffer size
7453 *width = dev->pbufferWidth;
7454 *height = dev->pbufferHeight;
7457 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7458 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7460 *width = This->pow2Width;
7461 *height = This->pow2Height;
7464 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7465 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7466 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7467 * current context's drawable, which is the size of the back buffer of the swapchain
7468 * the active context belongs to. The back buffer of the swapchain is stored as the
7469 * surface the context belongs to.
7471 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7472 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;